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