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