xref: /original-bsd/sys/netiso/tp_usrreq.c (revision 92ab646d)
1 /***********************************************************
2 				Copyright IBM Corporation 1987
3 
4                       All Rights Reserved
5 
6 Permission to use, copy, modify, and distribute this software and its
7 documentation for any purpose and without fee is hereby granted,
8 provided that the above copyright notice appear in all copies and that
9 both that copyright notice and this permission notice appear in
10 supporting documentation, and that the name of IBM not be
11 used in advertising or publicity pertaining to distribution of the
12 software without specific, written prior permission.
13 
14 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20 SOFTWARE.
21 
22 ******************************************************************/
23 
24 /*
25  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
26  */
27 /*
28  * ARGO TP
29  *
30  * $Header: tp_usrreq.c,v 5.4 88/11/18 17:29:18 nhall Exp $
31  * $Source: /usr/argo/sys/netiso/RCS/tp_usrreq.c,v $
32  *	@(#)tp_usrreq.c	7.13 (Berkeley) 06/29/90
33  *
34  * tp_usrreq(), the fellow that gets called from most of the socket code.
35  * Pretty straighforward.
36  * THe only really awful stuff here is the OOB processing, which is done
37  * wholly here.
38  * tp_rcvoob() and tp_sendoob() are contained here and called by tp_usrreq().
39  */
40 
41 #ifndef lint
42 static char *rcsid = "$Header: tp_usrreq.c,v 5.4 88/11/18 17:29:18 nhall Exp $";
43 #endif lint
44 
45 #include "param.h"
46 #include "systm.h"
47 #include "user.h"
48 #include "mbuf.h"
49 #include "socket.h"
50 #include "socketvar.h"
51 #include "domain.h"
52 #include "protosw.h"
53 #include "errno.h"
54 
55 #include "tp_param.h"
56 #include "tp_timer.h"
57 #include "tp_stat.h"
58 #include "tp_seq.h"
59 #include "tp_ip.h"
60 #include "tp_pcb.h"
61 #include "argo_debug.h"
62 #include "tp_trace.h"
63 #include "tp_meas.h"
64 #include "iso.h"
65 #include "iso_errno.h"
66 
67 int tp_attach(), tp_driver();
68 int TNew;
69 int TPNagle1, TPNagle2;
70 struct tp_pcb *tp_listeners, *tp_intercepts;
71 
72 #ifdef ARGO_DEBUG
73 /*
74  * CALLED FROM:
75  *  anywhere you want to debug...
76  * FUNCTION and ARGUMENTS:
77  *  print (str) followed by the control info in the mbufs of an mbuf chain (n)
78  */
79 void
80 dump_mbuf(n, str)
81 	struct mbuf *n;
82 	char *str;
83 {
84 	struct mbuf *nextrecord;
85 
86 	printf("dump %s\n", str);
87 
88 	if (n == MNULL)  {
89 		printf("EMPTY:\n");
90 		return;
91 	}
92 
93 	while (n) {
94 		nextrecord = n->m_act;
95 		printf("RECORD:\n");
96 		while (n) {
97 			printf("%x : Len %x Data %x A %x Nx %x Tp %x\n",
98 				n, n->m_len, n->m_data, n->m_act, n->m_next, n->m_type);
99 #ifdef notdef
100 			{
101 				register char *p = mtod(n, char *);
102 				register int i;
103 
104 				printf("data: ");
105 				for (i = 0; i < n->m_len; i++) {
106 					if (i%8 == 0)
107 						printf("\n");
108 					printf("0x%x ", *(p+i));
109 				}
110 				printf("\n");
111 			}
112 #endif notdef
113 			if (n->m_next == n) {
114 				printf("LOOP!\n");
115 				return;
116 			}
117 			n = n->m_next;
118 		}
119 		n = nextrecord;
120 	}
121 	printf("\n");
122 }
123 
124 #endif ARGO_DEBUG
125 
126 /*
127  * CALLED FROM:
128  *  tp_usrreq(), PRU_RCVOOB
129  * FUNCTION and ARGUMENTS:
130  * 	Copy data from the expedited data socket buffer into
131  * 	the pre-allocated mbuf m.
132  * 	There is an isomorphism between XPD TPDUs and expedited data TSDUs.
133  * 	XPD tpdus are limited to 16 bytes of data so they fit in one mbuf.
134  * RETURN VALUE:
135  *  EINVAL if debugging is on and a disaster has occurred
136  *  ENOTCONN if the socket isn't connected
137  *  EWOULDBLOCK if the socket is in non-blocking mode and there's no
138  *		xpd data in the buffer
139  *  E* whatever is returned from the fsm.
140  */
141 tp_rcvoob(tpcb, so, m, outflags, inflags)
142 	struct tp_pcb	*tpcb;
143 	register struct socket	*so;
144 	register struct mbuf 	*m;
145 	int 		 	*outflags;
146 	int 		 	inflags;
147 {
148 	register struct mbuf *n;
149 	register struct sockbuf *sb = &so->so_rcv;
150 	struct tp_event E;
151 	int error = 0;
152 	register struct mbuf **nn;
153 
154 	IFDEBUG(D_XPD)
155 		printf("PRU_RCVOOB, sostate 0x%x\n", so->so_state);
156 	ENDDEBUG
157 
158 	/* if you use soreceive */
159 	if (m == MNULL)
160 		return ENOBUFS;
161 
162 restart:
163 	if ((((so->so_state & SS_ISCONNECTED) == 0)
164 		 || (so->so_state & SS_ISDISCONNECTING) != 0) &&
165 		(so->so_proto->pr_flags & PR_CONNREQUIRED)) {
166 			return ENOTCONN;
167 	}
168 
169 	/* Take the first mbuf off the chain.
170 	 * Each XPD TPDU gives you a complete TSDU so the chains don't get
171 	 * coalesced, but one TSDU may span several mbufs.
172 	 * Nevertheless, since n should have a most 16 bytes, it
173 	 * will fit into m.  (size was checked in tp_input() )
174 	 */
175 
176 	/*
177 	 * Code for excision of OOB data should be added to
178 	 * uipc_socket2.c (like sbappend).
179 	 */
180 
181 	sblock(sb);
182 	for (nn = &sb->sb_mb; n = *nn; nn = &n->m_act)
183 		if (n->m_type == MT_OOBDATA)
184 			break;
185 
186 	if (n == 0) {
187 		ASSERT((tpcb->tp_flags & TPF_DISC_DATA_IN) == 0);
188 		IFDEBUG(D_XPD)
189 			printf("RCVOOB: empty queue!\n");
190 		ENDDEBUG
191 		sbunlock(sb);
192 		if (so->so_state & SS_NBIO) {
193 			return  EWOULDBLOCK;
194 		}
195 		sbwait(sb);
196 		goto restart;
197 	}
198 	m->m_len = 0;
199 
200 	/* Assuming at most one xpd tpdu is in the buffer at once */
201 	while (n != MNULL) {
202 		m->m_len += n->m_len;
203 		bcopy(mtod(n, caddr_t), mtod(m, caddr_t), (unsigned)n->m_len);
204 		m->m_data += n->m_len; /* so mtod() in bcopy() above gives right addr */
205 		n = n->m_next;
206 	}
207 	m->m_data = m->m_dat;
208 	m->m_flags |= M_EOR;
209 
210 	IFDEBUG(D_XPD)
211 		printf("tp_rcvoob: xpdlen 0x%x\n", m->m_len);
212 		dump_mbuf(so->so_rcv.sb_mb, "RCVOOB: Rcv socketbuf");
213 		dump_mbuf(sb->sb_mb, "RCVOOB: Xrcv socketbuf");
214 	ENDDEBUG
215 
216 	if ((inflags & MSG_PEEK) == 0) {
217 		n = *nn;
218 		*nn = n->m_act;
219 		sb->sb_cc -= m->m_len;
220 	}
221 
222 release:
223 	sbunlock(sb);
224 
225 	IFTRACE(D_XPD)
226 		tptraceTPCB(TPPTmisc, "PRU_RCVOOB @ release sb_cc m_len",
227 			tpcb->tp_Xrcv.sb_cc, m->m_len, 0, 0);
228 	ENDTRACE
229 	if (error == 0)
230 		error = DoEvent(T_USR_Xrcvd);
231 	return error;
232 }
233 
234 /*
235  * CALLED FROM:
236  *  tp_usrreq(), PRU_SENDOOB
237  * FUNCTION and ARGUMENTS:
238  * 	Send what's in the mbuf chain (m) as an XPD TPDU.
239  * 	The mbuf may not contain more then 16 bytes of data.
240  * 	XPD TSDUs aren't segmented, so they translate into
241  * 	exactly one XPD TPDU, with EOT bit set.
242  * RETURN VALUE:
243  *  EWOULDBLOCK if socket is in non-blocking mode and the previous
244  *   xpd data haven't been acked yet.
245  *  EMSGSIZE if trying to send > max-xpd bytes (16)
246  *  ENOBUFS if ran out of mbufs
247  */
248 tp_sendoob(tpcb, so, xdata, outflags)
249 	struct tp_pcb	*tpcb;
250 	register struct socket	*so;
251 	register struct mbuf 	*xdata;
252 	int 		 	*outflags; /* not used */
253 {
254 	/*
255 	 * Each mbuf chain represents a sequence # in the XPD seq space.
256 	 * The first one in the queue has sequence # tp_Xuna.
257 	 * When we add to the XPD queue, we stuff a zero-length
258 	 * mbuf (mark) into the DATA queue, with its sequence number in m_next
259 	 * to be assigned to this XPD tpdu, so data xfer can stop
260 	 * when it reaches the zero-length mbuf if this XPD TPDU hasn't
261 	 * yet been acknowledged.
262 	 */
263 	register struct sockbuf *sb = &(tpcb->tp_Xsnd);
264 	register struct mbuf 	*xmark;
265 	register int 			len=0;
266 	struct tp_event E;
267 
268 	IFDEBUG(D_XPD)
269 		printf("tp_sendoob:");
270 		if (xdata)
271 			printf("xdata len 0x%x\n", xdata->m_len);
272 	ENDDEBUG
273 	/* DO NOT LOCK the Xsnd buffer!!!! You can have at MOST one
274 	 * socket buf locked at any time!!! (otherwise you might
275 	 * sleep() in sblock() w/ a signal pending and cause the
276 	 * system call to be aborted w/ a locked socketbuf, which
277 	 * is a problem.  So the so_snd buffer lock
278 	 * (done in sosend()) serves as the lock for Xpd.
279 	 */
280 	if (sb->sb_mb) { /* Anything already in eXpedited data sockbuf? */
281 		if (so->so_state & SS_NBIO) {
282 			return EWOULDBLOCK;
283 		}
284 		while (sb->sb_mb) {
285 			sbunlock(&so->so_snd); /* already locked by sosend */
286 			sbwait(&so->so_snd);
287 			sblock(&so->so_snd);  /* sosend will unlock on return */
288 		}
289 	}
290 
291 	if (xdata == (struct mbuf *)0) {
292 		/* empty xpd packet */
293 		MGETHDR(xdata, M_WAIT, MT_OOBDATA);
294 		if (xdata == NULL) {
295 			return ENOBUFS;
296 		}
297 		xdata->m_len = 0;
298 		xdata->m_pkthdr.len = 0;
299 	}
300 	IFDEBUG(D_XPD)
301 		printf("tp_sendoob 1:");
302 		if (xdata)
303 			printf("xdata len 0x%x\n", xdata->m_len);
304 	ENDDEBUG
305 	xmark = xdata; /* temporary use of variable xmark */
306 	while (xmark) {
307 		len += xmark->m_len;
308 		xmark = xmark->m_next;
309 	}
310 	if (len > TP_MAX_XPD_DATA) {
311 		return EMSGSIZE;
312 	}
313 	IFDEBUG(D_XPD)
314 		printf("tp_sendoob 2:");
315 		if (xdata)
316 			printf("xdata len 0x%x\n", len);
317 	ENDDEBUG
318 
319 
320 	IFTRACE(D_XPD)
321 		tptraceTPCB(TPPTmisc, "XPD mark m_next ", xdata->m_next, 0, 0, 0);
322 	ENDTRACE
323 
324 	sbappendrecord(sb, xdata);
325 
326 	IFDEBUG(D_XPD)
327 		printf("tp_sendoob len 0x%x\n", len);
328 		dump_mbuf(so->so_snd.sb_mb, "XPD request Regular sndbuf:");
329 		dump_mbuf(tpcb->tp_Xsnd.sb_mb, "XPD request Xsndbuf:");
330 	ENDDEBUG
331 	return DoEvent(T_XPD_req);
332 }
333 
334 /*
335  * CALLED FROM:
336  *  the socket routines
337  * FUNCTION and ARGUMENTS:
338  * 	Handles all "user requests" except the [gs]ockopts() requests.
339  * 	The argument (req) is the request type (PRU*),
340  * 	(m) is an mbuf chain, generally used for send and
341  * 	receive type requests only.
342  * 	(nam) is used for addresses usually, in particular for the bind request.
343  *
344  */
345 /*ARGSUSED*/
346 ProtoHook
347 tp_usrreq(so, req, m, nam, controlp)
348 	struct socket *so;
349 	u_int req;
350 	struct mbuf *m, *nam, *controlp;
351 {
352 	register struct tp_pcb *tpcb =  sototpcb(so);
353 	int s = splnet();
354 	int error = 0;
355 	int flags, *outflags = &flags;
356 	u_long eotsdu = 0;
357 	struct tp_event E;
358 
359 	IFDEBUG(D_REQUEST)
360 		printf("usrreq(0x%x,%d,0x%x,0x%x,0x%x)\n",so,req,m,nam,outflags);
361 		if (so->so_error)
362 			printf("WARNING!!! so->so_error is 0x%x\n", so->so_error);
363 	ENDDEBUG
364 	IFTRACE(D_REQUEST)
365 		tptraceTPCB(TPPTusrreq, "req so m state [", req, so, m,
366 			tpcb?tpcb->tp_state:0);
367 	ENDTRACE
368 
369 	if ((u_int)tpcb == 0 && req != PRU_ATTACH) {
370 		IFTRACE(D_REQUEST)
371 			tptraceTPCB(TPPTusrreq, "req failed NO TPCB[", 0, 0, 0, 0);
372 		ENDTRACE
373 		splx(s);
374 		return ENOTCONN;
375 	}
376 
377 	switch (req) {
378 
379 	case PRU_ATTACH:
380 		if (tpcb) {
381 			error = EISCONN;
382 			break;
383 		}
384 		if (error = tp_attach(so, so->so_proto->pr_domain->dom_family))
385 			break;
386 		tpcb = sototpcb(so);
387 		break;
388 
389 	case PRU_ABORT: 	/* called from close() */
390 		/* called for each incoming connect queued on the
391 		 *	parent (accepting) socket
392 		 */
393 		if (tpcb->tp_state == TP_OPEN) {
394 			E.ATTR(T_DISC_req).e_reason = E_TP_NO_SESSION;
395 			error = DoEvent(T_DISC_req); /* pretend it was a close() */
396 			break;
397 		} /* else DROP THROUGH */
398 
399 	case PRU_DETACH: 	/* called from close() */
400 		/* called only after disconnect was called */
401 		if (tpcb->tp_state == TP_LISTENING) {
402 			register struct tp_pcb **tt;
403 			for (tt = &tp_listeners; *tt; tt = &((*tt)->tp_nextlisten))
404 				if (*tt == tpcb)
405 					break;
406 			if (*tt)
407 				*tt = tpcb->tp_nextlisten;
408 			else {
409 				for (tt = &tp_intercepts; *tt; tt = &((*tt)->tp_nextlisten))
410 					if (*tt == tpcb)
411 						break;
412 				if (*tt)
413 					*tt = tpcb->tp_nextlisten;
414 				else
415 					printf("tp_usrreq - detach: should panic\n");
416 			}
417 		}
418 		if (tpcb->tp_next)
419 			remque(tpcb);
420 		error = DoEvent(T_DETACH);
421 		if (tpcb->tp_state == TP_CLOSED) {
422 			free((caddr_t)tpcb, M_PCB);
423 			tpcb = 0;
424 		}
425 		break;
426 
427 	case PRU_SHUTDOWN:
428 		/* recv end may have been released; local credit might be zero  */
429 	case PRU_DISCONNECT:
430 		E.ATTR(T_DISC_req).e_reason = E_TP_NORMAL_DISC;
431 		error = DoEvent(T_DISC_req);
432 		break;
433 
434 	case PRU_BIND:
435 		error =  (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, nam);
436 		if (error == 0) {
437 			(tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
438 				tpcb->tp_lsuffix, TP_LOCAL);
439 		}
440 		break;
441 
442 	case PRU_LISTEN:
443 		if (tpcb->tp_lsuffixlen == 0) {
444 			if (error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL))
445 				break;
446 			(tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
447 				tpcb->tp_lsuffix, TP_LOCAL);
448 		}
449 		if (tpcb->tp_next == 0) {
450 			tpcb->tp_next = tpcb->tp_prev = tpcb;
451 			tpcb->tp_nextlisten = tp_listeners;
452 			tp_listeners = tpcb;
453 		}
454 		IFDEBUG(D_TPISO)
455 			if (tpcb->tp_state != TP_CLOSED)
456 				printf("LISTEN ERROR: state 0x%x\n", tpcb->tp_state);
457 		ENDDEBUG
458 		error = DoEvent(T_LISTEN_req);
459 		break;
460 
461 	case PRU_CONNECT2:
462 		error = EOPNOTSUPP; /* for unix domain sockets */
463 		break;
464 
465 	case PRU_CONNECT:
466 		IFTRACE(D_CONN)
467 			tptraceTPCB(TPPTmisc,
468 			"PRU_CONNECT: so 0x%x *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x",
469 			tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen,
470 				tpcb->tp_class);
471 		ENDTRACE
472 		IFDEBUG(D_CONN)
473 			printf("PRU_CONNECT: so *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x",
474 			tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen,
475 				tpcb->tp_class);
476 		ENDDEBUG
477 		if (tpcb->tp_lsuffixlen == 0) {
478 			if (error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL)) {
479 				IFDEBUG(D_CONN)
480 					printf("pcbbind returns error 0x%x\n", error);
481 				ENDDEBUG
482 				break;
483 			}
484 			(tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
485 				tpcb->tp_lsuffix, TP_LOCAL);
486 		}
487 
488 		IFDEBUG(D_CONN)
489 			printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb);
490 			dump_buf(tpcb->tp_npcb, 16);
491 		ENDDEBUG
492 		if (error = tp_route_to(nam, tpcb, /* channel */0))
493 			break;
494 		IFDEBUG(D_CONN)
495 			printf(
496 				"PRU_CONNECT after tpcb 0x%x so 0x%x npcb 0x%x flags 0x%x\n",
497 				tpcb, so, tpcb->tp_npcb, tpcb->tp_flags);
498 			printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb);
499 			dump_buf(tpcb->tp_npcb, 16);
500 		ENDDEBUG
501 		if (tpcb->tp_fsuffixlen ==  0) {
502 			/* didn't set peer extended suffix */
503 			(tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_fsuffixlen,
504 				tpcb->tp_fsuffix, TP_FOREIGN);
505 		}
506 		(void) (tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb,
507 					&tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0);
508 		if (tpcb->tp_state == TP_CLOSED) {
509 			soisconnecting(so);
510 			error = DoEvent(T_CONN_req);
511 		} else {
512 			(tpcb->tp_nlproto->nlp_pcbdisc)(so->so_pcb);
513 			error = EISCONN;
514 		}
515 		IFPERF(tpcb)
516 			u_int lsufx, fsufx;
517 			lsufx = *(u_short *)(tpcb->tp_lsuffix);
518 			fsufx = *(u_short *)(tpcb->tp_fsuffix);
519 
520 			tpmeas(tpcb->tp_lref,
521 				TPtime_open | (tpcb->tp_xtd_format << 4),
522 				&time, lsufx, fsufx, tpcb->tp_fref);
523 		ENDPERF
524 		break;
525 
526 	case PRU_ACCEPT:
527 		(tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN);
528 		IFDEBUG(D_REQUEST)
529 			printf("ACCEPT PEERADDDR:");
530 			dump_buf(mtod(nam, char *), nam->m_len);
531 		ENDDEBUG
532 		IFPERF(tpcb)
533 			u_int lsufx, fsufx;
534 			lsufx = *(u_short *)(tpcb->tp_lsuffix);
535 			fsufx = *(u_short *)(tpcb->tp_fsuffix);
536 
537 			tpmeas(tpcb->tp_lref, TPtime_open,
538 				&time, lsufx, fsufx, tpcb->tp_fref);
539 		ENDPERF
540 		break;
541 
542 	case PRU_RCVD:
543 		if (so->so_state & SS_ISCONFIRMING) {
544 			if (tpcb->tp_state == TP_CONFIRMING)
545 				error = tp_confirm(tpcb);
546 			break;
547 		}
548 		IFTRACE(D_DATA)
549 			tptraceTPCB(TPPTmisc,
550 			"RCVD BF: lcredit sent_lcdt cc hiwat \n",
551 				tpcb->tp_lcredit, tpcb->tp_sent_lcdt,
552 				so->so_rcv.sb_cc, so->so_rcv.sb_hiwat);
553 			LOCAL_CREDIT(tpcb);
554 			tptraceTPCB(TPPTmisc,
555 				"PRU_RCVD AF sbspace lcredit hiwat cc",
556 				sbspace(&so->so_rcv), tpcb->tp_lcredit,
557 				so->so_rcv.sb_cc, so->so_rcv.sb_hiwat);
558 		ENDTRACE
559 		IFDEBUG(D_REQUEST)
560 			printf("RCVD: cc %d space %d hiwat %d\n",
561 				so->so_rcv.sb_cc, sbspace(&so->so_rcv),
562 				so->so_rcv.sb_hiwat);
563 		ENDDEBUG
564 		if (((int)nam) & MSG_OOB)
565 			error = DoEvent(T_USR_Xrcvd);
566 		else
567 			error = DoEvent(T_USR_rcvd);
568 		break;
569 
570 	case PRU_RCVOOB:
571 		if ((so->so_state & SS_ISCONNECTED) == 0) {
572 			error = ENOTCONN;
573 			break;
574 		}
575 		if (! tpcb->tp_xpd_service) {
576 			error = EOPNOTSUPP;
577 			break;
578 		}
579 		/* kludge - nam is really flags here */
580 		error = tp_rcvoob(tpcb, so, m, outflags, (int)nam);
581 		break;
582 
583 	case PRU_SEND:
584 	case PRU_SENDOOB:
585 		if (controlp) {
586 			error = tp_snd_control(controlp, so, &m);
587 			controlp = NULL;
588 			if (error)
589 				break;
590 		}
591 		if (so->so_state & SS_ISCONFIRMING) {
592 			if (tpcb->tp_state == TP_CONFIRMING)
593 				error = tp_confirm(tpcb);
594 			if (m) {
595 				if (error == 0 && m->m_len != 0)
596 					error =  ENOTCONN;
597 				m_freem(m);
598 				m = 0;
599 			}
600 			break;
601 		}
602 		if (m == 0)
603 			break;
604 
605 		if (req == PRU_SENDOOB) {
606 			if (tpcb->tp_xpd_service == 0) {
607 				error = EOPNOTSUPP;
608 				break;
609 			}
610 			error = tp_sendoob(tpcb, so, m, outflags);
611 			break;
612 		}
613 		/*
614 		 * The protocol machine copies mbuf chains,
615 		 * prepends headers, assigns seq numbers, and
616 		 * puts the packets on the device.
617 		 * When they are acked they are removed from the socket buf.
618 		 *
619 		 * sosend calls this up until sbspace goes negative.
620 		 * Sbspace may be made negative by appending this mbuf chain,
621 		 * possibly by a whole cluster.
622 		 */
623 		{
624 			register struct mbuf *n = m;
625 			register struct sockbuf *sb = &so->so_snd;
626 			int	maxsize = tpcb->tp_l_tpdusize
627 				    - tp_headersize(DT_TPDU_type, tpcb)
628 				    - (tpcb->tp_use_checksum?4:0) ;
629 			int totlen = n->m_pkthdr.len;
630 			int	mbufcnt = 0;
631 			struct mbuf *nn;
632 
633 			/*
634 			 * Could have eotsdu and no data.(presently MUST have
635 			 * an mbuf though, even if its length == 0)
636 			 */
637 			if (n->m_flags & M_EOR) {
638 				eotsdu = 1;
639 				n->m_flags &= ~M_EOR;
640 			}
641 			IFPERF(tpcb)
642 			   PStat(tpcb, Nb_from_sess) += totlen;
643 			   tpmeas(tpcb->tp_lref, TPtime_from_session, 0, 0,
644 					PStat(tpcb, Nb_from_sess), totlen);
645 			ENDPERF
646 			IFDEBUG(D_SYSCALL)
647 				printf(
648 				"PRU_SEND: eot %d before sbappend 0x%x len 0x%x to sb @ 0x%x\n",
649 					eotsdu, m, totlen, sb);
650 				dump_mbuf(sb->sb_mb, "so_snd.sb_mb");
651 				dump_mbuf(m, "m : to be added");
652 			ENDDEBUG
653 			/*
654 			 * Pre-packetize the data in the sockbuf
655 			 * according to negotiated mtu.  Do it here
656 			 * where we can safely wait for mbufs.
657 			 *
658 			 * This presumes knowledge of sockbuf conventions.
659 			 */
660 			if (n = sb->sb_mb)
661 				while (n->m_act)
662 					n = n->m_act;
663 			if ((nn = n) && n->m_pkthdr.len < maxsize) {
664 				u_int space = maxsize - n->m_pkthdr.len;
665 
666 				do {
667 					if (n->m_flags & M_EOR)
668 						goto on1;
669 				} while (n->m_next && (n = n->m_next));
670 				if (totlen <= space) {
671 					TPNagle1++;
672 					n->m_next = m;
673 					nn->m_pkthdr.len += totlen;
674 					while (n = n->m_next)
675 						sballoc(sb, n);
676 					if (eotsdu)
677 						nn->m_flags |= M_EOR;
678 					goto on2;
679 				} else {
680 					/*
681 					 * Can't sleep here, because when you wake up
682 					 * packet you want to attach to may be gone!
683 					 */
684 					if (TNew && (n->m_next = m_copym(m, 0, space, M_NOWAIT))) {
685 						nn->m_pkthdr.len += space;
686 						TPNagle2++;
687 						while (n = n->m_next)
688 							sballoc(sb, n);
689 						m_adj(m, space);
690 					}
691 				}
692 			}
693 	on1:	mbufcnt++;
694 			for (n = m; n->m_pkthdr.len > maxsize;) {
695 				nn = m_copym(n, 0, maxsize, M_WAIT);
696 				sbappendrecord(sb, nn);
697 				m_adj(n, maxsize);
698 				mbufcnt++;
699 			}
700 			if (eotsdu)
701 				n->m_flags |= M_EOR;
702 			sbappendrecord(sb, n);
703 	on2:
704 			IFTRACE(D_DATA)
705 				tptraceTPCB(TPPTmisc,
706 				"SEND BF: maxsize totlen mbufcnt eotsdu",
707 					maxsize, totlen, mbufcnt, eotsdu);
708 			ENDTRACE
709 			IFDEBUG(D_SYSCALL)
710 				printf("PRU_SEND: eot %d after sbappend 0x%x mbufcnt 0x%x\n",
711 					eotsdu, n, mbufcnt);
712 				dump_mbuf(sb->sb_mb, "so_snd.sb_mb");
713 			ENDDEBUG
714 			error = DoEvent(T_DATA_req);
715 			IFDEBUG(D_SYSCALL)
716 				printf("PRU_SEND: after driver error 0x%x \n",error);
717 				printf("so_snd 0x%x cc 0t%d mbcnt 0t%d\n",
718 						sb, sb->sb_cc, sb->sb_mbcnt);
719 				dump_mbuf(sb->sb_mb, "so_snd.sb_mb after driver");
720 			ENDDEBUG
721 		}
722 		break;
723 
724 	case PRU_SOCKADDR:
725 		(tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_LOCAL);
726 		break;
727 
728 	case PRU_PEERADDR:
729 		(tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN);
730 		break;
731 
732 	case PRU_CONTROL:
733 		error = EOPNOTSUPP;
734 		break;
735 
736 	case PRU_PROTOSEND:
737 	case PRU_PROTORCV:
738 	case PRU_SENSE:
739 	case PRU_SLOWTIMO:
740 	case PRU_FASTTIMO:
741 		error = EOPNOTSUPP;
742 		break;
743 
744 	default:
745 #ifdef ARGO_DEBUG
746 		printf("tp_usrreq UNKNOWN PRU %d\n", req);
747 #endif ARGO_DEBUG
748 		error = EOPNOTSUPP;
749 	}
750 
751 	IFDEBUG(D_REQUEST)
752 		printf("%s, so 0x%x, tpcb 0x%x, error %d, state %d\n",
753 			"returning from tp_usrreq", so, tpcb, error,
754 			tpcb ? 0 : tpcb->tp_state);
755 	ENDDEBUG
756 	IFTRACE(D_REQUEST)
757 		tptraceTPCB(TPPTusrreq, "END req so m state [", req, so, m,
758 			tpcb?0:tpcb->tp_state);
759 	ENDTRACE
760 	if (controlp) {
761 		m_freem(controlp);
762 		printf("control data unexpectedly retained in tp_usrreq()");
763 	}
764 	splx(s);
765 	return error;
766 }
767 tp_ltrace(so, uio)
768 struct socket *so;
769 struct uio *uio;
770 {
771 	IFTRACE(D_DATA)
772 		register struct tp_pcb *tpcb =  sototpcb(so);
773 		if (tpcb) {
774 			tptraceTPCB(TPPTmisc, "sosend so resid iovcnt", so,
775 				uio->uio_resid, uio->uio_iovcnt, 0);
776 		}
777 	ENDTRACE
778 }
779 
780 tp_confirm(tpcb)
781 register struct tp_pcb *tpcb;
782 {
783 	struct tp_event E;
784 	if (tpcb->tp_state == TP_CONFIRMING)
785 	    return DoEvent(T_ACPT_req);
786 	printf("Tp confirm called when not confirming; tpcb 0x%x, state 0x%x\n",
787 		tpcb, tpcb->tp_state);
788 	return 0;
789 }
790 
791 /*
792  * Process control data sent with sendmsg()
793  */
794 tp_snd_control(m, so, data)
795 	struct mbuf *m;
796 	struct socket *so;
797 	register struct mbuf **data;
798 {
799 	register struct cmsghdr *ch;
800 	int error = 0;
801 
802 	if (m && m->m_len) {
803 		ch = mtod(m, struct cmsghdr *);
804 		m->m_len -= sizeof (*ch);
805 		m->m_data += sizeof (*ch);
806 		error = tp_ctloutput(PRCO_SETOPT,
807 							 so, ch->cmsg_level, ch->cmsg_type, &m);
808 		if (ch->cmsg_type == TPOPT_DISC_DATA) {
809 			if (data && *data) {
810 				m_freem(*data);
811 				*data = 0;
812 			}
813 			error = tp_usrreq(so, PRU_DISCONNECT, (struct mbuf *)0,
814 								(caddr_t)0, (struct mbuf *)0);
815 		}
816 	}
817 	if (m)
818 		m_freem(m);
819 	return error;
820 }
821