xref: /csrg-svn/sys/netiso/tp_usrreq.c (revision 41924)
136420Ssklower /***********************************************************
239196Ssklower 				Copyright IBM Corporation 1987
336420Ssklower 
436420Ssklower                       All Rights Reserved
536420Ssklower 
636420Ssklower Permission to use, copy, modify, and distribute this software and its
736420Ssklower documentation for any purpose and without fee is hereby granted,
836420Ssklower provided that the above copyright notice appear in all copies and that
936420Ssklower both that copyright notice and this permission notice appear in
1036420Ssklower supporting documentation, and that the name of IBM not be
1136420Ssklower used in advertising or publicity pertaining to distribution of the
1236420Ssklower software without specific, written prior permission.
1336420Ssklower 
1436420Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
1536420Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
1636420Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
1736420Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
1836420Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
1936420Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2036420Ssklower SOFTWARE.
2136420Ssklower 
2236420Ssklower ******************************************************************/
2336420Ssklower 
2436420Ssklower /*
2536420Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
2636420Ssklower  */
2736420Ssklower /*
2836420Ssklower  * ARGO TP
2936420Ssklower  *
3036420Ssklower  * $Header: tp_usrreq.c,v 5.4 88/11/18 17:29:18 nhall Exp $
3136420Ssklower  * $Source: /usr/argo/sys/netiso/RCS/tp_usrreq.c,v $
32*41924Ssklower  *	@(#)tp_usrreq.c	7.9 (Berkeley) 05/14/90
3336420Ssklower  *
3436420Ssklower  * tp_usrreq(), the fellow that gets called from most of the socket code.
3536420Ssklower  * Pretty straighforward.
3636420Ssklower  * THe only really awful stuff here is the OOB processing, which is done
3736420Ssklower  * wholly here.
3836420Ssklower  * tp_rcvoob() and tp_sendoob() are contained here and called by tp_usrreq().
3936420Ssklower  */
4036420Ssklower 
4136420Ssklower #ifndef lint
4236420Ssklower static char *rcsid = "$Header: tp_usrreq.c,v 5.4 88/11/18 17:29:18 nhall Exp $";
4336420Ssklower #endif lint
4436420Ssklower 
4536420Ssklower #include "param.h"
4636420Ssklower #include "systm.h"
4736420Ssklower #include "user.h"
4836420Ssklower #include "mbuf.h"
4936420Ssklower #include "socket.h"
5036420Ssklower #include "socketvar.h"
5136420Ssklower #include "domain.h"
5236420Ssklower #include "protosw.h"
5336420Ssklower #include "errno.h"
5436420Ssklower 
5537469Ssklower #include "tp_param.h"
5637469Ssklower #include "tp_timer.h"
5737469Ssklower #include "tp_stat.h"
5837469Ssklower #include "tp_seq.h"
5937469Ssklower #include "tp_ip.h"
6037469Ssklower #include "tp_pcb.h"
6137469Ssklower #include "argo_debug.h"
6237469Ssklower #include "tp_trace.h"
6337469Ssklower #include "tp_meas.h"
6437469Ssklower #include "iso.h"
6537469Ssklower #include "iso_errno.h"
6636420Ssklower 
6736420Ssklower int tp_attach(), tp_driver();
6839937Ssklower int TNew;
6939937Ssklower int TPNagle1, TPNagle2;
7036420Ssklower 
7136420Ssklower #ifdef ARGO_DEBUG
7236420Ssklower /*
7336420Ssklower  * CALLED FROM:
7436420Ssklower  *  anywhere you want to debug...
7536420Ssklower  * FUNCTION and ARGUMENTS:
7636420Ssklower  *  print (str) followed by the control info in the mbufs of an mbuf chain (n)
7736420Ssklower  */
7836420Ssklower void
7936420Ssklower dump_mbuf(n, str)
8036420Ssklower 	struct mbuf *n;
8136420Ssklower 	char *str;
8236420Ssklower {
8336420Ssklower 	struct mbuf *nextrecord;
8436420Ssklower 
8536420Ssklower 	printf("dump %s\n", str);
8636420Ssklower 
8736420Ssklower 	if( n == MNULL)  {
8836420Ssklower 		printf("EMPTY:\n");
8936420Ssklower 		return;
9036420Ssklower 	}
9136420Ssklower 
9236420Ssklower 	for(;n;) {
9336420Ssklower 		nextrecord = n->m_act;
9436420Ssklower 		printf("RECORD:\n");
9536420Ssklower 		while (n) {
9637469Ssklower 			printf("%x : Len %x Data %x A %x Nx %x Tp %x\n",
9737469Ssklower 				n, n->m_len, n->m_data, n->m_act, n->m_next, n->m_type);
9836420Ssklower #ifdef notdef
9936420Ssklower 			{
10036420Ssklower 				register char *p = mtod(n, char *);
10136420Ssklower 				register int i;
10236420Ssklower 
10336420Ssklower 				printf("data: ");
10436420Ssklower 				for(i=0; i < n->m_len; i++ ) {
10536420Ssklower 					if(i%8 == 0)
10636420Ssklower 						printf("\n");
10736420Ssklower 					printf("0x%x ", *(p+i));
10836420Ssklower 				}
10936420Ssklower 				printf("\n");
11036420Ssklower 			}
11136420Ssklower #endif notdef
11236420Ssklower 			if( n->m_next == n ) {
11336420Ssklower 				printf("LOOP!\n");
11436420Ssklower 				return;
11536420Ssklower 			}
11636420Ssklower 			n = n->m_next;
11736420Ssklower 		}
11836420Ssklower 		n = nextrecord;
11936420Ssklower 	}
12036420Ssklower 	printf("\n");
12136420Ssklower }
12236420Ssklower 
12336420Ssklower #endif ARGO_DEBUG
12436420Ssklower 
12536420Ssklower /*
12636420Ssklower  * CALLED FROM:
12736420Ssklower  *  tp_usrreq(), PRU_RCVOOB
12836420Ssklower  * FUNCTION and ARGUMENTS:
12936420Ssklower  * 	Copy data from the expedited data socket buffer into
13036420Ssklower  * 	the pre-allocated mbuf m.
13136420Ssklower  * 	There is an isomorphism between XPD TPDUs and expedited data TSDUs.
13236420Ssklower  * 	XPD tpdus are limited to 16 bytes of data so they fit in one mbuf.
13336420Ssklower  * RETURN VALUE:
13436420Ssklower  *  EINVAL if debugging is on and a disaster has occurred
13536420Ssklower  *  ENOTCONN if the socket isn't connected
13636420Ssklower  *  EWOULDBLOCK if the socket is in non-blocking mode and there's no
13736420Ssklower  *		xpd data in the buffer
13836420Ssklower  *  E* whatever is returned from the fsm.
13936420Ssklower  */
14036420Ssklower tp_rcvoob(tpcb, so, m, outflags, inflags)
14136420Ssklower 	struct tp_pcb	*tpcb;
14236420Ssklower 	register struct socket	*so;
14336420Ssklower 	register struct mbuf 	*m;
14436420Ssklower 	int 		 	*outflags;
14536420Ssklower 	int 		 	inflags;
14636420Ssklower {
14736420Ssklower 	register struct mbuf *n;
14837469Ssklower 	register struct sockbuf *sb = &so->so_rcv;
14936420Ssklower 	struct tp_event E;
15036420Ssklower 	int error = 0;
15137469Ssklower 	register struct mbuf **nn;
15236420Ssklower 
15336420Ssklower 	IFDEBUG(D_XPD)
15436420Ssklower 		printf("PRU_RCVOOB, sostate 0x%x\n", so->so_state);
15536420Ssklower 	ENDDEBUG
15636420Ssklower 
15736420Ssklower 	/* if you use soreceive */
15836420Ssklower 	if (m==MNULL)
15936420Ssklower 		return ENOBUFS;
16036420Ssklower 
16136420Ssklower restart:
16236420Ssklower 	if ((((so->so_state & SS_ISCONNECTED) == 0)
16336420Ssklower 		 || (so->so_state & SS_ISDISCONNECTING) != 0) &&
16436420Ssklower 		(so->so_proto->pr_flags & PR_CONNREQUIRED)) {
16536420Ssklower 			return ENOTCONN;
16636420Ssklower 	}
16736420Ssklower 
16837469Ssklower 	/* Take the first mbuf off the chain.
16937469Ssklower 	 * Each XPD TPDU gives you a complete TSDU so the chains don't get
17037469Ssklower 	 * coalesced, but one TSDU may span several mbufs.
17137469Ssklower 	 * Nevertheless, since n should have a most 16 bytes, it
17237469Ssklower 	 * will fit into m.  (size was checked in tp_input() )
17337469Ssklower 	 */
17437469Ssklower 
17537469Ssklower 	/*
17637469Ssklower 	 * Code for excision of OOB data should be added to
17737469Ssklower 	 * uipc_socket2.c (like sbappend).
17837469Ssklower 	 */
17937469Ssklower 
18038841Ssklower 	sblock(sb);
18137469Ssklower 	for (nn = &sb->sb_mb; n = *nn; nn = &n->m_act)
18237469Ssklower 		if (n->m_type == MT_OOBDATA)
18337469Ssklower 			break;
18437469Ssklower 
18537469Ssklower 	if (n == 0) {
18636420Ssklower 		ASSERT( (tpcb->tp_flags & TPF_DISC_DATA_IN)  == 0 );
18736420Ssklower 		IFDEBUG(D_XPD)
18836420Ssklower 			printf("RCVOOB: empty queue!\n");
18936420Ssklower 		ENDDEBUG
19038841Ssklower 		sbunlock(sb);
19136420Ssklower 		if (so->so_state & SS_NBIO) {
19236420Ssklower 			return  EWOULDBLOCK;
19336420Ssklower 		}
19436420Ssklower 		sbwait(sb);
19536420Ssklower 		goto restart;
19636420Ssklower 	}
19736420Ssklower 	m->m_len = 0;
19836420Ssklower 
19936420Ssklower 	/* Assuming at most one xpd tpdu is in the buffer at once */
20036420Ssklower 	while ( n != MNULL ) {
20136420Ssklower 		m->m_len += n->m_len;
20237469Ssklower 		bcopy(mtod(n, caddr_t), mtod(m, caddr_t), (unsigned)n->m_len);
20337469Ssklower 		m->m_data += n->m_len; /* so mtod() in bcopy() above gives right addr */
20436420Ssklower 		n = n->m_next;
20536420Ssklower 	}
20637469Ssklower 	m->m_data = m->m_dat;
20737469Ssklower 	m->m_flags |= M_EOR;
20836420Ssklower 
20936420Ssklower 	IFDEBUG(D_XPD)
21036420Ssklower 		printf("tp_rcvoob: xpdlen 0x%x\n", m->m_len);
21136420Ssklower 		dump_mbuf(so->so_rcv.sb_mb, "RCVOOB: Rcv socketbuf");
21236420Ssklower 		dump_mbuf(sb->sb_mb, "RCVOOB: Xrcv socketbuf");
21336420Ssklower 	ENDDEBUG
21436420Ssklower 
21537469Ssklower 	if( (inflags & MSG_PEEK) == 0 ) {
21637469Ssklower 		n = *nn;
21737469Ssklower 		*nn = n->m_act;
21837469Ssklower 		sb->sb_cc -= m->m_len;
21937469Ssklower 	}
22036420Ssklower 
22136420Ssklower release:
22236420Ssklower 	sbunlock(sb);
22336420Ssklower 
22436420Ssklower 	IFTRACE(D_XPD)
22536420Ssklower 		tptraceTPCB(TPPTmisc, "PRU_RCVOOB @ release sb_cc m_len",
22636420Ssklower 			tpcb->tp_Xrcv.sb_cc, m->m_len,0,0 );
22736420Ssklower 	ENDTRACE
22836420Ssklower 	if (error == 0)
22936420Ssklower 		error = DoEvent(T_USR_Xrcvd);
23036420Ssklower 	return error;
23136420Ssklower }
23236420Ssklower 
23336420Ssklower /*
23436420Ssklower  * CALLED FROM:
23536420Ssklower  *  tp_usrreq(), PRU_SENDOOB
23636420Ssklower  * FUNCTION and ARGUMENTS:
23736420Ssklower  * 	Send what's in the mbuf chain (m) as an XPD TPDU.
23836420Ssklower  * 	The mbuf may not contain more then 16 bytes of data.
23936420Ssklower  * 	XPD TSDUs aren't segmented, so they translate into
24036420Ssklower  * 	exactly one XPD TPDU, with EOT bit set.
24136420Ssklower  * RETURN VALUE:
24236420Ssklower  *  EWOULDBLOCK if socket is in non-blocking mode and the previous
24336420Ssklower  *   xpd data haven't been acked yet.
24436420Ssklower  *  EMSGSIZE if trying to send > max-xpd bytes (16)
24536420Ssklower  *  ENOBUFS if ran out of mbufs
24636420Ssklower  */
24736420Ssklower tp_sendoob(tpcb, so, xdata, outflags)
24836420Ssklower 	struct tp_pcb	*tpcb;
24936420Ssklower 	register struct socket	*so;
25036420Ssklower 	register struct mbuf 	*xdata;
25136420Ssklower 	int 		 	*outflags; /* not used */
25236420Ssklower {
25336420Ssklower 	/*
25436420Ssklower 	 * Each mbuf chain represents a sequence # in the XPD seq space.
25536420Ssklower 	 * The first one in the queue has sequence # tp_Xuna.
25636420Ssklower 	 * When we add to the XPD queue, we stuff a zero-length
25736420Ssklower 	 * mbuf (mark) into the DATA queue, with its sequence number in m_next
25836420Ssklower 	 * to be assigned to this XPD tpdu, so data xfer can stop
25936420Ssklower 	 * when it reaches the zero-length mbuf if this XPD TPDU hasn't
26036420Ssklower 	 * yet been acknowledged.
26136420Ssklower 	 */
26236420Ssklower 	register struct sockbuf *sb = &(tpcb->tp_Xsnd);
26336420Ssklower 	register struct mbuf 	*xmark;
26436420Ssklower 	register int 			len=0;
26536420Ssklower 	struct tp_event E;
26636420Ssklower 
26736420Ssklower 	IFDEBUG(D_XPD)
26836420Ssklower 		printf("tp_sendoob:");
26936420Ssklower 		if(xdata)
27036420Ssklower 			printf("xdata len 0x%x\n", xdata->m_len);
27136420Ssklower 	ENDDEBUG
27236420Ssklower 	/* DO NOT LOCK the Xsnd buffer!!!! You can have at MOST one
27336420Ssklower 	 * socket buf locked at any time!!! (otherwise you might
27436420Ssklower 	 * sleep() in sblock() w/ a signal pending and cause the
27536420Ssklower 	 * system call to be aborted w/ a locked socketbuf, which
27636420Ssklower 	 * is a problem.  So the so_snd buffer lock
27736420Ssklower 	 * (done in sosend()) serves as the lock for Xpd.
27836420Ssklower 	 */
27938841Ssklower 	if (sb->sb_mb) { /* Anything already in eXpedited data sockbuf? */
28036420Ssklower 		if (so->so_state & SS_NBIO) {
28136420Ssklower 			return EWOULDBLOCK;
28236420Ssklower 		}
28338841Ssklower 		while (sb->sb_mb) {
28438841Ssklower 			sbunlock(&so->so_snd); /* already locked by sosend */
28538841Ssklower 			sbwait(&so->so_snd);
28638841Ssklower 			sblock(&so->so_snd);  /* sosend will unlock on return */
28738841Ssklower 		}
28836420Ssklower 	}
28936420Ssklower 
29036420Ssklower 	if (xdata == (struct mbuf *)0) {
29136420Ssklower 		/* empty xpd packet */
29237469Ssklower 		MGETHDR(xdata, M_WAIT, MT_OOBDATA);
29336420Ssklower 		if (xdata == NULL) {
29436420Ssklower 			return ENOBUFS;
29536420Ssklower 		}
29636420Ssklower 		xdata->m_len = 0;
29737469Ssklower 		xdata->m_pkthdr.len = 0;
29836420Ssklower 	}
29936420Ssklower 	IFDEBUG(D_XPD)
30036420Ssklower 		printf("tp_sendoob 1:");
30136420Ssklower 		if(xdata)
30236420Ssklower 			printf("xdata len 0x%x\n", xdata->m_len);
30336420Ssklower 	ENDDEBUG
30436420Ssklower 	xmark = xdata; /* temporary use of variable xmark */
30536420Ssklower 	while (xmark) {
30636420Ssklower 		len += xmark->m_len;
30736420Ssklower 		xmark = xmark->m_next;
30836420Ssklower 	}
30936420Ssklower 	if (len > TP_MAX_XPD_DATA) {
31036420Ssklower 		return EMSGSIZE;
31136420Ssklower 	}
31236420Ssklower 	IFDEBUG(D_XPD)
31336420Ssklower 		printf("tp_sendoob 2:");
31436420Ssklower 		if(xdata)
31536420Ssklower 			printf("xdata len 0x%x\n", len);
31636420Ssklower 	ENDDEBUG
31736420Ssklower 
31836420Ssklower 
31936420Ssklower 	IFTRACE(D_XPD)
32038841Ssklower 		tptraceTPCB(TPPTmisc, "XPD mark m_next ", xdata->m_next, 0, 0, 0);
32136420Ssklower 	ENDTRACE
32236420Ssklower 
32336420Ssklower 	sbappendrecord(sb, xdata);
32436420Ssklower 
32536420Ssklower 	IFDEBUG(D_XPD)
32636420Ssklower 		printf("tp_sendoob len 0x%x\n", len);
32736420Ssklower 		dump_mbuf(so->so_snd.sb_mb, "XPD request Regular sndbuf:");
32836420Ssklower 		dump_mbuf(tpcb->tp_Xsnd.sb_mb, "XPD request Xsndbuf:");
32936420Ssklower 	ENDDEBUG
33036420Ssklower 	return DoEvent(T_XPD_req);
33136420Ssklower }
33236420Ssklower 
33336420Ssklower /*
33436420Ssklower  * CALLED FROM:
33536420Ssklower  *  the socket routines
33636420Ssklower  * FUNCTION and ARGUMENTS:
33736420Ssklower  * 	Handles all "user requests" except the [gs]ockopts() requests.
33836420Ssklower  * 	The argument (req) is the request type (PRU*),
33936420Ssklower  * 	(m) is an mbuf chain, generally used for send and
34036420Ssklower  * 	receive type requests only.
34136420Ssklower  * 	(nam) is used for addresses usually, in particular for the bind request.
34236420Ssklower  *
34336420Ssklower  */
34436420Ssklower /*ARGSUSED*/
34536420Ssklower ProtoHook
34640773Ssklower tp_usrreq(so, req, m, nam, controlp)
34736420Ssklower 	struct socket *so;
34836420Ssklower 	u_int req;
34940773Ssklower 	struct mbuf *m, *nam, *controlp;
35036420Ssklower {
35136420Ssklower 	register struct tp_pcb *tpcb =  sototpcb(so);
35236420Ssklower 	int s = splnet();
35336420Ssklower 	int error = 0;
35437469Ssklower 	int flags, *outflags = &flags;
35536420Ssklower 	u_long eotsdu = 0;
35636420Ssklower 	struct tp_event E;
35736420Ssklower 
35836420Ssklower 	IFDEBUG(D_REQUEST)
35936420Ssklower 		printf("usrreq(0x%x,%d,0x%x,0x%x,0x%x)\n",so,req,m,nam,outflags);
36036420Ssklower 		if(so->so_error)
36136420Ssklower 			printf("WARNING!!! so->so_error is 0x%x\n", so->so_error);
36236420Ssklower 	ENDDEBUG
36336420Ssklower 	IFTRACE(D_REQUEST)
36436420Ssklower 		tptraceTPCB(TPPTusrreq, "req so m state [", req, so, m,
36536420Ssklower 			tpcb?tpcb->tp_state:0);
36636420Ssklower 	ENDTRACE
36736420Ssklower 
36836420Ssklower 	if ((u_int)tpcb == 0 && req != PRU_ATTACH) {
36936420Ssklower 		IFTRACE(D_REQUEST)
37036420Ssklower 			tptraceTPCB(TPPTusrreq, "req failed NO TPCB[", 0, 0, 0, 0);
37136420Ssklower 		ENDTRACE
37236420Ssklower 		splx(s);
37336420Ssklower 		return ENOTCONN;
37436420Ssklower 	}
37536420Ssklower 
37636420Ssklower 	switch (req) {
37736420Ssklower 
37836420Ssklower 	case PRU_ATTACH:
37936420Ssklower 		if (tpcb) {
38036420Ssklower 			error = EISCONN;
38136420Ssklower 			break;
38236420Ssklower 		}
38336420Ssklower 		if( error = tp_attach(so, so->so_proto->pr_domain->dom_family ) )
38436420Ssklower 			break;
38536420Ssklower 		tpcb = sototpcb(so);
38636420Ssklower 		break;
38736420Ssklower 
38836420Ssklower 	case PRU_ABORT: 	/* called from close() */
38936420Ssklower 		/* called for each incoming connect queued on the
39036420Ssklower 		 *	parent (accepting) socket
39136420Ssklower 		 */
39236420Ssklower 		if( tpcb->tp_state == TP_OPEN ) {
39336420Ssklower 			E.ATTR(T_DISC_req).e_reason = E_TP_NO_SESSION;
39436420Ssklower 			error = DoEvent(T_DISC_req); /* pretend it was a close() */
39536420Ssklower 			break;
39636420Ssklower 		} /* else DROP THROUGH */
39736420Ssklower 
39836420Ssklower 	case PRU_DETACH: 	/* called from close() */
39936420Ssklower 		/* called only after disconnect was called */
40036420Ssklower 		error = DoEvent(T_DETACH);
40137469Ssklower 		if (tpcb->tp_state == TP_CLOSED) {
40237469Ssklower 			free((caddr_t)tpcb, M_PCB);
40337469Ssklower 			tpcb = 0;
40437469Ssklower 		}
40536420Ssklower 		break;
40636420Ssklower 
40736420Ssklower 	case PRU_SHUTDOWN:
40836420Ssklower 		/* recv end may have been released; local credit might be zero  */
40936420Ssklower 	case PRU_DISCONNECT:
41036420Ssklower 		E.ATTR(T_DISC_req).e_reason = E_TP_NORMAL_DISC;
41136420Ssklower 		error = DoEvent(T_DISC_req);
41236420Ssklower 		break;
41336420Ssklower 
41436420Ssklower 	case PRU_BIND:
41536420Ssklower 		error =  (tpcb->tp_nlproto->nlp_pcbbind)( so->so_pcb, nam );
41636420Ssklower 		if (error == 0) {
41737469Ssklower 			(tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
41837469Ssklower 				tpcb->tp_lsuffix, TP_LOCAL );
41936420Ssklower 		}
42036420Ssklower 		break;
42136420Ssklower 
42236420Ssklower 	case PRU_LISTEN:
42338841Ssklower 		if( tpcb->tp_lsuffixlen ==  0) {
42436420Ssklower 			if( error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL) )
42536420Ssklower 				break;
42637469Ssklower 			(tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
42737469Ssklower 				tpcb->tp_lsuffix, TP_LOCAL );
42836420Ssklower 		}
42936420Ssklower 		IFDEBUG(D_TPISO)
43036420Ssklower 			if(tpcb->tp_state != TP_CLOSED)
43136420Ssklower 				printf("LISTEN ERROR: state 0x%x\n", tpcb->tp_state);
43236420Ssklower 		ENDDEBUG
43336420Ssklower 		error = DoEvent(T_LISTEN_req);
43436420Ssklower 		break;
43536420Ssklower 
43636420Ssklower 	case PRU_CONNECT2:
43736420Ssklower 		error = EOPNOTSUPP; /* for unix domain sockets */
43836420Ssklower 		break;
43936420Ssklower 
44036420Ssklower 	case PRU_CONNECT:
44136420Ssklower 		IFTRACE(D_CONN)
44236420Ssklower 			tptraceTPCB(TPPTmisc,
44337469Ssklower 			"PRU_CONNECT: so 0x%x *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x",
44436420Ssklower 			tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen,
44536420Ssklower 				tpcb->tp_class);
44636420Ssklower 		ENDTRACE
44736420Ssklower 		IFDEBUG(D_CONN)
44836420Ssklower 			printf("PRU_CONNECT: so *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x",
44936420Ssklower 			tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen,
45036420Ssklower 				tpcb->tp_class);
45136420Ssklower 		ENDDEBUG
45238841Ssklower 		if( tpcb->tp_lsuffixlen ==  0) {
45336420Ssklower 			if( error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL) ) {
45436420Ssklower 				IFDEBUG(D_CONN)
45536420Ssklower 					printf("pcbbind returns error 0x%x\n", error );
45636420Ssklower 				ENDDEBUG
45736420Ssklower 				break;
45836420Ssklower 			}
45937469Ssklower 			(tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
46037469Ssklower 				tpcb->tp_lsuffix, TP_LOCAL );
46137469Ssklower 		}
46236420Ssklower 
46336420Ssklower 		IFDEBUG(D_CONN)
46436420Ssklower 			printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb);
46536420Ssklower 			dump_buf( tpcb->tp_npcb, 16);
46636420Ssklower 		ENDDEBUG
46736420Ssklower 		if( error = tp_route_to( nam, tpcb, /* channel */0) )
46836420Ssklower 			break;
46936420Ssklower 		IFDEBUG(D_CONN)
47036420Ssklower 			printf(
47136420Ssklower 				"PRU_CONNECT after tpcb 0x%x so 0x%x npcb 0x%x flags 0x%x\n",
47236420Ssklower 				tpcb, so, tpcb->tp_npcb, tpcb->tp_flags);
47336420Ssklower 			printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb);
47436420Ssklower 			dump_buf( tpcb->tp_npcb, 16);
47536420Ssklower 		ENDDEBUG
47637469Ssklower 		if( tpcb->tp_fsuffixlen ==  0) {
47736420Ssklower 			/* didn't set peer extended suffix */
47837469Ssklower 			(tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_fsuffixlen,
47937469Ssklower 				tpcb->tp_fsuffix, TP_FOREIGN );
48036420Ssklower 		}
48136420Ssklower 		(void) (tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb,
48236420Ssklower 					&tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0);
48336420Ssklower 		if( tpcb->tp_state == TP_CLOSED) {
48436420Ssklower 			soisconnecting(so);
48536420Ssklower 			error = DoEvent(T_CONN_req);
48636420Ssklower 		} else {
48736420Ssklower 			(tpcb->tp_nlproto->nlp_pcbdisc)(so->so_pcb);
48836420Ssklower 			error = EISCONN;
48936420Ssklower 		}
49036420Ssklower 		IFPERF(tpcb)
49136420Ssklower 			u_int lsufx, fsufx;
49239196Ssklower 			lsufx = *(u_short *)(tpcb->tp_lsuffix);
49339196Ssklower 			fsufx = *(u_short *)(tpcb->tp_fsuffix);
49436420Ssklower 
49536420Ssklower 			tpmeas( tpcb->tp_lref,
49636420Ssklower 				TPtime_open | (tpcb->tp_xtd_format <<4 ),
49736420Ssklower 				&time, lsufx, fsufx, tpcb->tp_fref);
49836420Ssklower 		ENDPERF
49936420Ssklower 		break;
50036420Ssklower 
50136420Ssklower 	case PRU_ACCEPT:
50238841Ssklower 		(tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN);
50336420Ssklower 		IFDEBUG(D_REQUEST)
50438841Ssklower 			printf("ACCEPT PEERADDDR:");
50538841Ssklower 			dump_buf(mtod(nam, char *), nam->m_len);
50636420Ssklower 		ENDDEBUG
50736420Ssklower 		IFPERF(tpcb)
50836420Ssklower 			u_int lsufx, fsufx;
50939196Ssklower 			lsufx = *(u_short *)(tpcb->tp_lsuffix);
51039196Ssklower 			fsufx = *(u_short *)(tpcb->tp_fsuffix);
51136420Ssklower 
51236420Ssklower 			tpmeas( tpcb->tp_lref, TPtime_open,
51336420Ssklower 				&time, lsufx, fsufx, tpcb->tp_fref);
51436420Ssklower 		ENDPERF
51536420Ssklower 		break;
51636420Ssklower 
51736420Ssklower 	case PRU_RCVD:
51838841Ssklower 		if (so->so_state & SS_ISCONFIRMING) {
51938841Ssklower 			if (tpcb->tp_state == TP_CONFIRMING)
52038841Ssklower 				error = tp_confirm(tpcb);
52138841Ssklower 			break;
52238841Ssklower 		}
52336420Ssklower 		IFTRACE(D_DATA)
52436420Ssklower 			tptraceTPCB(TPPTmisc,
52536420Ssklower 			"RCVD BF: lcredit sent_lcdt cc hiwat \n",
52636420Ssklower 				tpcb->tp_lcredit, tpcb->tp_sent_lcdt,
52736420Ssklower 				so->so_rcv.sb_cc, so->so_rcv.sb_hiwat);
52836420Ssklower 			LOCAL_CREDIT(tpcb);
52936420Ssklower 			tptraceTPCB(TPPTmisc,
53036420Ssklower 				"PRU_RCVD AF sbspace lcredit hiwat cc",
53136420Ssklower 				sbspace(&so->so_rcv), tpcb->tp_lcredit,
53236420Ssklower 				so->so_rcv.sb_cc, so->so_rcv.sb_hiwat);
53336420Ssklower 		ENDTRACE
53437469Ssklower 		IFDEBUG(D_REQUEST)
53537469Ssklower 			printf("RCVD: cc %d space %d hiwat %d\n",
53637469Ssklower 				so->so_rcv.sb_cc, sbspace(&so->so_rcv),
53737469Ssklower 				so->so_rcv.sb_hiwat);
53837469Ssklower 		ENDDEBUG
53937469Ssklower 		if (((int)nam) & MSG_OOB)
54037469Ssklower 			error = DoEvent(T_USR_Xrcvd);
54137469Ssklower 		else
54237469Ssklower 			error = DoEvent(T_USR_rcvd);
54336420Ssklower 		break;
54436420Ssklower 
54536420Ssklower 	case PRU_RCVOOB:
54636420Ssklower 		if ((so->so_state & SS_ISCONNECTED) == 0) {
54736420Ssklower 			error = ENOTCONN;
54836420Ssklower 			break;
54936420Ssklower 		}
55036420Ssklower 		if( ! tpcb->tp_xpd_service ) {
55136420Ssklower 			error = EOPNOTSUPP;
55236420Ssklower 			break;
55336420Ssklower 		}
55436420Ssklower 		/* kludge - nam is really flags here */
55536420Ssklower 		error = tp_rcvoob(tpcb, so, m, outflags, (int)nam);
55636420Ssklower 		break;
55736420Ssklower 
55838841Ssklower 	case PRU_SEND:
55936420Ssklower 	case PRU_SENDOOB:
560*41924Ssklower 		if (controlp) {
561*41924Ssklower 			error = tp_snd_control(controlp, so, &m);
562*41924Ssklower 			controlp = NULL;
563*41924Ssklower 			if (error)
564*41924Ssklower 				break;
565*41924Ssklower 		}
56638841Ssklower 		if (so->so_state & SS_ISCONFIRMING) {
56738841Ssklower 			if (tpcb->tp_state == TP_CONFIRMING)
56838841Ssklower 				error = tp_confirm(tpcb);
56938841Ssklower 			if (m) {
57038841Ssklower 				if (error == 0 && m->m_len != 0)
57138841Ssklower 					error =  ENOTCONN;
57238841Ssklower 				m_freem(m);
57338841Ssklower 				m = 0;
57438841Ssklower 			}
57538841Ssklower 			break;
57638841Ssklower 		}
57737469Ssklower 		if (m == 0)
57837469Ssklower 			break;
57938841Ssklower 
58038841Ssklower 		if (req == PRU_SENDOOB) {
58138841Ssklower 			if (tpcb->tp_xpd_service == 0) {
58238841Ssklower 				error = EOPNOTSUPP;
58338841Ssklower 				break;
58438841Ssklower 			}
58538841Ssklower 			error = tp_sendoob(tpcb, so, m, outflags);
58636420Ssklower 			break;
58736420Ssklower 		}
58836420Ssklower 		/*
58936420Ssklower 		 * The protocol machine copies mbuf chains,
59036420Ssklower 		 * prepends headers, assigns seq numbers, and
59136420Ssklower 		 * puts the packets on the device.
59236420Ssklower 		 * When they are acked they are removed from the socket buf.
59336420Ssklower 		 *
59436420Ssklower 		 * sosend calls this up until sbspace goes negative.
59536420Ssklower 		 * Sbspace may be made negative by appending this mbuf chain,
59636420Ssklower 		 * possibly by a whole cluster.
59736420Ssklower 		 */
59836420Ssklower 		{
59937469Ssklower 			register struct mbuf *n = m;
60036420Ssklower 			register struct sockbuf *sb = &so->so_snd;
60137469Ssklower 			int	maxsize = tpcb->tp_l_tpdusize
60237469Ssklower 				    - tp_headersize(DT_TPDU_type, tpcb)
60337469Ssklower 				    - (tpcb->tp_use_checksum?4:0) ;
60437469Ssklower 			int totlen = n->m_pkthdr.len;
60539937Ssklower 			int	mbufcnt = 0;
60639196Ssklower 			struct mbuf *nn;
60736420Ssklower 
60837469Ssklower 			/*
60937469Ssklower 			 * Could have eotsdu and no data.(presently MUST have
61037469Ssklower 			 * an mbuf though, even if its length == 0)
61137469Ssklower 			 */
61238841Ssklower 			if (n->m_flags & M_EOR) {
61337469Ssklower 				eotsdu = 1;
61438841Ssklower 				n->m_flags &= ~M_EOR;
61538841Ssklower 			}
61636420Ssklower 			IFPERF(tpcb)
61737469Ssklower 			   PStat(tpcb, Nb_from_sess) += totlen;
61836420Ssklower 			   tpmeas(tpcb->tp_lref, TPtime_from_session, 0, 0,
61937469Ssklower 					PStat(tpcb, Nb_from_sess), totlen);
62036420Ssklower 			ENDPERF
62136420Ssklower 			IFDEBUG(D_SYSCALL)
62236420Ssklower 				printf(
62336420Ssklower 				"PRU_SEND: eot %d before sbappend 0x%x len 0x%x to sb @ 0x%x\n",
62439937Ssklower 					eotsdu, m, totlen, sb);
62536420Ssklower 				dump_mbuf(sb->sb_mb, "so_snd.sb_mb");
62636420Ssklower 				dump_mbuf(m, "m : to be added");
62736420Ssklower 			ENDDEBUG
62837469Ssklower 			/*
62937469Ssklower 			 * Pre-packetize the data in the sockbuf
63037469Ssklower 			 * according to negotiated mtu.  Do it here
63137469Ssklower 			 * where we can safely wait for mbufs.
63239196Ssklower 			 *
63339196Ssklower 			 * This presumes knowledge of sockbuf conventions.
63436420Ssklower 			 */
63539196Ssklower 			if (n = sb->sb_mb)
63639196Ssklower 				while (n->m_act)
63739196Ssklower 					n = n->m_act;
63839647Ssklower 			if ((nn = n) && n->m_pkthdr.len < maxsize) {
63939937Ssklower 				u_int space = maxsize - n->m_pkthdr.len;
64039647Ssklower 
64139647Ssklower 				do {
64239647Ssklower 					if (n->m_flags & M_EOR)
64339647Ssklower 						goto on1;
64439647Ssklower 				} while (n->m_next && (n = n->m_next));
64539937Ssklower 				if (totlen <= space) {
64639937Ssklower 					TPNagle1++;
64739196Ssklower 					n->m_next = m;
64839937Ssklower 					nn->m_pkthdr.len += totlen;
64939937Ssklower 					while (n = n->m_next)
65039937Ssklower 						sballoc(sb, n);
65139196Ssklower 					if (eotsdu)
65239196Ssklower 						nn->m_flags |= M_EOR;
65339196Ssklower 					goto on2;
65439937Ssklower 				} else {
65539937Ssklower 					/*
65639937Ssklower 					 * Can't sleep here, because when you wake up
65739937Ssklower 					 * packet you want to attach to may be gone!
65839937Ssklower 					 */
65939937Ssklower 					if (TNew && (n->m_next = m_copym(m, 0, space, M_NOWAIT))) {
66039937Ssklower 						nn->m_pkthdr.len += space;
66139937Ssklower 						TPNagle2++;
66239937Ssklower 						while (n = n->m_next)
66339937Ssklower 							sballoc(sb, n);
66439937Ssklower 						m_adj(m, space);
66539937Ssklower 					}
66639196Ssklower 				}
66739196Ssklower 			}
66839937Ssklower 	on1:	mbufcnt++;
66939196Ssklower 			for (n = m; n->m_pkthdr.len > maxsize;) {
67039937Ssklower 				nn = m_copym(n, 0, maxsize, M_WAIT);
67137469Ssklower 				sbappendrecord(sb, nn);
67237469Ssklower 				m_adj(n, maxsize);
67339937Ssklower 				mbufcnt++;
67437469Ssklower 			}
67539196Ssklower 			if (eotsdu)
67639196Ssklower 				n->m_flags |= M_EOR;
67737469Ssklower 			sbappendrecord(sb, n);
67839196Ssklower 	on2:
67939196Ssklower 			IFTRACE(D_DATA)
68039196Ssklower 				tptraceTPCB(TPPTmisc,
68139937Ssklower 				"SEND BF: maxsize totlen mbufcnt eotsdu",
68239937Ssklower 					maxsize, totlen, mbufcnt, eotsdu);
68339196Ssklower 			ENDTRACE
68436420Ssklower 			IFDEBUG(D_SYSCALL)
68539937Ssklower 				printf("PRU_SEND: eot %d after sbappend 0x%x mbufcnt 0x%x\n",
68639937Ssklower 					eotsdu, n, mbufcnt);
68736420Ssklower 				dump_mbuf(sb->sb_mb, "so_snd.sb_mb");
68836420Ssklower 			ENDDEBUG
68936420Ssklower 			error = DoEvent(T_DATA_req);
69036420Ssklower 			IFDEBUG(D_SYSCALL)
69136420Ssklower 				printf("PRU_SEND: after driver error 0x%x \n",error);
69237469Ssklower 				printf("so_snd 0x%x cc 0t%d mbcnt 0t%d\n",
69337469Ssklower 						sb, sb->sb_cc, sb->sb_mbcnt);
69437469Ssklower 				dump_mbuf(sb->sb_mb, "so_snd.sb_mb after driver");
69536420Ssklower 			ENDDEBUG
69636420Ssklower 		}
69736420Ssklower 		break;
69836420Ssklower 
69937469Ssklower 	case PRU_SOCKADDR:
70037469Ssklower 		(tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_LOCAL);
70136420Ssklower 		break;
70236420Ssklower 
70336420Ssklower 	case PRU_PEERADDR:
70438841Ssklower 		(tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN);
70536420Ssklower 		break;
70636420Ssklower 
70736420Ssklower 	case PRU_CONTROL:
70836420Ssklower 		error = EOPNOTSUPP;
70936420Ssklower 		break;
71036420Ssklower 
71136420Ssklower 	case PRU_PROTOSEND:
71236420Ssklower 	case PRU_PROTORCV:
71336420Ssklower 	case PRU_SENSE:
71436420Ssklower 	case PRU_SLOWTIMO:
71536420Ssklower 	case PRU_FASTTIMO:
71636420Ssklower 		error = EOPNOTSUPP;
71736420Ssklower 		break;
71836420Ssklower 
71936420Ssklower 	default:
72036420Ssklower #ifdef ARGO_DEBUG
72136420Ssklower 		printf("tp_usrreq UNKNOWN PRU %d\n", req);
72236420Ssklower #endif ARGO_DEBUG
72336420Ssklower 		error = EOPNOTSUPP;
72436420Ssklower 	}
72536420Ssklower 
72636420Ssklower 	IFDEBUG(D_REQUEST)
72738841Ssklower 		printf("%s, so 0x%x, tpcb 0x%x, error %d, state %d\n",
72838841Ssklower 			"returning from tp_usrreq", so, tpcb, error,
72938841Ssklower 			tpcb ? 0 : tpcb->tp_state);
73036420Ssklower 	ENDDEBUG
73136420Ssklower 	IFTRACE(D_REQUEST)
73236420Ssklower 		tptraceTPCB(TPPTusrreq, "END req so m state [", req, so, m,
73336420Ssklower 			tpcb?0:tpcb->tp_state);
73436420Ssklower 	ENDTRACE
735*41924Ssklower 	if (controlp) {
736*41924Ssklower 		m_freem(controlp);
737*41924Ssklower 		printf("control data unexpectedly retained in tp_usrreq()");
738*41924Ssklower 	}
73936420Ssklower 	splx(s);
74036420Ssklower 	return error;
74136420Ssklower }
74239196Ssklower tp_ltrace(so, uio)
74339196Ssklower struct socket *so;
74439196Ssklower struct uio *uio;
74539196Ssklower {
74639196Ssklower 	IFTRACE(D_DATA)
74739196Ssklower 		register struct tp_pcb *tpcb =  sototpcb(so);
74839196Ssklower 		if (tpcb) {
74939196Ssklower 			tptraceTPCB(TPPTmisc, "sosend so resid iovcnt", so,
75039196Ssklower 				uio->uio_resid, uio->uio_iovcnt, 0);
75139196Ssklower 		}
75239196Ssklower 	ENDTRACE
75339196Ssklower }
75437469Ssklower 
75538841Ssklower tp_confirm(tpcb)
75638841Ssklower register struct tp_pcb *tpcb;
75737469Ssklower {
75838841Ssklower 	struct tp_event E;
75938841Ssklower 	if (tpcb->tp_state == TP_CONFIRMING)
76038841Ssklower 	    return DoEvent(T_ACPT_req);
76138841Ssklower 	printf("Tp confirm called when not confirming; tpcb 0x%x, state 0x%x\n",
76238841Ssklower 		tpcb, tpcb->tp_state);
76338841Ssklower 	return 0;
76437469Ssklower }
76537469Ssklower 
76637469Ssklower /*
76737469Ssklower  * Process control data sent with sendmsg()
76837469Ssklower  */
769*41924Ssklower tp_snd_control(m, so, data)
770*41924Ssklower 	struct mbuf *m;
77137469Ssklower 	struct socket *so;
77237469Ssklower 	register struct mbuf **data;
77337469Ssklower {
77437469Ssklower 	register struct tp_control_hdr *ch;
77537469Ssklower 	int error = 0;
77637469Ssklower 
777*41924Ssklower 	if (m && m->m_len) {
778*41924Ssklower 		ch = mtod(m, struct tp_control_hdr *);
779*41924Ssklower 		m->m_len -= sizeof (*ch);
780*41924Ssklower 		m->m_data += sizeof (*ch);
78137469Ssklower 		error = tp_ctloutput(PRCO_SETOPT,
78237469Ssklower 							 so, ch->cmsg_level, ch->cmsg_type, &m);
78337469Ssklower 		if (ch->cmsg_type == TPOPT_DISC_DATA) {
78437469Ssklower 			if (data && *data) {
78537469Ssklower 				m_freem(*data);
78637469Ssklower 				*data = 0;
78737469Ssklower 			}
788*41924Ssklower 			error = tp_usrreq(so, PRU_DISCONNECT, (struct mbuf *)0,
789*41924Ssklower 								(caddr_t)0, (struct mbuf *)0);
79037469Ssklower 		}
79137469Ssklower 	}
792*41924Ssklower 	if (m)
793*41924Ssklower 		m_freem(m);
79437469Ssklower 	return error;
79537469Ssklower }
796