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