xref: /original-bsd/sys/netiso/tp_usrreq.c (revision c73f6197)
1 /*-
2  * Copyright (c) 1991, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)tp_usrreq.c	8.1 (Berkeley) 06/10/93
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 <sys/param.h>
50 #include <sys/systm.h>
51 #include <sys/mbuf.h>
52 #include <sys/socket.h>
53 #include <sys/socketvar.h>
54 #include <sys/domain.h>
55 #include <sys/protosw.h>
56 #include <sys/errno.h>
57 #include <sys/time.h>
58 
59 #include <netiso/tp_param.h>
60 #include <netiso/tp_timer.h>
61 #include <netiso/tp_stat.h>
62 #include <netiso/tp_seq.h>
63 #include <netiso/tp_ip.h>
64 #include <netiso/tp_pcb.h>
65 #include <netiso/argo_debug.h>
66 #include <netiso/tp_trace.h>
67 #include <netiso/tp_meas.h>
68 #include <netiso/iso.h>
69 #include <netiso/iso_errno.h>
70 
71 int tp_attach(), tp_driver(), tp_pcbbind();
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, M_WAITOK);
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 		for (; n; n = m_free(n))
223 			sbfree(sb, n);
224 	}
225 
226 release:
227 	sbunlock(sb);
228 
229 	IFTRACE(D_XPD)
230 		tptraceTPCB(TPPTmisc, "PRU_RCVOOB @ release sb_cc m_len",
231 			tpcb->tp_Xrcv.sb_cc, m->m_len, 0, 0);
232 	ENDTRACE
233 	if (error == 0)
234 		error = DoEvent(T_USR_Xrcvd);
235 	return error;
236 }
237 
238 /*
239  * CALLED FROM:
240  *  tp_usrreq(), PRU_SENDOOB
241  * FUNCTION and ARGUMENTS:
242  * 	Send what's in the mbuf chain (m) as an XPD TPDU.
243  * 	The mbuf may not contain more then 16 bytes of data.
244  * 	XPD TSDUs aren't segmented, so they translate into
245  * 	exactly one XPD TPDU, with EOT bit set.
246  * RETURN VALUE:
247  *  EWOULDBLOCK if socket is in non-blocking mode and the previous
248  *   xpd data haven't been acked yet.
249  *  EMSGSIZE if trying to send > max-xpd bytes (16)
250  *  ENOBUFS if ran out of mbufs
251  */
252 tp_sendoob(tpcb, so, xdata, outflags)
253 	struct tp_pcb	*tpcb;
254 	register struct socket	*so;
255 	register struct mbuf 	*xdata;
256 	int 		 	*outflags; /* not used */
257 {
258 	/*
259 	 * Each mbuf chain represents a sequence # in the XPD seq space.
260 	 * The first one in the queue has sequence # tp_Xuna.
261 	 * When we add to the XPD queue, we stuff a zero-length
262 	 * mbuf (mark) into the DATA queue, with its sequence number in m_next
263 	 * to be assigned to this XPD tpdu, so data xfer can stop
264 	 * when it reaches the zero-length mbuf if this XPD TPDU hasn't
265 	 * yet been acknowledged.
266 	 */
267 	register struct sockbuf *sb = &(tpcb->tp_Xsnd);
268 	register struct mbuf 	*xmark;
269 	register int 			len=0;
270 	struct tp_event E;
271 
272 	IFDEBUG(D_XPD)
273 		printf("tp_sendoob:");
274 		if (xdata)
275 			printf("xdata len 0x%x\n", xdata->m_len);
276 	ENDDEBUG
277 	/* DO NOT LOCK the Xsnd buffer!!!! You can have at MOST one
278 	 * socket buf locked at any time!!! (otherwise you might
279 	 * sleep() in sblock() w/ a signal pending and cause the
280 	 * system call to be aborted w/ a locked socketbuf, which
281 	 * is a problem.  So the so_snd buffer lock
282 	 * (done in sosend()) serves as the lock for Xpd.
283 	 */
284 	if (sb->sb_mb) { /* Anything already in eXpedited data sockbuf? */
285 		if (so->so_state & SS_NBIO) {
286 			return EWOULDBLOCK;
287 		}
288 		while (sb->sb_mb) {
289 			sbunlock(&so->so_snd); /* already locked by sosend */
290 			sbwait(&so->so_snd);
291 			sblock(&so->so_snd, M_WAITOK);  /* sosend will unlock on return */
292 		}
293 	}
294 
295 	if (xdata == (struct mbuf *)0) {
296 		/* empty xpd packet */
297 		MGETHDR(xdata, M_WAIT, MT_OOBDATA);
298 		if (xdata == NULL) {
299 			return ENOBUFS;
300 		}
301 		xdata->m_len = 0;
302 		xdata->m_pkthdr.len = 0;
303 	}
304 	IFDEBUG(D_XPD)
305 		printf("tp_sendoob 1:");
306 		if (xdata)
307 			printf("xdata len 0x%x\n", xdata->m_len);
308 	ENDDEBUG
309 	xmark = xdata; /* temporary use of variable xmark */
310 	while (xmark) {
311 		len += xmark->m_len;
312 		xmark = xmark->m_next;
313 	}
314 	if (len > TP_MAX_XPD_DATA) {
315 		return EMSGSIZE;
316 	}
317 	IFDEBUG(D_XPD)
318 		printf("tp_sendoob 2:");
319 		if (xdata)
320 			printf("xdata len 0x%x\n", len);
321 	ENDDEBUG
322 
323 
324 	IFTRACE(D_XPD)
325 		tptraceTPCB(TPPTmisc, "XPD mark m_next ", xdata->m_next, 0, 0, 0);
326 	ENDTRACE
327 
328 	sbappendrecord(sb, xdata);
329 
330 	IFDEBUG(D_XPD)
331 		printf("tp_sendoob len 0x%x\n", len);
332 		dump_mbuf(so->so_snd.sb_mb, "XPD request Regular sndbuf:");
333 		dump_mbuf(tpcb->tp_Xsnd.sb_mb, "XPD request Xsndbuf:");
334 	ENDDEBUG
335 	return DoEvent(T_XPD_req);
336 }
337 
338 /*
339  * CALLED FROM:
340  *  the socket routines
341  * FUNCTION and ARGUMENTS:
342  * 	Handles all "user requests" except the [gs]ockopts() requests.
343  * 	The argument (req) is the request type (PRU*),
344  * 	(m) is an mbuf chain, generally used for send and
345  * 	receive type requests only.
346  * 	(nam) is used for addresses usually, in particular for the bind request.
347  *
348  */
349 /*ARGSUSED*/
350 ProtoHook
351 tp_usrreq(so, req, m, nam, controlp)
352 	struct socket *so;
353 	u_int req;
354 	struct mbuf *m, *nam, *controlp;
355 {
356 	register struct tp_pcb *tpcb =  sototpcb(so);
357 	int s = splnet();
358 	int error = 0;
359 	int flags, *outflags = &flags;
360 	u_long eotsdu = 0;
361 	struct tp_event E;
362 
363 	IFDEBUG(D_REQUEST)
364 		printf("usrreq(0x%x,%d,0x%x,0x%x,0x%x)\n",so,req,m,nam,outflags);
365 		if (so->so_error)
366 			printf("WARNING!!! so->so_error is 0x%x\n", so->so_error);
367 	ENDDEBUG
368 	IFTRACE(D_REQUEST)
369 		tptraceTPCB(TPPTusrreq, "req so m state [", req, so, m,
370 			tpcb?tpcb->tp_state:0);
371 	ENDTRACE
372 
373 	if ((u_int)tpcb == 0 && req != PRU_ATTACH) {
374 		IFTRACE(D_REQUEST)
375 			tptraceTPCB(TPPTusrreq, "req failed NO TPCB[", 0, 0, 0, 0);
376 		ENDTRACE
377 		splx(s);
378 		return ENOTCONN;
379 	}
380 
381 	switch (req) {
382 
383 	case PRU_ATTACH:
384 		if (tpcb) {
385 			error = EISCONN;
386 		} else if ((error = tp_attach(so, (int)nam)) == 0)
387 			tpcb = sototpcb(so);
388 		break;
389 
390 	case PRU_ABORT: 	/* called from close() */
391 		/* called for each incoming connect queued on the
392 		 *	parent (accepting) socket
393 		 */
394 		if (tpcb->tp_state == TP_OPEN || tpcb->tp_state == TP_CONFIRMING) {
395 			E.ATTR(T_DISC_req).e_reason = E_TP_NO_SESSION;
396 			error = DoEvent(T_DISC_req); /* pretend it was a close() */
397 			break;
398 		} /* else DROP THROUGH */
399 
400 	case PRU_DETACH: 	/* called from close() */
401 		/* called only after disconnect was called */
402 		error = DoEvent(T_DETACH);
403 		if (tpcb->tp_state == TP_CLOSED) {
404 			if (tpcb->tp_notdetached) {
405 				IFDEBUG(D_CONN)
406 					printf("PRU_DETACH: not detached\n");
407 				ENDDEBUG
408 				tp_detach(tpcb);
409 			}
410 			free((caddr_t)tpcb, M_PCB);
411 			tpcb = 0;
412 		}
413 		break;
414 
415 	case PRU_SHUTDOWN:
416 		/* recv end may have been released; local credit might be zero  */
417 	case PRU_DISCONNECT:
418 		E.ATTR(T_DISC_req).e_reason = E_TP_NORMAL_DISC;
419 		error = DoEvent(T_DISC_req);
420 		break;
421 
422 	case PRU_BIND:
423 		error =  tp_pcbbind(tpcb, nam);
424 		break;
425 
426 	case PRU_LISTEN:
427 		if (tpcb->tp_state != TP_CLOSED || tpcb->tp_lsuffixlen == 0 ||
428 				tpcb->tp_next == 0)
429 			error = EINVAL;
430 		else {
431 			register struct tp_pcb **tt;
432 			remque(tpcb);
433 			tpcb->tp_next = tpcb->tp_prev = tpcb;
434 			for (tt = &tp_listeners; *tt; tt = &((*tt)->tp_nextlisten))
435 				if ((*tt)->tp_lsuffixlen)
436 					break;
437 			tpcb->tp_nextlisten = *tt;
438 			*tt = tpcb;
439 			error = DoEvent(T_LISTEN_req);
440 		}
441 		break;
442 
443 	case PRU_CONNECT2:
444 		error = EOPNOTSUPP; /* for unix domain sockets */
445 		break;
446 
447 	case PRU_CONNECT:
448 		IFTRACE(D_CONN)
449 			tptraceTPCB(TPPTmisc,
450 			"PRU_CONNECT: so 0x%x *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x",
451 			tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen,
452 				tpcb->tp_class);
453 		ENDTRACE
454 		IFDEBUG(D_CONN)
455 			printf("PRU_CONNECT: so *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x",
456 			tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen,
457 				tpcb->tp_class);
458 		ENDDEBUG
459 		if (tpcb->tp_lsuffixlen == 0) {
460 			if (error = tp_pcbbind(tpcb, MNULL)) {
461 				IFDEBUG(D_CONN)
462 					printf("pcbbind returns error 0x%x\n", error);
463 				ENDDEBUG
464 				break;
465 			}
466 		}
467 		IFDEBUG(D_CONN)
468 			printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb);
469 			dump_buf(tpcb->tp_npcb, 16);
470 		ENDDEBUG
471 		if (error = tp_route_to(nam, tpcb, /* channel */0))
472 			break;
473 		IFDEBUG(D_CONN)
474 			printf(
475 				"PRU_CONNECT after tpcb 0x%x so 0x%x npcb 0x%x flags 0x%x\n",
476 				tpcb, so, tpcb->tp_npcb, tpcb->tp_flags);
477 			printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb);
478 			dump_buf(tpcb->tp_npcb, 16);
479 		ENDDEBUG
480 		if (tpcb->tp_fsuffixlen ==  0) {
481 			/* didn't set peer extended suffix */
482 			(tpcb->tp_nlproto->nlp_getsufx)(tpcb->tp_npcb, &tpcb->tp_fsuffixlen,
483 				tpcb->tp_fsuffix, TP_FOREIGN);
484 		}
485 		if (tpcb->tp_state == TP_CLOSED) {
486 			soisconnecting(so);
487 			error = DoEvent(T_CONN_req);
488 		} else {
489 			(tpcb->tp_nlproto->nlp_pcbdisc)(tpcb->tp_npcb);
490 			error = EISCONN;
491 		}
492 		IFPERF(tpcb)
493 			u_int lsufx, fsufx;
494 			lsufx = *(u_short *)(tpcb->tp_lsuffix);
495 			fsufx = *(u_short *)(tpcb->tp_fsuffix);
496 
497 			tpmeas(tpcb->tp_lref,
498 				TPtime_open | (tpcb->tp_xtd_format << 4),
499 				&time, lsufx, fsufx, tpcb->tp_fref);
500 		ENDPERF
501 		break;
502 
503 	case PRU_ACCEPT:
504 		(tpcb->tp_nlproto->nlp_getnetaddr)(tpcb->tp_npcb, nam, TP_FOREIGN);
505 		IFDEBUG(D_REQUEST)
506 			printf("ACCEPT PEERADDDR:");
507 			dump_buf(mtod(nam, char *), nam->m_len);
508 		ENDDEBUG
509 		IFPERF(tpcb)
510 			u_int lsufx, fsufx;
511 			lsufx = *(u_short *)(tpcb->tp_lsuffix);
512 			fsufx = *(u_short *)(tpcb->tp_fsuffix);
513 
514 			tpmeas(tpcb->tp_lref, TPtime_open,
515 				&time, lsufx, fsufx, tpcb->tp_fref);
516 		ENDPERF
517 		break;
518 
519 	case PRU_RCVD:
520 		if (so->so_state & SS_ISCONFIRMING) {
521 			if (tpcb->tp_state == TP_CONFIRMING)
522 				error = tp_confirm(tpcb);
523 			break;
524 		}
525 		IFTRACE(D_DATA)
526 			tptraceTPCB(TPPTmisc,
527 			"RCVD BF: lcredit sent_lcdt cc hiwat \n",
528 				tpcb->tp_lcredit, tpcb->tp_sent_lcdt,
529 				so->so_rcv.sb_cc, so->so_rcv.sb_hiwat);
530 			LOCAL_CREDIT(tpcb);
531 			tptraceTPCB(TPPTmisc,
532 				"PRU_RCVD AF sbspace lcredit hiwat cc",
533 				sbspace(&so->so_rcv), tpcb->tp_lcredit,
534 				so->so_rcv.sb_cc, so->so_rcv.sb_hiwat);
535 		ENDTRACE
536 		IFDEBUG(D_REQUEST)
537 			printf("RCVD: cc %d space %d hiwat %d\n",
538 				so->so_rcv.sb_cc, sbspace(&so->so_rcv),
539 				so->so_rcv.sb_hiwat);
540 		ENDDEBUG
541 		if (((int)nam) & MSG_OOB)
542 			error = DoEvent(T_USR_Xrcvd);
543 		else
544 			error = DoEvent(T_USR_rcvd);
545 		break;
546 
547 	case PRU_RCVOOB:
548 		if ((so->so_state & SS_ISCONNECTED) == 0) {
549 			error = ENOTCONN;
550 			break;
551 		}
552 		if (! tpcb->tp_xpd_service) {
553 			error = EOPNOTSUPP;
554 			break;
555 		}
556 		/* kludge - nam is really flags here */
557 		error = tp_rcvoob(tpcb, so, m, outflags, (int)nam);
558 		break;
559 
560 	case PRU_SEND:
561 	case PRU_SENDOOB:
562 		if (controlp) {
563 			error = tp_snd_control(controlp, so, &m);
564 			controlp = NULL;
565 			if (error)
566 				break;
567 		}
568 		if ((so->so_state & SS_ISCONFIRMING) &&
569 		    (tpcb->tp_state == TP_CONFIRMING) &&
570 		    (error = tp_confirm(tpcb)))
571 			    break;
572 		if (req == PRU_SENDOOB) {
573 			error = (tpcb->tp_xpd_service == 0) ?
574 						EOPNOTSUPP : tp_sendoob(tpcb, so, m, outflags);
575 			break;
576 		}
577 		if (m == 0)
578 			break;
579 		if (m->m_flags & M_EOR) {
580 			eotsdu = 1;
581 			m->m_flags &= ~M_EOR;
582 		}
583 		if (eotsdu == 0 && m->m_pkthdr.len == 0)
584 			break;
585 		if (tpcb->tp_state != TP_AKWAIT && tpcb->tp_state != TP_OPEN) {
586 			error = ENOTCONN;
587 			break;
588 		}
589 		/*
590 		 * The protocol machine copies mbuf chains,
591 		 * prepends headers, assigns seq numbers, and
592 		 * puts the packets on the device.
593 		 * When they are acked they are removed from the socket buf.
594 		 *
595 		 * sosend calls this up until sbspace goes negative.
596 		 * Sbspace may be made negative by appending this mbuf chain,
597 		 * possibly by a whole cluster.
598 		 */
599 		{
600 			/*
601 			 * Could have eotsdu and no data.(presently MUST have
602 			 * an mbuf though, even if its length == 0)
603 			 */
604 			int totlen = m->m_pkthdr.len;
605 			struct sockbuf *sb = &so->so_snd;
606 			IFPERF(tpcb)
607 			   PStat(tpcb, Nb_from_sess) += totlen;
608 			   tpmeas(tpcb->tp_lref, TPtime_from_session, 0, 0,
609 					PStat(tpcb, Nb_from_sess), totlen);
610 			ENDPERF
611 			IFDEBUG(D_SYSCALL)
612 				printf(
613 				"PRU_SEND: eot %d before sbappend 0x%x len 0x%x to sb @ 0x%x\n",
614 					eotsdu, m, totlen, sb);
615 				dump_mbuf(sb->sb_mb, "so_snd.sb_mb");
616 				dump_mbuf(m, "m : to be added");
617 			ENDDEBUG
618 			tp_packetize(tpcb, m, eotsdu);
619 			IFDEBUG(D_SYSCALL)
620 				printf("PRU_SEND: eot %d after sbappend 0x%x\n", eotsdu, m);
621 				dump_mbuf(sb->sb_mb, "so_snd.sb_mb");
622 			ENDDEBUG
623 			if (tpcb->tp_state == TP_OPEN)
624 				error = DoEvent(T_DATA_req);
625 			IFDEBUG(D_SYSCALL)
626 				printf("PRU_SEND: after driver error 0x%x \n",error);
627 				printf("so_snd 0x%x cc 0t%d mbcnt 0t%d\n",
628 						sb, sb->sb_cc, sb->sb_mbcnt);
629 				dump_mbuf(sb->sb_mb, "so_snd.sb_mb after driver");
630 			ENDDEBUG
631 		}
632 		break;
633 
634 	case PRU_SOCKADDR:
635 		(tpcb->tp_nlproto->nlp_getnetaddr)(tpcb->tp_npcb, nam, TP_LOCAL);
636 		break;
637 
638 	case PRU_PEERADDR:
639 		(tpcb->tp_nlproto->nlp_getnetaddr)(tpcb->tp_npcb, nam, TP_FOREIGN);
640 		break;
641 
642 	case PRU_CONTROL:
643 		error = EOPNOTSUPP;
644 		break;
645 
646 	case PRU_PROTOSEND:
647 	case PRU_PROTORCV:
648 	case PRU_SENSE:
649 	case PRU_SLOWTIMO:
650 	case PRU_FASTTIMO:
651 		error = EOPNOTSUPP;
652 		break;
653 
654 	default:
655 #ifdef ARGO_DEBUG
656 		printf("tp_usrreq UNKNOWN PRU %d\n", req);
657 #endif /* ARGO_DEBUG */
658 		error = EOPNOTSUPP;
659 	}
660 
661 	IFDEBUG(D_REQUEST)
662 		printf("%s, so 0x%x, tpcb 0x%x, error %d, state %d\n",
663 			"returning from tp_usrreq", so, tpcb, error,
664 			tpcb ? tpcb->tp_state : 0);
665 	ENDDEBUG
666 	IFTRACE(D_REQUEST)
667 		tptraceTPCB(TPPTusrreq, "END req so m state [", req, so, m,
668 			tpcb ? tpcb->tp_state : 0);
669 	ENDTRACE
670 	if (controlp) {
671 		m_freem(controlp);
672 		printf("control data unexpectedly retained in tp_usrreq()");
673 	}
674 	splx(s);
675 	return error;
676 }
677 tp_ltrace(so, uio)
678 struct socket *so;
679 struct uio *uio;
680 {
681 	IFTRACE(D_DATA)
682 		register struct tp_pcb *tpcb =  sototpcb(so);
683 		if (tpcb) {
684 			tptraceTPCB(TPPTmisc, "sosend so resid iovcnt", so,
685 				uio->uio_resid, uio->uio_iovcnt, 0);
686 		}
687 	ENDTRACE
688 }
689 
690 tp_confirm(tpcb)
691 register struct tp_pcb *tpcb;
692 {
693 	struct tp_event E;
694 	if (tpcb->tp_state == TP_CONFIRMING)
695 	    return DoEvent(T_ACPT_req);
696 	printf("Tp confirm called when not confirming; tpcb 0x%x, state 0x%x\n",
697 		tpcb, tpcb->tp_state);
698 	return 0;
699 }
700 
701 /*
702  * Process control data sent with sendmsg()
703  */
704 tp_snd_control(m, so, data)
705 	struct mbuf *m;
706 	struct socket *so;
707 	register struct mbuf **data;
708 {
709 	register struct cmsghdr *ch;
710 	int error = 0;
711 
712 	if (m && m->m_len) {
713 		ch = mtod(m, struct cmsghdr *);
714 		m->m_len -= sizeof (*ch);
715 		m->m_data += sizeof (*ch);
716 		error = tp_ctloutput(PRCO_SETOPT,
717 							 so, ch->cmsg_level, ch->cmsg_type, &m);
718 		if (ch->cmsg_type == TPOPT_DISC_DATA) {
719 			if (data && *data) {
720 				m_freem(*data);
721 				*data = 0;
722 			}
723 			error = tp_usrreq(so, PRU_DISCONNECT, (struct mbuf *)0,
724 								(caddr_t)0, (struct mbuf *)0);
725 		}
726 	}
727 	if (m)
728 		m_freem(m);
729 	return error;
730 }
731