xref: /original-bsd/sys/netiso/tp_usrreq.c (revision 0e8defd9)
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.14 (Berkeley) 03/12/91
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 		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 		if (tpcb->tp_state == TP_LISTENING) {
401 			register struct tp_pcb **tt;
402 			for (tt = &tp_listeners; *tt; tt = &((*tt)->tp_nextlisten))
403 				if (*tt == tpcb)
404 					break;
405 			if (*tt)
406 				*tt = tpcb->tp_nextlisten;
407 			else {
408 				for (tt = &tp_intercepts; *tt; tt = &((*tt)->tp_nextlisten))
409 					if (*tt == tpcb)
410 						break;
411 				if (*tt)
412 					*tt = tpcb->tp_nextlisten;
413 				else
414 					printf("tp_usrreq - detach: should panic\n");
415 			}
416 		}
417 		if (tpcb->tp_next)
418 			remque(tpcb);
419 		error = DoEvent(T_DETACH);
420 		if (tpcb->tp_state == TP_CLOSED) {
421 			free((caddr_t)tpcb, M_PCB);
422 			tpcb = 0;
423 		}
424 		break;
425 
426 	case PRU_SHUTDOWN:
427 		/* recv end may have been released; local credit might be zero  */
428 	case PRU_DISCONNECT:
429 		E.ATTR(T_DISC_req).e_reason = E_TP_NORMAL_DISC;
430 		error = DoEvent(T_DISC_req);
431 		break;
432 
433 	case PRU_BIND:
434 		error =  (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, nam);
435 		if (error == 0) {
436 			(tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
437 				tpcb->tp_lsuffix, TP_LOCAL);
438 		}
439 		break;
440 
441 	case PRU_LISTEN:
442 		if (tpcb->tp_lsuffixlen == 0) {
443 			if (error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL))
444 				break;
445 			(tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
446 				tpcb->tp_lsuffix, TP_LOCAL);
447 		}
448 		if (tpcb->tp_next == 0) {
449 			tpcb->tp_next = tpcb->tp_prev = tpcb;
450 			tpcb->tp_nextlisten = tp_listeners;
451 			tp_listeners = tpcb;
452 		}
453 		IFDEBUG(D_TPISO)
454 			if (tpcb->tp_state != TP_CLOSED)
455 				printf("LISTEN ERROR: state 0x%x\n", tpcb->tp_state);
456 		ENDDEBUG
457 		error = DoEvent(T_LISTEN_req);
458 		break;
459 
460 	case PRU_CONNECT2:
461 		error = EOPNOTSUPP; /* for unix domain sockets */
462 		break;
463 
464 	case PRU_CONNECT:
465 		IFTRACE(D_CONN)
466 			tptraceTPCB(TPPTmisc,
467 			"PRU_CONNECT: so 0x%x *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x",
468 			tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen,
469 				tpcb->tp_class);
470 		ENDTRACE
471 		IFDEBUG(D_CONN)
472 			printf("PRU_CONNECT: so *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x",
473 			tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen,
474 				tpcb->tp_class);
475 		ENDDEBUG
476 		if (tpcb->tp_lsuffixlen == 0) {
477 			if (error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL)) {
478 				IFDEBUG(D_CONN)
479 					printf("pcbbind returns error 0x%x\n", error);
480 				ENDDEBUG
481 				break;
482 			}
483 			(tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
484 				tpcb->tp_lsuffix, TP_LOCAL);
485 		}
486 
487 		IFDEBUG(D_CONN)
488 			printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb);
489 			dump_buf(tpcb->tp_npcb, 16);
490 		ENDDEBUG
491 		if (error = tp_route_to(nam, tpcb, /* channel */0))
492 			break;
493 		IFDEBUG(D_CONN)
494 			printf(
495 				"PRU_CONNECT after tpcb 0x%x so 0x%x npcb 0x%x flags 0x%x\n",
496 				tpcb, so, tpcb->tp_npcb, tpcb->tp_flags);
497 			printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb);
498 			dump_buf(tpcb->tp_npcb, 16);
499 		ENDDEBUG
500 		if (tpcb->tp_fsuffixlen ==  0) {
501 			/* didn't set peer extended suffix */
502 			(tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_fsuffixlen,
503 				tpcb->tp_fsuffix, TP_FOREIGN);
504 		}
505 		(void) (tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb,
506 					&tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0);
507 		if (tpcb->tp_state == TP_CLOSED) {
508 			soisconnecting(so);
509 			error = DoEvent(T_CONN_req);
510 		} else {
511 			(tpcb->tp_nlproto->nlp_pcbdisc)(so->so_pcb);
512 			error = EISCONN;
513 		}
514 		IFPERF(tpcb)
515 			u_int lsufx, fsufx;
516 			lsufx = *(u_short *)(tpcb->tp_lsuffix);
517 			fsufx = *(u_short *)(tpcb->tp_fsuffix);
518 
519 			tpmeas(tpcb->tp_lref,
520 				TPtime_open | (tpcb->tp_xtd_format << 4),
521 				&time, lsufx, fsufx, tpcb->tp_fref);
522 		ENDPERF
523 		break;
524 
525 	case PRU_ACCEPT:
526 		(tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN);
527 		IFDEBUG(D_REQUEST)
528 			printf("ACCEPT PEERADDDR:");
529 			dump_buf(mtod(nam, char *), nam->m_len);
530 		ENDDEBUG
531 		IFPERF(tpcb)
532 			u_int lsufx, fsufx;
533 			lsufx = *(u_short *)(tpcb->tp_lsuffix);
534 			fsufx = *(u_short *)(tpcb->tp_fsuffix);
535 
536 			tpmeas(tpcb->tp_lref, TPtime_open,
537 				&time, lsufx, fsufx, tpcb->tp_fref);
538 		ENDPERF
539 		break;
540 
541 	case PRU_RCVD:
542 		if (so->so_state & SS_ISCONFIRMING) {
543 			if (tpcb->tp_state == TP_CONFIRMING)
544 				error = tp_confirm(tpcb);
545 			break;
546 		}
547 		IFTRACE(D_DATA)
548 			tptraceTPCB(TPPTmisc,
549 			"RCVD BF: lcredit sent_lcdt cc hiwat \n",
550 				tpcb->tp_lcredit, tpcb->tp_sent_lcdt,
551 				so->so_rcv.sb_cc, so->so_rcv.sb_hiwat);
552 			LOCAL_CREDIT(tpcb);
553 			tptraceTPCB(TPPTmisc,
554 				"PRU_RCVD AF sbspace lcredit hiwat cc",
555 				sbspace(&so->so_rcv), tpcb->tp_lcredit,
556 				so->so_rcv.sb_cc, so->so_rcv.sb_hiwat);
557 		ENDTRACE
558 		IFDEBUG(D_REQUEST)
559 			printf("RCVD: cc %d space %d hiwat %d\n",
560 				so->so_rcv.sb_cc, sbspace(&so->so_rcv),
561 				so->so_rcv.sb_hiwat);
562 		ENDDEBUG
563 		if (((int)nam) & MSG_OOB)
564 			error = DoEvent(T_USR_Xrcvd);
565 		else
566 			error = DoEvent(T_USR_rcvd);
567 		break;
568 
569 	case PRU_RCVOOB:
570 		if ((so->so_state & SS_ISCONNECTED) == 0) {
571 			error = ENOTCONN;
572 			break;
573 		}
574 		if (! tpcb->tp_xpd_service) {
575 			error = EOPNOTSUPP;
576 			break;
577 		}
578 		/* kludge - nam is really flags here */
579 		error = tp_rcvoob(tpcb, so, m, outflags, (int)nam);
580 		break;
581 
582 	case PRU_SEND:
583 	case PRU_SENDOOB:
584 		if (controlp) {
585 			error = tp_snd_control(controlp, so, &m);
586 			controlp = NULL;
587 			if (error)
588 				break;
589 		}
590 		if (so->so_state & SS_ISCONFIRMING) {
591 			if (tpcb->tp_state == TP_CONFIRMING)
592 				error = tp_confirm(tpcb);
593 			if (m) {
594 				if (error == 0 && m->m_len != 0)
595 					error =  ENOTCONN;
596 				m_freem(m);
597 				m = 0;
598 			}
599 			break;
600 		}
601 		if (m == 0)
602 			break;
603 
604 		if (req == PRU_SENDOOB) {
605 			if (tpcb->tp_xpd_service == 0) {
606 				error = EOPNOTSUPP;
607 				break;
608 			}
609 			error = tp_sendoob(tpcb, so, m, outflags);
610 			break;
611 		}
612 		/*
613 		 * The protocol machine copies mbuf chains,
614 		 * prepends headers, assigns seq numbers, and
615 		 * puts the packets on the device.
616 		 * When they are acked they are removed from the socket buf.
617 		 *
618 		 * sosend calls this up until sbspace goes negative.
619 		 * Sbspace may be made negative by appending this mbuf chain,
620 		 * possibly by a whole cluster.
621 		 */
622 		{
623 			register struct mbuf *n = m;
624 			register struct sockbuf *sb = &so->so_snd;
625 			int	maxsize = tpcb->tp_l_tpdusize
626 				    - tp_headersize(DT_TPDU_type, tpcb)
627 				    - (tpcb->tp_use_checksum?4:0) ;
628 			int totlen = n->m_pkthdr.len;
629 			int	mbufcnt = 0;
630 			struct mbuf *nn;
631 
632 			/*
633 			 * Could have eotsdu and no data.(presently MUST have
634 			 * an mbuf though, even if its length == 0)
635 			 */
636 			if (n->m_flags & M_EOR) {
637 				eotsdu = 1;
638 				n->m_flags &= ~M_EOR;
639 			}
640 			IFPERF(tpcb)
641 			   PStat(tpcb, Nb_from_sess) += totlen;
642 			   tpmeas(tpcb->tp_lref, TPtime_from_session, 0, 0,
643 					PStat(tpcb, Nb_from_sess), totlen);
644 			ENDPERF
645 			IFDEBUG(D_SYSCALL)
646 				printf(
647 				"PRU_SEND: eot %d before sbappend 0x%x len 0x%x to sb @ 0x%x\n",
648 					eotsdu, m, totlen, sb);
649 				dump_mbuf(sb->sb_mb, "so_snd.sb_mb");
650 				dump_mbuf(m, "m : to be added");
651 			ENDDEBUG
652 			/*
653 			 * Pre-packetize the data in the sockbuf
654 			 * according to negotiated mtu.  Do it here
655 			 * where we can safely wait for mbufs.
656 			 *
657 			 * This presumes knowledge of sockbuf conventions.
658 			 */
659 			if (n = sb->sb_mb)
660 				while (n->m_act)
661 					n = n->m_act;
662 			if ((nn = n) && n->m_pkthdr.len < maxsize) {
663 				u_int space = maxsize - n->m_pkthdr.len;
664 
665 				do {
666 					if (n->m_flags & M_EOR)
667 						goto on1;
668 				} while (n->m_next && (n = n->m_next));
669 				if (totlen <= space) {
670 					TPNagle1++;
671 					n->m_next = m;
672 					nn->m_pkthdr.len += totlen;
673 					while (n = n->m_next)
674 						sballoc(sb, n);
675 					if (eotsdu)
676 						nn->m_flags |= M_EOR;
677 					goto on2;
678 				} else {
679 					/*
680 					 * Can't sleep here, because when you wake up
681 					 * packet you want to attach to may be gone!
682 					 */
683 					if (TNew && (n->m_next = m_copym(m, 0, space, M_NOWAIT))) {
684 						nn->m_pkthdr.len += space;
685 						TPNagle2++;
686 						while (n = n->m_next)
687 							sballoc(sb, n);
688 						m_adj(m, space);
689 					}
690 				}
691 			}
692 	on1:	mbufcnt++;
693 			for (n = m; n->m_pkthdr.len > maxsize;) {
694 				nn = m_copym(n, 0, maxsize, M_WAIT);
695 				sbappendrecord(sb, nn);
696 				m_adj(n, maxsize);
697 				mbufcnt++;
698 			}
699 			if (eotsdu)
700 				n->m_flags |= M_EOR;
701 			sbappendrecord(sb, n);
702 	on2:
703 			IFTRACE(D_DATA)
704 				tptraceTPCB(TPPTmisc,
705 				"SEND BF: maxsize totlen mbufcnt eotsdu",
706 					maxsize, totlen, mbufcnt, eotsdu);
707 			ENDTRACE
708 			IFDEBUG(D_SYSCALL)
709 				printf("PRU_SEND: eot %d after sbappend 0x%x mbufcnt 0x%x\n",
710 					eotsdu, n, mbufcnt);
711 				dump_mbuf(sb->sb_mb, "so_snd.sb_mb");
712 			ENDDEBUG
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