xref: /csrg-svn/sys/netiso/tp_usrreq.c (revision 39647)
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.6 (Berkeley) 11/28/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 ((nn = n) && n->m_pkthdr.len < maxsize) {
634 				int space = maxsize - n->m_pkthdr.len;
635 
636 				do {
637 					if (n->m_flags & M_EOR)
638 						goto on1;
639 				} while (n->m_next && (n = n->m_next));
640 				nn->m_pkthdr.len += space;
641 				if (m->m_pkthdr.len <= space) {
642 					n->m_next = m;
643 					sballoc(sb, m);
644 					if (eotsdu)
645 						nn->m_flags |= M_EOR;
646 					goto on2;
647 				} else {
648 					nn->m_next = m_copym(m, 0, space, M_WAIT);
649 					sballoc(sb, nn->m_next);
650 					m_adj(m, space);
651 				}
652 			}
653 	on1:	len++;
654 			for (n = m; n->m_pkthdr.len > maxsize;) {
655 				nn = m_copym(n, 0, len, M_WAIT);
656 				sbappendrecord(sb, nn);
657 				m_adj(n, maxsize);
658 				len++;
659 			}
660 			if (eotsdu)
661 				n->m_flags |= M_EOR;
662 			sbappendrecord(sb, n);
663 	on2:
664 			IFTRACE(D_DATA)
665 				tptraceTPCB(TPPTmisc,
666 				"SEND BF: maxsize totlen frags eotsdu",
667 					maxsize, totlen, len, eotsdu);
668 			ENDTRACE
669 			IFDEBUG(D_SYSCALL)
670 				printf("PRU_SEND: eot %d after sbappend 0x%x len 0x%x\n",
671 					eotsdu, n, len);
672 				dump_mbuf(sb->sb_mb, "so_snd.sb_mb");
673 			ENDDEBUG
674 			error = DoEvent(T_DATA_req);
675 			IFDEBUG(D_SYSCALL)
676 				printf("PRU_SEND: after driver error 0x%x \n",error);
677 				printf("so_snd 0x%x cc 0t%d mbcnt 0t%d\n",
678 						sb, sb->sb_cc, sb->sb_mbcnt);
679 				dump_mbuf(sb->sb_mb, "so_snd.sb_mb after driver");
680 			ENDDEBUG
681 		}
682 		break;
683 
684 	case PRU_SOCKADDR:
685 		(tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_LOCAL);
686 		break;
687 
688 	case PRU_PEERADDR:
689 		(tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN);
690 		break;
691 
692 	case PRU_CONTROL:
693 		error = EOPNOTSUPP;
694 		break;
695 
696 	case PRU_PROTOSEND:
697 	case PRU_PROTORCV:
698 	case PRU_SENSE:
699 	case PRU_SLOWTIMO:
700 	case PRU_FASTTIMO:
701 		error = EOPNOTSUPP;
702 		break;
703 
704 	default:
705 #ifdef ARGO_DEBUG
706 		printf("tp_usrreq UNKNOWN PRU %d\n", req);
707 #endif ARGO_DEBUG
708 		error = EOPNOTSUPP;
709 	}
710 
711 	IFDEBUG(D_REQUEST)
712 		printf("%s, so 0x%x, tpcb 0x%x, error %d, state %d\n",
713 			"returning from tp_usrreq", so, tpcb, error,
714 			tpcb ? 0 : tpcb->tp_state);
715 	ENDDEBUG
716 	IFTRACE(D_REQUEST)
717 		tptraceTPCB(TPPTusrreq, "END req so m state [", req, so, m,
718 			tpcb?0:tpcb->tp_state);
719 	ENDTRACE
720 	splx(s);
721 	return error;
722 }
723 tp_ltrace(so, uio)
724 struct socket *so;
725 struct uio *uio;
726 {
727 	IFTRACE(D_DATA)
728 		register struct tp_pcb *tpcb =  sototpcb(so);
729 		if (tpcb) {
730 			tptraceTPCB(TPPTmisc, "sosend so resid iovcnt", so,
731 				uio->uio_resid, uio->uio_iovcnt, 0);
732 		}
733 	ENDTRACE
734 }
735 
736 tp_confirm(tpcb)
737 register struct tp_pcb *tpcb;
738 {
739 	struct tp_event E;
740 	if (tpcb->tp_state == TP_CONFIRMING)
741 	    return DoEvent(T_ACPT_req);
742 	printf("Tp confirm called when not confirming; tpcb 0x%x, state 0x%x\n",
743 		tpcb, tpcb->tp_state);
744 	return 0;
745 }
746 
747 /*
748  * Process control data sent with sendmsg()
749  */
750 tp_snd_control(m0, so, data)
751 	register struct mbuf *m0;
752 	struct socket *so;
753 	register struct mbuf **data;
754 {
755 	register struct tp_control_hdr *ch;
756 	struct mbuf *m;
757 	int error = 0;
758 
759 	if (m0 && m0->m_len) {
760 		ch = mtod(m0, struct tp_control_hdr *);
761 		m0->m_len -= sizeof (*ch);
762 		m0->m_data += sizeof (*ch);
763 		m = m_copym(m0, 0, M_COPYALL, M_WAIT);
764 		error = tp_ctloutput(PRCO_SETOPT,
765 							 so, ch->cmsg_level, ch->cmsg_type, &m);
766 		if (m)
767 			m_freem(m);
768 		if (ch->cmsg_type == TPOPT_DISC_DATA) {
769 			if (data && *data) {
770 				m_freem(*data);
771 				*data = 0;
772 			}
773 			m0 = 0;
774 			error = tp_usrreq(so, PRU_DISCONNECT, m0, (caddr_t)0, m0, m0);
775 		}
776 	}
777 	return error;
778 }
779