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