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