xref: /csrg-svn/sys/netiso/tp_usrreq.c (revision 39196)
136420Ssklower /***********************************************************
2*39196Ssklower 				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*39196Ssklower  *	@(#)tp_usrreq.c	7.5 (Berkeley) 09/22/89
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();
6836420Ssklower 
6936420Ssklower #ifdef ARGO_DEBUG
7036420Ssklower /*
7136420Ssklower  * CALLED FROM:
7236420Ssklower  *  anywhere you want to debug...
7336420Ssklower  * FUNCTION and ARGUMENTS:
7436420Ssklower  *  print (str) followed by the control info in the mbufs of an mbuf chain (n)
7536420Ssklower  */
7636420Ssklower void
7736420Ssklower dump_mbuf(n, str)
7836420Ssklower 	struct mbuf *n;
7936420Ssklower 	char *str;
8036420Ssklower {
8136420Ssklower 	struct mbuf *nextrecord;
8236420Ssklower 
8336420Ssklower 	printf("dump %s\n", str);
8436420Ssklower 
8536420Ssklower 	if( n == MNULL)  {
8636420Ssklower 		printf("EMPTY:\n");
8736420Ssklower 		return;
8836420Ssklower 	}
8936420Ssklower 
9036420Ssklower 	for(;n;) {
9136420Ssklower 		nextrecord = n->m_act;
9236420Ssklower 		printf("RECORD:\n");
9336420Ssklower 		while (n) {
9437469Ssklower 			printf("%x : Len %x Data %x A %x Nx %x Tp %x\n",
9537469Ssklower 				n, n->m_len, n->m_data, n->m_act, n->m_next, n->m_type);
9636420Ssklower #ifdef notdef
9736420Ssklower 			{
9836420Ssklower 				register char *p = mtod(n, char *);
9936420Ssklower 				register int i;
10036420Ssklower 
10136420Ssklower 				printf("data: ");
10236420Ssklower 				for(i=0; i < n->m_len; i++ ) {
10336420Ssklower 					if(i%8 == 0)
10436420Ssklower 						printf("\n");
10536420Ssklower 					printf("0x%x ", *(p+i));
10636420Ssklower 				}
10736420Ssklower 				printf("\n");
10836420Ssklower 			}
10936420Ssklower #endif notdef
11036420Ssklower 			if( n->m_next == n ) {
11136420Ssklower 				printf("LOOP!\n");
11236420Ssklower 				return;
11336420Ssklower 			}
11436420Ssklower 			n = n->m_next;
11536420Ssklower 		}
11636420Ssklower 		n = nextrecord;
11736420Ssklower 	}
11836420Ssklower 	printf("\n");
11936420Ssklower }
12036420Ssklower 
12136420Ssklower #endif ARGO_DEBUG
12236420Ssklower 
12336420Ssklower /*
12436420Ssklower  * CALLED FROM:
12536420Ssklower  *  tp_usrreq(), PRU_RCVOOB
12636420Ssklower  * FUNCTION and ARGUMENTS:
12736420Ssklower  * 	Copy data from the expedited data socket buffer into
12836420Ssklower  * 	the pre-allocated mbuf m.
12936420Ssklower  * 	There is an isomorphism between XPD TPDUs and expedited data TSDUs.
13036420Ssklower  * 	XPD tpdus are limited to 16 bytes of data so they fit in one mbuf.
13136420Ssklower  * RETURN VALUE:
13236420Ssklower  *  EINVAL if debugging is on and a disaster has occurred
13336420Ssklower  *  ENOTCONN if the socket isn't connected
13436420Ssklower  *  EWOULDBLOCK if the socket is in non-blocking mode and there's no
13536420Ssklower  *		xpd data in the buffer
13636420Ssklower  *  E* whatever is returned from the fsm.
13736420Ssklower  */
13836420Ssklower tp_rcvoob(tpcb, so, m, outflags, inflags)
13936420Ssklower 	struct tp_pcb	*tpcb;
14036420Ssklower 	register struct socket	*so;
14136420Ssklower 	register struct mbuf 	*m;
14236420Ssklower 	int 		 	*outflags;
14336420Ssklower 	int 		 	inflags;
14436420Ssklower {
14536420Ssklower 	register struct mbuf *n;
14637469Ssklower 	register struct sockbuf *sb = &so->so_rcv;
14736420Ssklower 	struct tp_event E;
14836420Ssklower 	int error = 0;
14937469Ssklower 	register struct mbuf **nn;
15036420Ssklower 
15136420Ssklower 	IFDEBUG(D_XPD)
15236420Ssklower 		printf("PRU_RCVOOB, sostate 0x%x\n", so->so_state);
15336420Ssklower 	ENDDEBUG
15436420Ssklower 
15536420Ssklower 	/* if you use soreceive */
15636420Ssklower 	if (m==MNULL)
15736420Ssklower 		return ENOBUFS;
15836420Ssklower 
15936420Ssklower restart:
16036420Ssklower 	if ((((so->so_state & SS_ISCONNECTED) == 0)
16136420Ssklower 		 || (so->so_state & SS_ISDISCONNECTING) != 0) &&
16236420Ssklower 		(so->so_proto->pr_flags & PR_CONNREQUIRED)) {
16336420Ssklower 			return ENOTCONN;
16436420Ssklower 	}
16536420Ssklower 
16637469Ssklower 	/* Take the first mbuf off the chain.
16737469Ssklower 	 * Each XPD TPDU gives you a complete TSDU so the chains don't get
16837469Ssklower 	 * coalesced, but one TSDU may span several mbufs.
16937469Ssklower 	 * Nevertheless, since n should have a most 16 bytes, it
17037469Ssklower 	 * will fit into m.  (size was checked in tp_input() )
17137469Ssklower 	 */
17237469Ssklower 
17337469Ssklower 	/*
17437469Ssklower 	 * Code for excision of OOB data should be added to
17537469Ssklower 	 * uipc_socket2.c (like sbappend).
17637469Ssklower 	 */
17737469Ssklower 
17838841Ssklower 	sblock(sb);
17937469Ssklower 	for (nn = &sb->sb_mb; n = *nn; nn = &n->m_act)
18037469Ssklower 		if (n->m_type == MT_OOBDATA)
18137469Ssklower 			break;
18237469Ssklower 
18337469Ssklower 	if (n == 0) {
18436420Ssklower 		ASSERT( (tpcb->tp_flags & TPF_DISC_DATA_IN)  == 0 );
18536420Ssklower 		IFDEBUG(D_XPD)
18636420Ssklower 			printf("RCVOOB: empty queue!\n");
18736420Ssklower 		ENDDEBUG
18838841Ssklower 		sbunlock(sb);
18936420Ssklower 		if (so->so_state & SS_NBIO) {
19036420Ssklower 			return  EWOULDBLOCK;
19136420Ssklower 		}
19236420Ssklower 		sbwait(sb);
19336420Ssklower 		goto restart;
19436420Ssklower 	}
19536420Ssklower 	m->m_len = 0;
19636420Ssklower 
19736420Ssklower 	/* Assuming at most one xpd tpdu is in the buffer at once */
19836420Ssklower 	while ( n != MNULL ) {
19936420Ssklower 		m->m_len += n->m_len;
20037469Ssklower 		bcopy(mtod(n, caddr_t), mtod(m, caddr_t), (unsigned)n->m_len);
20137469Ssklower 		m->m_data += n->m_len; /* so mtod() in bcopy() above gives right addr */
20236420Ssklower 		n = n->m_next;
20336420Ssklower 	}
20437469Ssklower 	m->m_data = m->m_dat;
20537469Ssklower 	m->m_flags |= M_EOR;
20636420Ssklower 
20736420Ssklower 	IFDEBUG(D_XPD)
20836420Ssklower 		printf("tp_rcvoob: xpdlen 0x%x\n", m->m_len);
20936420Ssklower 		dump_mbuf(so->so_rcv.sb_mb, "RCVOOB: Rcv socketbuf");
21036420Ssklower 		dump_mbuf(sb->sb_mb, "RCVOOB: Xrcv socketbuf");
21136420Ssklower 	ENDDEBUG
21236420Ssklower 
21337469Ssklower 	if( (inflags & MSG_PEEK) == 0 ) {
21437469Ssklower 		n = *nn;
21537469Ssklower 		*nn = n->m_act;
21637469Ssklower 		sb->sb_cc -= m->m_len;
21737469Ssklower 	}
21836420Ssklower 
21936420Ssklower release:
22036420Ssklower 	sbunlock(sb);
22136420Ssklower 
22236420Ssklower 	IFTRACE(D_XPD)
22336420Ssklower 		tptraceTPCB(TPPTmisc, "PRU_RCVOOB @ release sb_cc m_len",
22436420Ssklower 			tpcb->tp_Xrcv.sb_cc, m->m_len,0,0 );
22536420Ssklower 	ENDTRACE
22636420Ssklower 	if (error == 0)
22736420Ssklower 		error = DoEvent(T_USR_Xrcvd);
22836420Ssklower 	return error;
22936420Ssklower }
23036420Ssklower 
23136420Ssklower /*
23236420Ssklower  * CALLED FROM:
23336420Ssklower  *  tp_usrreq(), PRU_SENDOOB
23436420Ssklower  * FUNCTION and ARGUMENTS:
23536420Ssklower  * 	Send what's in the mbuf chain (m) as an XPD TPDU.
23636420Ssklower  * 	The mbuf may not contain more then 16 bytes of data.
23736420Ssklower  * 	XPD TSDUs aren't segmented, so they translate into
23836420Ssklower  * 	exactly one XPD TPDU, with EOT bit set.
23936420Ssklower  * RETURN VALUE:
24036420Ssklower  *  EWOULDBLOCK if socket is in non-blocking mode and the previous
24136420Ssklower  *   xpd data haven't been acked yet.
24236420Ssklower  *  EMSGSIZE if trying to send > max-xpd bytes (16)
24336420Ssklower  *  ENOBUFS if ran out of mbufs
24436420Ssklower  */
24536420Ssklower tp_sendoob(tpcb, so, xdata, outflags)
24636420Ssklower 	struct tp_pcb	*tpcb;
24736420Ssklower 	register struct socket	*so;
24836420Ssklower 	register struct mbuf 	*xdata;
24936420Ssklower 	int 		 	*outflags; /* not used */
25036420Ssklower {
25136420Ssklower 	/*
25236420Ssklower 	 * Each mbuf chain represents a sequence # in the XPD seq space.
25336420Ssklower 	 * The first one in the queue has sequence # tp_Xuna.
25436420Ssklower 	 * When we add to the XPD queue, we stuff a zero-length
25536420Ssklower 	 * mbuf (mark) into the DATA queue, with its sequence number in m_next
25636420Ssklower 	 * to be assigned to this XPD tpdu, so data xfer can stop
25736420Ssklower 	 * when it reaches the zero-length mbuf if this XPD TPDU hasn't
25836420Ssklower 	 * yet been acknowledged.
25936420Ssklower 	 */
26036420Ssklower 	register struct sockbuf *sb = &(tpcb->tp_Xsnd);
26136420Ssklower 	register struct mbuf 	*xmark;
26236420Ssklower 	register int 			len=0;
26336420Ssklower 	struct tp_event E;
26436420Ssklower 
26536420Ssklower 	IFDEBUG(D_XPD)
26636420Ssklower 		printf("tp_sendoob:");
26736420Ssklower 		if(xdata)
26836420Ssklower 			printf("xdata len 0x%x\n", xdata->m_len);
26936420Ssklower 	ENDDEBUG
27036420Ssklower 	/* DO NOT LOCK the Xsnd buffer!!!! You can have at MOST one
27136420Ssklower 	 * socket buf locked at any time!!! (otherwise you might
27236420Ssklower 	 * sleep() in sblock() w/ a signal pending and cause the
27336420Ssklower 	 * system call to be aborted w/ a locked socketbuf, which
27436420Ssklower 	 * is a problem.  So the so_snd buffer lock
27536420Ssklower 	 * (done in sosend()) serves as the lock for Xpd.
27636420Ssklower 	 */
27738841Ssklower 	if (sb->sb_mb) { /* Anything already in eXpedited data sockbuf? */
27836420Ssklower 		if (so->so_state & SS_NBIO) {
27936420Ssklower 			return EWOULDBLOCK;
28036420Ssklower 		}
28138841Ssklower 		while (sb->sb_mb) {
28238841Ssklower 			sbunlock(&so->so_snd); /* already locked by sosend */
28338841Ssklower 			sbwait(&so->so_snd);
28438841Ssklower 			sblock(&so->so_snd);  /* sosend will unlock on return */
28538841Ssklower 		}
28636420Ssklower 	}
28736420Ssklower 
28836420Ssklower 	if (xdata == (struct mbuf *)0) {
28936420Ssklower 		/* empty xpd packet */
29037469Ssklower 		MGETHDR(xdata, M_WAIT, MT_OOBDATA);
29136420Ssklower 		if (xdata == NULL) {
29236420Ssklower 			return ENOBUFS;
29336420Ssklower 		}
29436420Ssklower 		xdata->m_len = 0;
29537469Ssklower 		xdata->m_pkthdr.len = 0;
29636420Ssklower 	}
29736420Ssklower 	IFDEBUG(D_XPD)
29836420Ssklower 		printf("tp_sendoob 1:");
29936420Ssklower 		if(xdata)
30036420Ssklower 			printf("xdata len 0x%x\n", xdata->m_len);
30136420Ssklower 	ENDDEBUG
30236420Ssklower 	xmark = xdata; /* temporary use of variable xmark */
30336420Ssklower 	while (xmark) {
30436420Ssklower 		len += xmark->m_len;
30536420Ssklower 		xmark = xmark->m_next;
30636420Ssklower 	}
30736420Ssklower 	if (len > TP_MAX_XPD_DATA) {
30836420Ssklower 		return EMSGSIZE;
30936420Ssklower 	}
31036420Ssklower 	IFDEBUG(D_XPD)
31136420Ssklower 		printf("tp_sendoob 2:");
31236420Ssklower 		if(xdata)
31336420Ssklower 			printf("xdata len 0x%x\n", len);
31436420Ssklower 	ENDDEBUG
31536420Ssklower 
31636420Ssklower 
31736420Ssklower 	IFTRACE(D_XPD)
31838841Ssklower 		tptraceTPCB(TPPTmisc, "XPD mark m_next ", xdata->m_next, 0, 0, 0);
31936420Ssklower 	ENDTRACE
32036420Ssklower 
32136420Ssklower 	sbappendrecord(sb, xdata);
32236420Ssklower 
32336420Ssklower 	IFDEBUG(D_XPD)
32436420Ssklower 		printf("tp_sendoob len 0x%x\n", len);
32536420Ssklower 		dump_mbuf(so->so_snd.sb_mb, "XPD request Regular sndbuf:");
32636420Ssklower 		dump_mbuf(tpcb->tp_Xsnd.sb_mb, "XPD request Xsndbuf:");
32736420Ssklower 	ENDDEBUG
32836420Ssklower 	return DoEvent(T_XPD_req);
32936420Ssklower }
33036420Ssklower 
33136420Ssklower /*
33236420Ssklower  * CALLED FROM:
33336420Ssklower  *  the socket routines
33436420Ssklower  * FUNCTION and ARGUMENTS:
33536420Ssklower  * 	Handles all "user requests" except the [gs]ockopts() requests.
33636420Ssklower  * 	The argument (req) is the request type (PRU*),
33736420Ssklower  * 	(m) is an mbuf chain, generally used for send and
33836420Ssklower  * 	receive type requests only.
33936420Ssklower  * 	(nam) is used for addresses usually, in particular for the bind request.
34036420Ssklower  *
34136420Ssklower  */
34236420Ssklower /*ARGSUSED*/
34336420Ssklower ProtoHook
34437469Ssklower tp_usrreq(so, req, m, nam, rightsp, controlp)
34536420Ssklower 	struct socket *so;
34636420Ssklower 	u_int req;
34737469Ssklower 	struct mbuf *m, *nam, *rightsp, *controlp;
34836420Ssklower {
34936420Ssklower 	register struct tp_pcb *tpcb =  sototpcb(so);
35036420Ssklower 	int s = splnet();
35136420Ssklower 	int error = 0;
35237469Ssklower 	int flags, *outflags = &flags;
35336420Ssklower 	u_long eotsdu = 0;
35436420Ssklower 	struct tp_event E;
35536420Ssklower 
35636420Ssklower 	IFDEBUG(D_REQUEST)
35736420Ssklower 		printf("usrreq(0x%x,%d,0x%x,0x%x,0x%x)\n",so,req,m,nam,outflags);
35836420Ssklower 		if(so->so_error)
35936420Ssklower 			printf("WARNING!!! so->so_error is 0x%x\n", so->so_error);
36036420Ssklower 	ENDDEBUG
36136420Ssklower 	IFTRACE(D_REQUEST)
36236420Ssklower 		tptraceTPCB(TPPTusrreq, "req so m state [", req, so, m,
36336420Ssklower 			tpcb?tpcb->tp_state:0);
36436420Ssklower 	ENDTRACE
36536420Ssklower 
36636420Ssklower 	if ((u_int)tpcb == 0 && req != PRU_ATTACH) {
36736420Ssklower 		IFTRACE(D_REQUEST)
36836420Ssklower 			tptraceTPCB(TPPTusrreq, "req failed NO TPCB[", 0, 0, 0, 0);
36936420Ssklower 		ENDTRACE
37036420Ssklower 		splx(s);
37136420Ssklower 		return ENOTCONN;
37236420Ssklower 	}
37336420Ssklower 
37436420Ssklower 	switch (req) {
37536420Ssklower 
37636420Ssklower 	case PRU_ATTACH:
37736420Ssklower 		if (tpcb) {
37836420Ssklower 			error = EISCONN;
37936420Ssklower 			break;
38036420Ssklower 		}
38136420Ssklower 		if( error = tp_attach(so, so->so_proto->pr_domain->dom_family ) )
38236420Ssklower 			break;
38336420Ssklower 		tpcb = sototpcb(so);
38436420Ssklower 		break;
38536420Ssklower 
38636420Ssklower 	case PRU_ABORT: 	/* called from close() */
38736420Ssklower 		/* called for each incoming connect queued on the
38836420Ssklower 		 *	parent (accepting) socket
38936420Ssklower 		 */
39036420Ssklower 		if( tpcb->tp_state == TP_OPEN ) {
39136420Ssklower 			E.ATTR(T_DISC_req).e_reason = E_TP_NO_SESSION;
39236420Ssklower 			error = DoEvent(T_DISC_req); /* pretend it was a close() */
39336420Ssklower 			break;
39436420Ssklower 		} /* else DROP THROUGH */
39536420Ssklower 
39636420Ssklower 	case PRU_DETACH: 	/* called from close() */
39736420Ssklower 		/* called only after disconnect was called */
39836420Ssklower 		error = DoEvent(T_DETACH);
39937469Ssklower 		if (tpcb->tp_state == TP_CLOSED) {
40037469Ssklower 			free((caddr_t)tpcb, M_PCB);
40137469Ssklower 			tpcb = 0;
40237469Ssklower 		}
40336420Ssklower 		break;
40436420Ssklower 
40536420Ssklower 	case PRU_SHUTDOWN:
40636420Ssklower 		/* recv end may have been released; local credit might be zero  */
40736420Ssklower 	case PRU_DISCONNECT:
40836420Ssklower 		E.ATTR(T_DISC_req).e_reason = E_TP_NORMAL_DISC;
40936420Ssklower 		error = DoEvent(T_DISC_req);
41036420Ssklower 		break;
41136420Ssklower 
41236420Ssklower 	case PRU_BIND:
41336420Ssklower 		error =  (tpcb->tp_nlproto->nlp_pcbbind)( so->so_pcb, nam );
41436420Ssklower 		if (error == 0) {
41537469Ssklower 			(tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
41637469Ssklower 				tpcb->tp_lsuffix, TP_LOCAL );
41736420Ssklower 		}
41836420Ssklower 		break;
41936420Ssklower 
42036420Ssklower 	case PRU_LISTEN:
42138841Ssklower 		if( tpcb->tp_lsuffixlen ==  0) {
42236420Ssklower 			if( error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL) )
42336420Ssklower 				break;
42437469Ssklower 			(tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
42537469Ssklower 				tpcb->tp_lsuffix, TP_LOCAL );
42636420Ssklower 		}
42736420Ssklower 		IFDEBUG(D_TPISO)
42836420Ssklower 			if(tpcb->tp_state != TP_CLOSED)
42936420Ssklower 				printf("LISTEN ERROR: state 0x%x\n", tpcb->tp_state);
43036420Ssklower 		ENDDEBUG
43136420Ssklower 		error = DoEvent(T_LISTEN_req);
43236420Ssklower 		break;
43336420Ssklower 
43436420Ssklower 	case PRU_CONNECT2:
43536420Ssklower 		error = EOPNOTSUPP; /* for unix domain sockets */
43636420Ssklower 		break;
43736420Ssklower 
43836420Ssklower 	case PRU_CONNECT:
43936420Ssklower 		IFTRACE(D_CONN)
44036420Ssklower 			tptraceTPCB(TPPTmisc,
44137469Ssklower 			"PRU_CONNECT: so 0x%x *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x",
44236420Ssklower 			tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen,
44336420Ssklower 				tpcb->tp_class);
44436420Ssklower 		ENDTRACE
44536420Ssklower 		IFDEBUG(D_CONN)
44636420Ssklower 			printf("PRU_CONNECT: so *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x",
44736420Ssklower 			tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen,
44836420Ssklower 				tpcb->tp_class);
44936420Ssklower 		ENDDEBUG
45038841Ssklower 		if( tpcb->tp_lsuffixlen ==  0) {
45136420Ssklower 			if( error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL) ) {
45236420Ssklower 				IFDEBUG(D_CONN)
45336420Ssklower 					printf("pcbbind returns error 0x%x\n", error );
45436420Ssklower 				ENDDEBUG
45536420Ssklower 				break;
45636420Ssklower 			}
45737469Ssklower 			(tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
45837469Ssklower 				tpcb->tp_lsuffix, TP_LOCAL );
45937469Ssklower 		}
46036420Ssklower 
46136420Ssklower 		IFDEBUG(D_CONN)
46236420Ssklower 			printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb);
46336420Ssklower 			dump_buf( tpcb->tp_npcb, 16);
46436420Ssklower 		ENDDEBUG
46536420Ssklower 		if( error = tp_route_to( nam, tpcb, /* channel */0) )
46636420Ssklower 			break;
46736420Ssklower 		IFDEBUG(D_CONN)
46836420Ssklower 			printf(
46936420Ssklower 				"PRU_CONNECT after tpcb 0x%x so 0x%x npcb 0x%x flags 0x%x\n",
47036420Ssklower 				tpcb, so, tpcb->tp_npcb, tpcb->tp_flags);
47136420Ssklower 			printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb);
47236420Ssklower 			dump_buf( tpcb->tp_npcb, 16);
47336420Ssklower 		ENDDEBUG
47437469Ssklower 		if( tpcb->tp_fsuffixlen ==  0) {
47536420Ssklower 			/* didn't set peer extended suffix */
47637469Ssklower 			(tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_fsuffixlen,
47737469Ssklower 				tpcb->tp_fsuffix, TP_FOREIGN );
47836420Ssklower 		}
47936420Ssklower 		(void) (tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb,
48036420Ssklower 					&tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0);
48136420Ssklower 		if( tpcb->tp_state == TP_CLOSED) {
48236420Ssklower 			soisconnecting(so);
48336420Ssklower 			error = DoEvent(T_CONN_req);
48436420Ssklower 		} else {
48536420Ssklower 			(tpcb->tp_nlproto->nlp_pcbdisc)(so->so_pcb);
48636420Ssklower 			error = EISCONN;
48736420Ssklower 		}
48836420Ssklower 		IFPERF(tpcb)
48936420Ssklower 			u_int lsufx, fsufx;
490*39196Ssklower 			lsufx = *(u_short *)(tpcb->tp_lsuffix);
491*39196Ssklower 			fsufx = *(u_short *)(tpcb->tp_fsuffix);
49236420Ssklower 
49336420Ssklower 			tpmeas( tpcb->tp_lref,
49436420Ssklower 				TPtime_open | (tpcb->tp_xtd_format <<4 ),
49536420Ssklower 				&time, lsufx, fsufx, tpcb->tp_fref);
49636420Ssklower 		ENDPERF
49736420Ssklower 		break;
49836420Ssklower 
49936420Ssklower 	case PRU_ACCEPT:
50038841Ssklower 		(tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN);
50136420Ssklower 		IFDEBUG(D_REQUEST)
50238841Ssklower 			printf("ACCEPT PEERADDDR:");
50338841Ssklower 			dump_buf(mtod(nam, char *), nam->m_len);
50436420Ssklower 		ENDDEBUG
50536420Ssklower 		IFPERF(tpcb)
50636420Ssklower 			u_int lsufx, fsufx;
507*39196Ssklower 			lsufx = *(u_short *)(tpcb->tp_lsuffix);
508*39196Ssklower 			fsufx = *(u_short *)(tpcb->tp_fsuffix);
50936420Ssklower 
51036420Ssklower 			tpmeas( tpcb->tp_lref, TPtime_open,
51136420Ssklower 				&time, lsufx, fsufx, tpcb->tp_fref);
51236420Ssklower 		ENDPERF
51336420Ssklower 		break;
51436420Ssklower 
51536420Ssklower 	case PRU_RCVD:
51638841Ssklower 		if (so->so_state & SS_ISCONFIRMING) {
51738841Ssklower 			if (tpcb->tp_state == TP_CONFIRMING)
51838841Ssklower 				error = tp_confirm(tpcb);
51938841Ssklower 			break;
52038841Ssklower 		}
52136420Ssklower 		IFTRACE(D_DATA)
52236420Ssklower 			tptraceTPCB(TPPTmisc,
52336420Ssklower 			"RCVD BF: lcredit sent_lcdt cc hiwat \n",
52436420Ssklower 				tpcb->tp_lcredit, tpcb->tp_sent_lcdt,
52536420Ssklower 				so->so_rcv.sb_cc, so->so_rcv.sb_hiwat);
52636420Ssklower 			LOCAL_CREDIT(tpcb);
52736420Ssklower 			tptraceTPCB(TPPTmisc,
52836420Ssklower 				"PRU_RCVD AF sbspace lcredit hiwat cc",
52936420Ssklower 				sbspace(&so->so_rcv), tpcb->tp_lcredit,
53036420Ssklower 				so->so_rcv.sb_cc, so->so_rcv.sb_hiwat);
53136420Ssklower 		ENDTRACE
53237469Ssklower 		IFDEBUG(D_REQUEST)
53337469Ssklower 			printf("RCVD: cc %d space %d hiwat %d\n",
53437469Ssklower 				so->so_rcv.sb_cc, sbspace(&so->so_rcv),
53537469Ssklower 				so->so_rcv.sb_hiwat);
53637469Ssklower 		ENDDEBUG
53737469Ssklower 		if (((int)nam) & MSG_OOB)
53837469Ssklower 			error = DoEvent(T_USR_Xrcvd);
53937469Ssklower 		else
54037469Ssklower 			error = DoEvent(T_USR_rcvd);
54136420Ssklower 		break;
54236420Ssklower 
54336420Ssklower 	case PRU_RCVOOB:
54436420Ssklower 		if ((so->so_state & SS_ISCONNECTED) == 0) {
54536420Ssklower 			error = ENOTCONN;
54636420Ssklower 			break;
54736420Ssklower 		}
54836420Ssklower 		if( ! tpcb->tp_xpd_service ) {
54936420Ssklower 			error = EOPNOTSUPP;
55036420Ssklower 			break;
55136420Ssklower 		}
55236420Ssklower 		/* kludge - nam is really flags here */
55336420Ssklower 		error = tp_rcvoob(tpcb, so, m, outflags, (int)nam);
55436420Ssklower 		break;
55536420Ssklower 
55638841Ssklower 	case PRU_SEND:
55736420Ssklower 	case PRU_SENDOOB:
55837469Ssklower 		if (controlp && (error = tp_snd_control(controlp, so, &m)))
55936420Ssklower 			break;
56038841Ssklower 		if (so->so_state & SS_ISCONFIRMING) {
56138841Ssklower 			if (tpcb->tp_state == TP_CONFIRMING)
56238841Ssklower 				error = tp_confirm(tpcb);
56338841Ssklower 			if (m) {
56438841Ssklower 				if (error == 0 && m->m_len != 0)
56538841Ssklower 					error =  ENOTCONN;
56638841Ssklower 				m_freem(m);
56738841Ssklower 				m = 0;
56838841Ssklower 			}
56938841Ssklower 			break;
57038841Ssklower 		}
57137469Ssklower 		if (m == 0)
57237469Ssklower 			break;
57338841Ssklower 
57438841Ssklower 		if (req == PRU_SENDOOB) {
57538841Ssklower 			if (tpcb->tp_xpd_service == 0) {
57638841Ssklower 				error = EOPNOTSUPP;
57738841Ssklower 				break;
57838841Ssklower 			}
57938841Ssklower 			error = tp_sendoob(tpcb, so, m, outflags);
58036420Ssklower 			break;
58136420Ssklower 		}
58236420Ssklower 		/*
58336420Ssklower 		 * The protocol machine copies mbuf chains,
58436420Ssklower 		 * prepends headers, assigns seq numbers, and
58536420Ssklower 		 * puts the packets on the device.
58636420Ssklower 		 * When they are acked they are removed from the socket buf.
58736420Ssklower 		 *
58836420Ssklower 		 * sosend calls this up until sbspace goes negative.
58936420Ssklower 		 * Sbspace may be made negative by appending this mbuf chain,
59036420Ssklower 		 * possibly by a whole cluster.
59136420Ssklower 		 */
59236420Ssklower 		{
59337469Ssklower 			register struct mbuf *n = m;
59436420Ssklower 			register int len=0;
59536420Ssklower 			register struct sockbuf *sb = &so->so_snd;
59637469Ssklower 			int	maxsize = tpcb->tp_l_tpdusize
59737469Ssklower 				    - tp_headersize(DT_TPDU_type, tpcb)
59837469Ssklower 				    - (tpcb->tp_use_checksum?4:0) ;
59937469Ssklower 			int totlen = n->m_pkthdr.len;
600*39196Ssklower 			struct mbuf *nn;
60136420Ssklower 
60237469Ssklower 			/*
60337469Ssklower 			 * Could have eotsdu and no data.(presently MUST have
60437469Ssklower 			 * an mbuf though, even if its length == 0)
60537469Ssklower 			 */
60638841Ssklower 			if (n->m_flags & M_EOR) {
60737469Ssklower 				eotsdu = 1;
60838841Ssklower 				n->m_flags &= ~M_EOR;
60938841Ssklower 			}
61036420Ssklower 			IFPERF(tpcb)
61137469Ssklower 			   PStat(tpcb, Nb_from_sess) += totlen;
61236420Ssklower 			   tpmeas(tpcb->tp_lref, TPtime_from_session, 0, 0,
61337469Ssklower 					PStat(tpcb, Nb_from_sess), totlen);
61436420Ssklower 			ENDPERF
61536420Ssklower 			IFDEBUG(D_SYSCALL)
61636420Ssklower 				printf(
61736420Ssklower 				"PRU_SEND: eot %d before sbappend 0x%x len 0x%x to sb @ 0x%x\n",
61837469Ssklower 					eotsdu, m,len, sb);
61936420Ssklower 				dump_mbuf(sb->sb_mb, "so_snd.sb_mb");
62036420Ssklower 				dump_mbuf(m, "m : to be added");
62136420Ssklower 			ENDDEBUG
62237469Ssklower 			/*
62337469Ssklower 			 * Pre-packetize the data in the sockbuf
62437469Ssklower 			 * according to negotiated mtu.  Do it here
62537469Ssklower 			 * where we can safely wait for mbufs.
626*39196Ssklower 			 *
627*39196Ssklower 			 * This presumes knowledge of sockbuf conventions.
62836420Ssklower 			 */
629*39196Ssklower 			len = 0;
630*39196Ssklower 			if (n = sb->sb_mb)
631*39196Ssklower 				while (n->m_act)
632*39196Ssklower 					n = n->m_act;
633*39196Ssklower 			if (n && n->m_pkthdr.len < maxsize) {
634*39196Ssklower 				int space = maxsize - n->m_pkthdr.len;
635*39196Ssklower 				int eorseen = 0;
636*39196Ssklower 				nn = n;
637*39196Ssklower 				for (;; n = n->m_next) {
638*39196Ssklower 				 eorseen |= n->m_flags & M_EOR;
639*39196Ssklower 					if (n->m_next == 0)
640*39196Ssklower 						break;
641*39196Ssklower 				}
642*39196Ssklower 				if (eorseen)
643*39196Ssklower 					goto on1;
644*39196Ssklower 				if (m->m_pkthdr.len <= space) {
645*39196Ssklower 					n->m_next = m;
646*39196Ssklower 					if (eotsdu)
647*39196Ssklower 						nn->m_flags |= M_EOR;
648*39196Ssklower 					goto on2;
649*39196Ssklower 				} else {
650*39196Ssklower 					nn->m_next = m_copym(n, 0, space, M_WAIT);
651*39196Ssklower 					m_adj(n, space);
652*39196Ssklower 				}
653*39196Ssklower 			}
654*39196Ssklower 	on1:	len++;
655*39196Ssklower 			for (n = m; n->m_pkthdr.len > maxsize;) {
656*39196Ssklower 				nn = m_copym(n, 0, len, M_WAIT);
65737469Ssklower 				sbappendrecord(sb, nn);
65837469Ssklower 				m_adj(n, maxsize);
659*39196Ssklower 				len++;
66037469Ssklower 			}
661*39196Ssklower 			if (eotsdu)
662*39196Ssklower 				n->m_flags |= M_EOR;
66337469Ssklower 			sbappendrecord(sb, n);
664*39196Ssklower 	on2:
665*39196Ssklower 			IFTRACE(D_DATA)
666*39196Ssklower 				tptraceTPCB(TPPTmisc,
667*39196Ssklower 				"SEND BF: maxsize totlen frags eotsdu",
668*39196Ssklower 					maxsize, totlen, len, eotsdu);
669*39196Ssklower 			ENDTRACE
67036420Ssklower 			IFDEBUG(D_SYSCALL)
67136420Ssklower 				printf("PRU_SEND: eot %d after sbappend 0x%x len 0x%x\n",
67237469Ssklower 					eotsdu, n, len);
67336420Ssklower 				dump_mbuf(sb->sb_mb, "so_snd.sb_mb");
67436420Ssklower 			ENDDEBUG
67536420Ssklower 			error = DoEvent(T_DATA_req);
67636420Ssklower 			IFDEBUG(D_SYSCALL)
67736420Ssklower 				printf("PRU_SEND: after driver error 0x%x \n",error);
67837469Ssklower 				printf("so_snd 0x%x cc 0t%d mbcnt 0t%d\n",
67937469Ssklower 						sb, sb->sb_cc, sb->sb_mbcnt);
68037469Ssklower 				dump_mbuf(sb->sb_mb, "so_snd.sb_mb after driver");
68136420Ssklower 			ENDDEBUG
68236420Ssklower 		}
68336420Ssklower 		break;
68436420Ssklower 
68537469Ssklower 	case PRU_SOCKADDR:
68637469Ssklower 		(tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_LOCAL);
68736420Ssklower 		break;
68836420Ssklower 
68936420Ssklower 	case PRU_PEERADDR:
69038841Ssklower 		(tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN);
69136420Ssklower 		break;
69236420Ssklower 
69336420Ssklower 	case PRU_CONTROL:
69436420Ssklower 		error = EOPNOTSUPP;
69536420Ssklower 		break;
69636420Ssklower 
69736420Ssklower 	case PRU_PROTOSEND:
69836420Ssklower 	case PRU_PROTORCV:
69936420Ssklower 	case PRU_SENSE:
70036420Ssklower 	case PRU_SLOWTIMO:
70136420Ssklower 	case PRU_FASTTIMO:
70236420Ssklower 		error = EOPNOTSUPP;
70336420Ssklower 		break;
70436420Ssklower 
70536420Ssklower 	default:
70636420Ssklower #ifdef ARGO_DEBUG
70736420Ssklower 		printf("tp_usrreq UNKNOWN PRU %d\n", req);
70836420Ssklower #endif ARGO_DEBUG
70936420Ssklower 		error = EOPNOTSUPP;
71036420Ssklower 	}
71136420Ssklower 
71236420Ssklower 	IFDEBUG(D_REQUEST)
71338841Ssklower 		printf("%s, so 0x%x, tpcb 0x%x, error %d, state %d\n",
71438841Ssklower 			"returning from tp_usrreq", so, tpcb, error,
71538841Ssklower 			tpcb ? 0 : tpcb->tp_state);
71636420Ssklower 	ENDDEBUG
71736420Ssklower 	IFTRACE(D_REQUEST)
71836420Ssklower 		tptraceTPCB(TPPTusrreq, "END req so m state [", req, so, m,
71936420Ssklower 			tpcb?0:tpcb->tp_state);
72036420Ssklower 	ENDTRACE
72136420Ssklower 	splx(s);
72236420Ssklower 	return error;
72336420Ssklower }
724*39196Ssklower tp_ltrace(so, uio)
725*39196Ssklower struct socket *so;
726*39196Ssklower struct uio *uio;
727*39196Ssklower {
728*39196Ssklower 	IFTRACE(D_DATA)
729*39196Ssklower 		register struct tp_pcb *tpcb =  sototpcb(so);
730*39196Ssklower 		if (tpcb) {
731*39196Ssklower 			tptraceTPCB(TPPTmisc, "sosend so resid iovcnt", so,
732*39196Ssklower 				uio->uio_resid, uio->uio_iovcnt, 0);
733*39196Ssklower 		}
734*39196Ssklower 	ENDTRACE
735*39196Ssklower }
73637469Ssklower 
73738841Ssklower tp_confirm(tpcb)
73838841Ssklower register struct tp_pcb *tpcb;
73937469Ssklower {
74038841Ssklower 	struct tp_event E;
74138841Ssklower 	if (tpcb->tp_state == TP_CONFIRMING)
74238841Ssklower 	    return DoEvent(T_ACPT_req);
74338841Ssklower 	printf("Tp confirm called when not confirming; tpcb 0x%x, state 0x%x\n",
74438841Ssklower 		tpcb, tpcb->tp_state);
74538841Ssklower 	return 0;
74637469Ssklower }
74737469Ssklower 
74837469Ssklower /*
74937469Ssklower  * Process control data sent with sendmsg()
75037469Ssklower  */
75137469Ssklower tp_snd_control(m0, so, data)
75237469Ssklower 	register struct mbuf *m0;
75337469Ssklower 	struct socket *so;
75437469Ssklower 	register struct mbuf **data;
75537469Ssklower {
75637469Ssklower 	register struct tp_control_hdr *ch;
75737469Ssklower 	struct mbuf *m;
75837469Ssklower 	int error = 0;
75937469Ssklower 
76037469Ssklower 	if (m0 && m0->m_len) {
76137469Ssklower 		ch = mtod(m0, struct tp_control_hdr *);
76237469Ssklower 		m0->m_len -= sizeof (*ch);
76337469Ssklower 		m0->m_data += sizeof (*ch);
76437469Ssklower 		m = m_copym(m0, 0, M_COPYALL, M_WAIT);
76537469Ssklower 		error = tp_ctloutput(PRCO_SETOPT,
76637469Ssklower 							 so, ch->cmsg_level, ch->cmsg_type, &m);
76737469Ssklower 		if (m)
76837469Ssklower 			m_freem(m);
76937469Ssklower 		if (ch->cmsg_type == TPOPT_DISC_DATA) {
77037469Ssklower 			if (data && *data) {
77137469Ssklower 				m_freem(*data);
77237469Ssklower 				*data = 0;
77337469Ssklower 			}
77437469Ssklower 			m0 = 0;
77537469Ssklower 			error = tp_usrreq(so, PRU_DISCONNECT, m0, (caddr_t)0, m0, m0);
77637469Ssklower 		}
77737469Ssklower 	}
77837469Ssklower 	return error;
77937469Ssklower }
780