xref: /csrg-svn/sys/netiso/tp_usrreq.c (revision 44424)
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*44424Ssklower  *	@(#)tp_usrreq.c	7.12 (Berkeley) 06/28/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;
70*44424Ssklower struct tp_pcb *tp_listeners, *tp_intercepts;
7136420Ssklower 
7236420Ssklower #ifdef ARGO_DEBUG
7336420Ssklower /*
7436420Ssklower  * CALLED FROM:
7536420Ssklower  *  anywhere you want to debug...
7636420Ssklower  * FUNCTION and ARGUMENTS:
7736420Ssklower  *  print (str) followed by the control info in the mbufs of an mbuf chain (n)
7836420Ssklower  */
7936420Ssklower void
8036420Ssklower dump_mbuf(n, str)
8136420Ssklower 	struct mbuf *n;
8236420Ssklower 	char *str;
8336420Ssklower {
8436420Ssklower 	struct mbuf *nextrecord;
8536420Ssklower 
8636420Ssklower 	printf("dump %s\n", str);
8736420Ssklower 
8844310Ssklower 	if (n == MNULL)  {
8936420Ssklower 		printf("EMPTY:\n");
9036420Ssklower 		return;
9136420Ssklower 	}
9236420Ssklower 
9344310Ssklower 	while (n) {
9436420Ssklower 		nextrecord = n->m_act;
9536420Ssklower 		printf("RECORD:\n");
9636420Ssklower 		while (n) {
9737469Ssklower 			printf("%x : Len %x Data %x A %x Nx %x Tp %x\n",
9837469Ssklower 				n, n->m_len, n->m_data, n->m_act, n->m_next, n->m_type);
9936420Ssklower #ifdef notdef
10036420Ssklower 			{
10136420Ssklower 				register char *p = mtod(n, char *);
10236420Ssklower 				register int i;
10336420Ssklower 
10436420Ssklower 				printf("data: ");
10544310Ssklower 				for (i = 0; i < n->m_len; i++) {
10644310Ssklower 					if (i%8 == 0)
10736420Ssklower 						printf("\n");
10836420Ssklower 					printf("0x%x ", *(p+i));
10936420Ssklower 				}
11036420Ssklower 				printf("\n");
11136420Ssklower 			}
11236420Ssklower #endif notdef
11344310Ssklower 			if (n->m_next == n) {
11436420Ssklower 				printf("LOOP!\n");
11536420Ssklower 				return;
11636420Ssklower 			}
11736420Ssklower 			n = n->m_next;
11836420Ssklower 		}
11936420Ssklower 		n = nextrecord;
12036420Ssklower 	}
12136420Ssklower 	printf("\n");
12236420Ssklower }
12336420Ssklower 
12436420Ssklower #endif ARGO_DEBUG
12536420Ssklower 
12636420Ssklower /*
12736420Ssklower  * CALLED FROM:
12836420Ssklower  *  tp_usrreq(), PRU_RCVOOB
12936420Ssklower  * FUNCTION and ARGUMENTS:
13036420Ssklower  * 	Copy data from the expedited data socket buffer into
13136420Ssklower  * 	the pre-allocated mbuf m.
13236420Ssklower  * 	There is an isomorphism between XPD TPDUs and expedited data TSDUs.
13336420Ssklower  * 	XPD tpdus are limited to 16 bytes of data so they fit in one mbuf.
13436420Ssklower  * RETURN VALUE:
13536420Ssklower  *  EINVAL if debugging is on and a disaster has occurred
13636420Ssklower  *  ENOTCONN if the socket isn't connected
13736420Ssklower  *  EWOULDBLOCK if the socket is in non-blocking mode and there's no
13836420Ssklower  *		xpd data in the buffer
13936420Ssklower  *  E* whatever is returned from the fsm.
14036420Ssklower  */
14136420Ssklower tp_rcvoob(tpcb, so, m, outflags, inflags)
14236420Ssklower 	struct tp_pcb	*tpcb;
14336420Ssklower 	register struct socket	*so;
14436420Ssklower 	register struct mbuf 	*m;
14536420Ssklower 	int 		 	*outflags;
14636420Ssklower 	int 		 	inflags;
14736420Ssklower {
14836420Ssklower 	register struct mbuf *n;
14937469Ssklower 	register struct sockbuf *sb = &so->so_rcv;
15036420Ssklower 	struct tp_event E;
15136420Ssklower 	int error = 0;
15237469Ssklower 	register struct mbuf **nn;
15336420Ssklower 
15436420Ssklower 	IFDEBUG(D_XPD)
15536420Ssklower 		printf("PRU_RCVOOB, sostate 0x%x\n", so->so_state);
15636420Ssklower 	ENDDEBUG
15736420Ssklower 
15836420Ssklower 	/* if you use soreceive */
15944310Ssklower 	if (m == MNULL)
16036420Ssklower 		return ENOBUFS;
16136420Ssklower 
16236420Ssklower restart:
16336420Ssklower 	if ((((so->so_state & SS_ISCONNECTED) == 0)
16436420Ssklower 		 || (so->so_state & SS_ISDISCONNECTING) != 0) &&
16536420Ssklower 		(so->so_proto->pr_flags & PR_CONNREQUIRED)) {
16636420Ssklower 			return ENOTCONN;
16736420Ssklower 	}
16836420Ssklower 
16937469Ssklower 	/* Take the first mbuf off the chain.
17037469Ssklower 	 * Each XPD TPDU gives you a complete TSDU so the chains don't get
17137469Ssklower 	 * coalesced, but one TSDU may span several mbufs.
17237469Ssklower 	 * Nevertheless, since n should have a most 16 bytes, it
17337469Ssklower 	 * will fit into m.  (size was checked in tp_input() )
17437469Ssklower 	 */
17537469Ssklower 
17637469Ssklower 	/*
17737469Ssklower 	 * Code for excision of OOB data should be added to
17837469Ssklower 	 * uipc_socket2.c (like sbappend).
17937469Ssklower 	 */
18037469Ssklower 
18138841Ssklower 	sblock(sb);
18237469Ssklower 	for (nn = &sb->sb_mb; n = *nn; nn = &n->m_act)
18337469Ssklower 		if (n->m_type == MT_OOBDATA)
18437469Ssklower 			break;
18537469Ssklower 
18637469Ssklower 	if (n == 0) {
18744310Ssklower 		ASSERT((tpcb->tp_flags & TPF_DISC_DATA_IN) == 0);
18836420Ssklower 		IFDEBUG(D_XPD)
18936420Ssklower 			printf("RCVOOB: empty queue!\n");
19036420Ssklower 		ENDDEBUG
19138841Ssklower 		sbunlock(sb);
19236420Ssklower 		if (so->so_state & SS_NBIO) {
19336420Ssklower 			return  EWOULDBLOCK;
19436420Ssklower 		}
19536420Ssklower 		sbwait(sb);
19636420Ssklower 		goto restart;
19736420Ssklower 	}
19836420Ssklower 	m->m_len = 0;
19936420Ssklower 
20036420Ssklower 	/* Assuming at most one xpd tpdu is in the buffer at once */
20144310Ssklower 	while (n != MNULL) {
20236420Ssklower 		m->m_len += n->m_len;
20337469Ssklower 		bcopy(mtod(n, caddr_t), mtod(m, caddr_t), (unsigned)n->m_len);
20437469Ssklower 		m->m_data += n->m_len; /* so mtod() in bcopy() above gives right addr */
20536420Ssklower 		n = n->m_next;
20636420Ssklower 	}
20737469Ssklower 	m->m_data = m->m_dat;
20837469Ssklower 	m->m_flags |= M_EOR;
20936420Ssklower 
21036420Ssklower 	IFDEBUG(D_XPD)
21136420Ssklower 		printf("tp_rcvoob: xpdlen 0x%x\n", m->m_len);
21236420Ssklower 		dump_mbuf(so->so_rcv.sb_mb, "RCVOOB: Rcv socketbuf");
21336420Ssklower 		dump_mbuf(sb->sb_mb, "RCVOOB: Xrcv socketbuf");
21436420Ssklower 	ENDDEBUG
21536420Ssklower 
21644310Ssklower 	if ((inflags & MSG_PEEK) == 0) {
21737469Ssklower 		n = *nn;
21837469Ssklower 		*nn = n->m_act;
21937469Ssklower 		sb->sb_cc -= m->m_len;
22037469Ssklower 	}
22136420Ssklower 
22236420Ssklower release:
22336420Ssklower 	sbunlock(sb);
22436420Ssklower 
22536420Ssklower 	IFTRACE(D_XPD)
22636420Ssklower 		tptraceTPCB(TPPTmisc, "PRU_RCVOOB @ release sb_cc m_len",
22744310Ssklower 			tpcb->tp_Xrcv.sb_cc, m->m_len, 0, 0);
22836420Ssklower 	ENDTRACE
22936420Ssklower 	if (error == 0)
23036420Ssklower 		error = DoEvent(T_USR_Xrcvd);
23136420Ssklower 	return error;
23236420Ssklower }
23336420Ssklower 
23436420Ssklower /*
23536420Ssklower  * CALLED FROM:
23636420Ssklower  *  tp_usrreq(), PRU_SENDOOB
23736420Ssklower  * FUNCTION and ARGUMENTS:
23836420Ssklower  * 	Send what's in the mbuf chain (m) as an XPD TPDU.
23936420Ssklower  * 	The mbuf may not contain more then 16 bytes of data.
24036420Ssklower  * 	XPD TSDUs aren't segmented, so they translate into
24136420Ssklower  * 	exactly one XPD TPDU, with EOT bit set.
24236420Ssklower  * RETURN VALUE:
24336420Ssklower  *  EWOULDBLOCK if socket is in non-blocking mode and the previous
24436420Ssklower  *   xpd data haven't been acked yet.
24536420Ssklower  *  EMSGSIZE if trying to send > max-xpd bytes (16)
24636420Ssklower  *  ENOBUFS if ran out of mbufs
24736420Ssklower  */
24836420Ssklower tp_sendoob(tpcb, so, xdata, outflags)
24936420Ssklower 	struct tp_pcb	*tpcb;
25036420Ssklower 	register struct socket	*so;
25136420Ssklower 	register struct mbuf 	*xdata;
25236420Ssklower 	int 		 	*outflags; /* not used */
25336420Ssklower {
25436420Ssklower 	/*
25536420Ssklower 	 * Each mbuf chain represents a sequence # in the XPD seq space.
25636420Ssklower 	 * The first one in the queue has sequence # tp_Xuna.
25736420Ssklower 	 * When we add to the XPD queue, we stuff a zero-length
25836420Ssklower 	 * mbuf (mark) into the DATA queue, with its sequence number in m_next
25936420Ssklower 	 * to be assigned to this XPD tpdu, so data xfer can stop
26036420Ssklower 	 * when it reaches the zero-length mbuf if this XPD TPDU hasn't
26136420Ssklower 	 * yet been acknowledged.
26236420Ssklower 	 */
26336420Ssklower 	register struct sockbuf *sb = &(tpcb->tp_Xsnd);
26436420Ssklower 	register struct mbuf 	*xmark;
26536420Ssklower 	register int 			len=0;
26636420Ssklower 	struct tp_event E;
26736420Ssklower 
26836420Ssklower 	IFDEBUG(D_XPD)
26936420Ssklower 		printf("tp_sendoob:");
27044310Ssklower 		if (xdata)
27136420Ssklower 			printf("xdata len 0x%x\n", xdata->m_len);
27236420Ssklower 	ENDDEBUG
27336420Ssklower 	/* DO NOT LOCK the Xsnd buffer!!!! You can have at MOST one
27436420Ssklower 	 * socket buf locked at any time!!! (otherwise you might
27536420Ssklower 	 * sleep() in sblock() w/ a signal pending and cause the
27636420Ssklower 	 * system call to be aborted w/ a locked socketbuf, which
27736420Ssklower 	 * is a problem.  So the so_snd buffer lock
27836420Ssklower 	 * (done in sosend()) serves as the lock for Xpd.
27936420Ssklower 	 */
28038841Ssklower 	if (sb->sb_mb) { /* Anything already in eXpedited data sockbuf? */
28136420Ssklower 		if (so->so_state & SS_NBIO) {
28236420Ssklower 			return EWOULDBLOCK;
28336420Ssklower 		}
28438841Ssklower 		while (sb->sb_mb) {
28538841Ssklower 			sbunlock(&so->so_snd); /* already locked by sosend */
28638841Ssklower 			sbwait(&so->so_snd);
28738841Ssklower 			sblock(&so->so_snd);  /* sosend will unlock on return */
28838841Ssklower 		}
28936420Ssklower 	}
29036420Ssklower 
29136420Ssklower 	if (xdata == (struct mbuf *)0) {
29236420Ssklower 		/* empty xpd packet */
29337469Ssklower 		MGETHDR(xdata, M_WAIT, MT_OOBDATA);
29436420Ssklower 		if (xdata == NULL) {
29536420Ssklower 			return ENOBUFS;
29636420Ssklower 		}
29736420Ssklower 		xdata->m_len = 0;
29837469Ssklower 		xdata->m_pkthdr.len = 0;
29936420Ssklower 	}
30036420Ssklower 	IFDEBUG(D_XPD)
30136420Ssklower 		printf("tp_sendoob 1:");
30244310Ssklower 		if (xdata)
30336420Ssklower 			printf("xdata len 0x%x\n", xdata->m_len);
30436420Ssklower 	ENDDEBUG
30536420Ssklower 	xmark = xdata; /* temporary use of variable xmark */
30636420Ssklower 	while (xmark) {
30736420Ssklower 		len += xmark->m_len;
30836420Ssklower 		xmark = xmark->m_next;
30936420Ssklower 	}
31036420Ssklower 	if (len > TP_MAX_XPD_DATA) {
31136420Ssklower 		return EMSGSIZE;
31236420Ssklower 	}
31336420Ssklower 	IFDEBUG(D_XPD)
31436420Ssklower 		printf("tp_sendoob 2:");
31544310Ssklower 		if (xdata)
31636420Ssklower 			printf("xdata len 0x%x\n", len);
31736420Ssklower 	ENDDEBUG
31836420Ssklower 
31936420Ssklower 
32036420Ssklower 	IFTRACE(D_XPD)
32138841Ssklower 		tptraceTPCB(TPPTmisc, "XPD mark m_next ", xdata->m_next, 0, 0, 0);
32236420Ssklower 	ENDTRACE
32336420Ssklower 
32436420Ssklower 	sbappendrecord(sb, xdata);
32536420Ssklower 
32636420Ssklower 	IFDEBUG(D_XPD)
32736420Ssklower 		printf("tp_sendoob len 0x%x\n", len);
32836420Ssklower 		dump_mbuf(so->so_snd.sb_mb, "XPD request Regular sndbuf:");
32936420Ssklower 		dump_mbuf(tpcb->tp_Xsnd.sb_mb, "XPD request Xsndbuf:");
33036420Ssklower 	ENDDEBUG
33136420Ssklower 	return DoEvent(T_XPD_req);
33236420Ssklower }
33336420Ssklower 
33436420Ssklower /*
33536420Ssklower  * CALLED FROM:
33636420Ssklower  *  the socket routines
33736420Ssklower  * FUNCTION and ARGUMENTS:
33836420Ssklower  * 	Handles all "user requests" except the [gs]ockopts() requests.
33936420Ssklower  * 	The argument (req) is the request type (PRU*),
34036420Ssklower  * 	(m) is an mbuf chain, generally used for send and
34136420Ssklower  * 	receive type requests only.
34236420Ssklower  * 	(nam) is used for addresses usually, in particular for the bind request.
34336420Ssklower  *
34436420Ssklower  */
34536420Ssklower /*ARGSUSED*/
34636420Ssklower ProtoHook
34740773Ssklower tp_usrreq(so, req, m, nam, controlp)
34836420Ssklower 	struct socket *so;
34936420Ssklower 	u_int req;
35040773Ssklower 	struct mbuf *m, *nam, *controlp;
35136420Ssklower {
35236420Ssklower 	register struct tp_pcb *tpcb =  sototpcb(so);
35336420Ssklower 	int s = splnet();
35436420Ssklower 	int error = 0;
35537469Ssklower 	int flags, *outflags = &flags;
35636420Ssklower 	u_long eotsdu = 0;
35736420Ssklower 	struct tp_event E;
35836420Ssklower 
35936420Ssklower 	IFDEBUG(D_REQUEST)
36036420Ssklower 		printf("usrreq(0x%x,%d,0x%x,0x%x,0x%x)\n",so,req,m,nam,outflags);
36144310Ssklower 		if (so->so_error)
36236420Ssklower 			printf("WARNING!!! so->so_error is 0x%x\n", so->so_error);
36336420Ssklower 	ENDDEBUG
36436420Ssklower 	IFTRACE(D_REQUEST)
36536420Ssklower 		tptraceTPCB(TPPTusrreq, "req so m state [", req, so, m,
36636420Ssklower 			tpcb?tpcb->tp_state:0);
36736420Ssklower 	ENDTRACE
36836420Ssklower 
36936420Ssklower 	if ((u_int)tpcb == 0 && req != PRU_ATTACH) {
37036420Ssklower 		IFTRACE(D_REQUEST)
37136420Ssklower 			tptraceTPCB(TPPTusrreq, "req failed NO TPCB[", 0, 0, 0, 0);
37236420Ssklower 		ENDTRACE
37336420Ssklower 		splx(s);
37436420Ssklower 		return ENOTCONN;
37536420Ssklower 	}
37636420Ssklower 
37736420Ssklower 	switch (req) {
37836420Ssklower 
37936420Ssklower 	case PRU_ATTACH:
38036420Ssklower 		if (tpcb) {
38136420Ssklower 			error = EISCONN;
38236420Ssklower 			break;
38336420Ssklower 		}
38444310Ssklower 		if (error = tp_attach(so, so->so_proto->pr_domain->dom_family))
38536420Ssklower 			break;
38636420Ssklower 		tpcb = sototpcb(so);
38736420Ssklower 		break;
38836420Ssklower 
38936420Ssklower 	case PRU_ABORT: 	/* called from close() */
39036420Ssklower 		/* called for each incoming connect queued on the
39136420Ssklower 		 *	parent (accepting) socket
39236420Ssklower 		 */
39344310Ssklower 		if (tpcb->tp_state == TP_OPEN) {
39436420Ssklower 			E.ATTR(T_DISC_req).e_reason = E_TP_NO_SESSION;
39536420Ssklower 			error = DoEvent(T_DISC_req); /* pretend it was a close() */
39636420Ssklower 			break;
39736420Ssklower 		} /* else DROP THROUGH */
39836420Ssklower 
39936420Ssklower 	case PRU_DETACH: 	/* called from close() */
40036420Ssklower 		/* called only after disconnect was called */
401*44424Ssklower 		if (tpcb->tp_state == TP_LISTENING) {
402*44424Ssklower 			register struct tp_pcb **tt;
403*44424Ssklower 			for (tt = &tp_listeners; *tt; tt = &((*tt)->tp_nextlisten))
404*44424Ssklower 				if (*tt == tpcb)
405*44424Ssklower 					break;
406*44424Ssklower 			if (*tt)
407*44424Ssklower 				*tt = tpcb->tp_nextlisten;
408*44424Ssklower 			else {
409*44424Ssklower 				for (tt = &tp_intercepts; *tt; tt = &((*tt)->tp_nextlisten))
410*44424Ssklower 					if (*tt == tpcb)
411*44424Ssklower 						break;
412*44424Ssklower 				if (*tt)
413*44424Ssklower 					*tt = tpcb->tp_nextlisten;
414*44424Ssklower 				else
415*44424Ssklower 					printf("tp_usrreq - detach: should panic\n");
416*44424Ssklower 			}
417*44424Ssklower 		}
418*44424Ssklower 		if (tpcb->tp_next)
419*44424Ssklower 			remque(tpcb);
42036420Ssklower 		error = DoEvent(T_DETACH);
42137469Ssklower 		if (tpcb->tp_state == TP_CLOSED) {
42237469Ssklower 			free((caddr_t)tpcb, M_PCB);
42337469Ssklower 			tpcb = 0;
42437469Ssklower 		}
42536420Ssklower 		break;
42636420Ssklower 
42736420Ssklower 	case PRU_SHUTDOWN:
42836420Ssklower 		/* recv end may have been released; local credit might be zero  */
42936420Ssklower 	case PRU_DISCONNECT:
43036420Ssklower 		E.ATTR(T_DISC_req).e_reason = E_TP_NORMAL_DISC;
43136420Ssklower 		error = DoEvent(T_DISC_req);
43236420Ssklower 		break;
43336420Ssklower 
43436420Ssklower 	case PRU_BIND:
43544310Ssklower 		error =  (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, nam);
43636420Ssklower 		if (error == 0) {
43737469Ssklower 			(tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
43844310Ssklower 				tpcb->tp_lsuffix, TP_LOCAL);
43936420Ssklower 		}
44036420Ssklower 		break;
44136420Ssklower 
44236420Ssklower 	case PRU_LISTEN:
44344310Ssklower 		if (tpcb->tp_lsuffixlen == 0) {
44444310Ssklower 			if (error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL))
44536420Ssklower 				break;
44637469Ssklower 			(tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
44744310Ssklower 				tpcb->tp_lsuffix, TP_LOCAL);
44836420Ssklower 		}
449*44424Ssklower 		if (tpcb->tp_next == 0) {
450*44424Ssklower 			tpcb->tp_next = tpcb->tp_prev = tpcb;
451*44424Ssklower 			tpcb->tp_nextlisten = tp_listeners;
452*44424Ssklower 			tp_listeners = tpcb->tp_nextlisten;
453*44424Ssklower 		}
45436420Ssklower 		IFDEBUG(D_TPISO)
45544310Ssklower 			if (tpcb->tp_state != TP_CLOSED)
45636420Ssklower 				printf("LISTEN ERROR: state 0x%x\n", tpcb->tp_state);
45736420Ssklower 		ENDDEBUG
45836420Ssklower 		error = DoEvent(T_LISTEN_req);
45936420Ssklower 		break;
46036420Ssklower 
46136420Ssklower 	case PRU_CONNECT2:
46236420Ssklower 		error = EOPNOTSUPP; /* for unix domain sockets */
46336420Ssklower 		break;
46436420Ssklower 
46536420Ssklower 	case PRU_CONNECT:
46636420Ssklower 		IFTRACE(D_CONN)
46736420Ssklower 			tptraceTPCB(TPPTmisc,
46837469Ssklower 			"PRU_CONNECT: so 0x%x *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x",
46936420Ssklower 			tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen,
47036420Ssklower 				tpcb->tp_class);
47136420Ssklower 		ENDTRACE
47236420Ssklower 		IFDEBUG(D_CONN)
47336420Ssklower 			printf("PRU_CONNECT: so *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x",
47436420Ssklower 			tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen,
47536420Ssklower 				tpcb->tp_class);
47636420Ssklower 		ENDDEBUG
47744310Ssklower 		if (tpcb->tp_lsuffixlen == 0) {
47844310Ssklower 			if (error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL)) {
47936420Ssklower 				IFDEBUG(D_CONN)
48044310Ssklower 					printf("pcbbind returns error 0x%x\n", error);
48136420Ssklower 				ENDDEBUG
48236420Ssklower 				break;
48336420Ssklower 			}
48437469Ssklower 			(tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
48544310Ssklower 				tpcb->tp_lsuffix, TP_LOCAL);
48637469Ssklower 		}
48736420Ssklower 
48836420Ssklower 		IFDEBUG(D_CONN)
48936420Ssklower 			printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb);
49044310Ssklower 			dump_buf(tpcb->tp_npcb, 16);
49136420Ssklower 		ENDDEBUG
49244310Ssklower 		if (error = tp_route_to(nam, tpcb, /* channel */0))
49336420Ssklower 			break;
49436420Ssklower 		IFDEBUG(D_CONN)
49536420Ssklower 			printf(
49636420Ssklower 				"PRU_CONNECT after tpcb 0x%x so 0x%x npcb 0x%x flags 0x%x\n",
49736420Ssklower 				tpcb, so, tpcb->tp_npcb, tpcb->tp_flags);
49836420Ssklower 			printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb);
49944310Ssklower 			dump_buf(tpcb->tp_npcb, 16);
50036420Ssklower 		ENDDEBUG
50144310Ssklower 		if (tpcb->tp_fsuffixlen ==  0) {
50236420Ssklower 			/* didn't set peer extended suffix */
50337469Ssklower 			(tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_fsuffixlen,
50444310Ssklower 				tpcb->tp_fsuffix, TP_FOREIGN);
50536420Ssklower 		}
50636420Ssklower 		(void) (tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb,
50736420Ssklower 					&tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0);
50844310Ssklower 		if (tpcb->tp_state == TP_CLOSED) {
50936420Ssklower 			soisconnecting(so);
51036420Ssklower 			error = DoEvent(T_CONN_req);
51136420Ssklower 		} else {
51236420Ssklower 			(tpcb->tp_nlproto->nlp_pcbdisc)(so->so_pcb);
51336420Ssklower 			error = EISCONN;
51436420Ssklower 		}
51536420Ssklower 		IFPERF(tpcb)
51636420Ssklower 			u_int lsufx, fsufx;
51739196Ssklower 			lsufx = *(u_short *)(tpcb->tp_lsuffix);
51839196Ssklower 			fsufx = *(u_short *)(tpcb->tp_fsuffix);
51936420Ssklower 
52044310Ssklower 			tpmeas(tpcb->tp_lref,
52144310Ssklower 				TPtime_open | (tpcb->tp_xtd_format << 4),
52236420Ssklower 				&time, lsufx, fsufx, tpcb->tp_fref);
52336420Ssklower 		ENDPERF
52436420Ssklower 		break;
52536420Ssklower 
52636420Ssklower 	case PRU_ACCEPT:
52738841Ssklower 		(tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN);
52836420Ssklower 		IFDEBUG(D_REQUEST)
52938841Ssklower 			printf("ACCEPT PEERADDDR:");
53038841Ssklower 			dump_buf(mtod(nam, char *), nam->m_len);
53136420Ssklower 		ENDDEBUG
53236420Ssklower 		IFPERF(tpcb)
53336420Ssklower 			u_int lsufx, fsufx;
53439196Ssklower 			lsufx = *(u_short *)(tpcb->tp_lsuffix);
53539196Ssklower 			fsufx = *(u_short *)(tpcb->tp_fsuffix);
53636420Ssklower 
53744310Ssklower 			tpmeas(tpcb->tp_lref, TPtime_open,
53836420Ssklower 				&time, lsufx, fsufx, tpcb->tp_fref);
53936420Ssklower 		ENDPERF
54036420Ssklower 		break;
54136420Ssklower 
54236420Ssklower 	case PRU_RCVD:
54338841Ssklower 		if (so->so_state & SS_ISCONFIRMING) {
54438841Ssklower 			if (tpcb->tp_state == TP_CONFIRMING)
54538841Ssklower 				error = tp_confirm(tpcb);
54638841Ssklower 			break;
54738841Ssklower 		}
54836420Ssklower 		IFTRACE(D_DATA)
54936420Ssklower 			tptraceTPCB(TPPTmisc,
55036420Ssklower 			"RCVD BF: lcredit sent_lcdt cc hiwat \n",
55136420Ssklower 				tpcb->tp_lcredit, tpcb->tp_sent_lcdt,
55236420Ssklower 				so->so_rcv.sb_cc, so->so_rcv.sb_hiwat);
55336420Ssklower 			LOCAL_CREDIT(tpcb);
55436420Ssklower 			tptraceTPCB(TPPTmisc,
55536420Ssklower 				"PRU_RCVD AF sbspace lcredit hiwat cc",
55636420Ssklower 				sbspace(&so->so_rcv), tpcb->tp_lcredit,
55736420Ssklower 				so->so_rcv.sb_cc, so->so_rcv.sb_hiwat);
55836420Ssklower 		ENDTRACE
55937469Ssklower 		IFDEBUG(D_REQUEST)
56037469Ssklower 			printf("RCVD: cc %d space %d hiwat %d\n",
56137469Ssklower 				so->so_rcv.sb_cc, sbspace(&so->so_rcv),
56237469Ssklower 				so->so_rcv.sb_hiwat);
56337469Ssklower 		ENDDEBUG
56437469Ssklower 		if (((int)nam) & MSG_OOB)
56537469Ssklower 			error = DoEvent(T_USR_Xrcvd);
56637469Ssklower 		else
56737469Ssklower 			error = DoEvent(T_USR_rcvd);
56836420Ssklower 		break;
56936420Ssklower 
57036420Ssklower 	case PRU_RCVOOB:
57136420Ssklower 		if ((so->so_state & SS_ISCONNECTED) == 0) {
57236420Ssklower 			error = ENOTCONN;
57336420Ssklower 			break;
57436420Ssklower 		}
57544310Ssklower 		if (! tpcb->tp_xpd_service) {
57636420Ssklower 			error = EOPNOTSUPP;
57736420Ssklower 			break;
57836420Ssklower 		}
57936420Ssklower 		/* kludge - nam is really flags here */
58036420Ssklower 		error = tp_rcvoob(tpcb, so, m, outflags, (int)nam);
58136420Ssklower 		break;
58236420Ssklower 
58338841Ssklower 	case PRU_SEND:
58436420Ssklower 	case PRU_SENDOOB:
58541924Ssklower 		if (controlp) {
58641924Ssklower 			error = tp_snd_control(controlp, so, &m);
58741924Ssklower 			controlp = NULL;
58841924Ssklower 			if (error)
58941924Ssklower 				break;
59041924Ssklower 		}
59138841Ssklower 		if (so->so_state & SS_ISCONFIRMING) {
59238841Ssklower 			if (tpcb->tp_state == TP_CONFIRMING)
59338841Ssklower 				error = tp_confirm(tpcb);
59438841Ssklower 			if (m) {
59538841Ssklower 				if (error == 0 && m->m_len != 0)
59638841Ssklower 					error =  ENOTCONN;
59738841Ssklower 				m_freem(m);
59838841Ssklower 				m = 0;
59938841Ssklower 			}
60038841Ssklower 			break;
60138841Ssklower 		}
60237469Ssklower 		if (m == 0)
60337469Ssklower 			break;
60438841Ssklower 
60538841Ssklower 		if (req == PRU_SENDOOB) {
60638841Ssklower 			if (tpcb->tp_xpd_service == 0) {
60738841Ssklower 				error = EOPNOTSUPP;
60838841Ssklower 				break;
60938841Ssklower 			}
61038841Ssklower 			error = tp_sendoob(tpcb, so, m, outflags);
61136420Ssklower 			break;
61236420Ssklower 		}
61336420Ssklower 		/*
61436420Ssklower 		 * The protocol machine copies mbuf chains,
61536420Ssklower 		 * prepends headers, assigns seq numbers, and
61636420Ssklower 		 * puts the packets on the device.
61736420Ssklower 		 * When they are acked they are removed from the socket buf.
61836420Ssklower 		 *
61936420Ssklower 		 * sosend calls this up until sbspace goes negative.
62036420Ssklower 		 * Sbspace may be made negative by appending this mbuf chain,
62136420Ssklower 		 * possibly by a whole cluster.
62236420Ssklower 		 */
62336420Ssklower 		{
62437469Ssklower 			register struct mbuf *n = m;
62536420Ssklower 			register struct sockbuf *sb = &so->so_snd;
62637469Ssklower 			int	maxsize = tpcb->tp_l_tpdusize
62737469Ssklower 				    - tp_headersize(DT_TPDU_type, tpcb)
62837469Ssklower 				    - (tpcb->tp_use_checksum?4:0) ;
62937469Ssklower 			int totlen = n->m_pkthdr.len;
63039937Ssklower 			int	mbufcnt = 0;
63139196Ssklower 			struct mbuf *nn;
63236420Ssklower 
63337469Ssklower 			/*
63437469Ssklower 			 * Could have eotsdu and no data.(presently MUST have
63537469Ssklower 			 * an mbuf though, even if its length == 0)
63637469Ssklower 			 */
63738841Ssklower 			if (n->m_flags & M_EOR) {
63837469Ssklower 				eotsdu = 1;
63938841Ssklower 				n->m_flags &= ~M_EOR;
64038841Ssklower 			}
64136420Ssklower 			IFPERF(tpcb)
64237469Ssklower 			   PStat(tpcb, Nb_from_sess) += totlen;
64336420Ssklower 			   tpmeas(tpcb->tp_lref, TPtime_from_session, 0, 0,
64437469Ssklower 					PStat(tpcb, Nb_from_sess), totlen);
64536420Ssklower 			ENDPERF
64636420Ssklower 			IFDEBUG(D_SYSCALL)
64736420Ssklower 				printf(
64836420Ssklower 				"PRU_SEND: eot %d before sbappend 0x%x len 0x%x to sb @ 0x%x\n",
64939937Ssklower 					eotsdu, m, totlen, sb);
65036420Ssklower 				dump_mbuf(sb->sb_mb, "so_snd.sb_mb");
65136420Ssklower 				dump_mbuf(m, "m : to be added");
65236420Ssklower 			ENDDEBUG
65337469Ssklower 			/*
65437469Ssklower 			 * Pre-packetize the data in the sockbuf
65537469Ssklower 			 * according to negotiated mtu.  Do it here
65637469Ssklower 			 * where we can safely wait for mbufs.
65739196Ssklower 			 *
65839196Ssklower 			 * This presumes knowledge of sockbuf conventions.
65936420Ssklower 			 */
66039196Ssklower 			if (n = sb->sb_mb)
66139196Ssklower 				while (n->m_act)
66239196Ssklower 					n = n->m_act;
66339647Ssklower 			if ((nn = n) && n->m_pkthdr.len < maxsize) {
66439937Ssklower 				u_int space = maxsize - n->m_pkthdr.len;
66539647Ssklower 
66639647Ssklower 				do {
66739647Ssklower 					if (n->m_flags & M_EOR)
66839647Ssklower 						goto on1;
66939647Ssklower 				} while (n->m_next && (n = n->m_next));
67039937Ssklower 				if (totlen <= space) {
67139937Ssklower 					TPNagle1++;
67239196Ssklower 					n->m_next = m;
67339937Ssklower 					nn->m_pkthdr.len += totlen;
67439937Ssklower 					while (n = n->m_next)
67539937Ssklower 						sballoc(sb, n);
67639196Ssklower 					if (eotsdu)
67739196Ssklower 						nn->m_flags |= M_EOR;
67839196Ssklower 					goto on2;
67939937Ssklower 				} else {
68039937Ssklower 					/*
68139937Ssklower 					 * Can't sleep here, because when you wake up
68239937Ssklower 					 * packet you want to attach to may be gone!
68339937Ssklower 					 */
68439937Ssklower 					if (TNew && (n->m_next = m_copym(m, 0, space, M_NOWAIT))) {
68539937Ssklower 						nn->m_pkthdr.len += space;
68639937Ssklower 						TPNagle2++;
68739937Ssklower 						while (n = n->m_next)
68839937Ssklower 							sballoc(sb, n);
68939937Ssklower 						m_adj(m, space);
69039937Ssklower 					}
69139196Ssklower 				}
69239196Ssklower 			}
69339937Ssklower 	on1:	mbufcnt++;
69439196Ssklower 			for (n = m; n->m_pkthdr.len > maxsize;) {
69539937Ssklower 				nn = m_copym(n, 0, maxsize, M_WAIT);
69637469Ssklower 				sbappendrecord(sb, nn);
69737469Ssklower 				m_adj(n, maxsize);
69839937Ssklower 				mbufcnt++;
69937469Ssklower 			}
70039196Ssklower 			if (eotsdu)
70139196Ssklower 				n->m_flags |= M_EOR;
70237469Ssklower 			sbappendrecord(sb, n);
70339196Ssklower 	on2:
70439196Ssklower 			IFTRACE(D_DATA)
70539196Ssklower 				tptraceTPCB(TPPTmisc,
70639937Ssklower 				"SEND BF: maxsize totlen mbufcnt eotsdu",
70739937Ssklower 					maxsize, totlen, mbufcnt, eotsdu);
70839196Ssklower 			ENDTRACE
70936420Ssklower 			IFDEBUG(D_SYSCALL)
71039937Ssklower 				printf("PRU_SEND: eot %d after sbappend 0x%x mbufcnt 0x%x\n",
71139937Ssklower 					eotsdu, n, mbufcnt);
71236420Ssklower 				dump_mbuf(sb->sb_mb, "so_snd.sb_mb");
71336420Ssklower 			ENDDEBUG
71436420Ssklower 			error = DoEvent(T_DATA_req);
71536420Ssklower 			IFDEBUG(D_SYSCALL)
71636420Ssklower 				printf("PRU_SEND: after driver error 0x%x \n",error);
71737469Ssklower 				printf("so_snd 0x%x cc 0t%d mbcnt 0t%d\n",
71837469Ssklower 						sb, sb->sb_cc, sb->sb_mbcnt);
71937469Ssklower 				dump_mbuf(sb->sb_mb, "so_snd.sb_mb after driver");
72036420Ssklower 			ENDDEBUG
72136420Ssklower 		}
72236420Ssklower 		break;
72336420Ssklower 
72437469Ssklower 	case PRU_SOCKADDR:
72537469Ssklower 		(tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_LOCAL);
72636420Ssklower 		break;
72736420Ssklower 
72836420Ssklower 	case PRU_PEERADDR:
72938841Ssklower 		(tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN);
73036420Ssklower 		break;
73136420Ssklower 
73236420Ssklower 	case PRU_CONTROL:
73336420Ssklower 		error = EOPNOTSUPP;
73436420Ssklower 		break;
73536420Ssklower 
73636420Ssklower 	case PRU_PROTOSEND:
73736420Ssklower 	case PRU_PROTORCV:
73836420Ssklower 	case PRU_SENSE:
73936420Ssklower 	case PRU_SLOWTIMO:
74036420Ssklower 	case PRU_FASTTIMO:
74136420Ssklower 		error = EOPNOTSUPP;
74236420Ssklower 		break;
74336420Ssklower 
74436420Ssklower 	default:
74536420Ssklower #ifdef ARGO_DEBUG
74636420Ssklower 		printf("tp_usrreq UNKNOWN PRU %d\n", req);
74736420Ssklower #endif ARGO_DEBUG
74836420Ssklower 		error = EOPNOTSUPP;
74936420Ssklower 	}
75036420Ssklower 
75136420Ssklower 	IFDEBUG(D_REQUEST)
75238841Ssklower 		printf("%s, so 0x%x, tpcb 0x%x, error %d, state %d\n",
75338841Ssklower 			"returning from tp_usrreq", so, tpcb, error,
75438841Ssklower 			tpcb ? 0 : tpcb->tp_state);
75536420Ssklower 	ENDDEBUG
75636420Ssklower 	IFTRACE(D_REQUEST)
75736420Ssklower 		tptraceTPCB(TPPTusrreq, "END req so m state [", req, so, m,
75836420Ssklower 			tpcb?0:tpcb->tp_state);
75936420Ssklower 	ENDTRACE
76041924Ssklower 	if (controlp) {
76141924Ssklower 		m_freem(controlp);
76241924Ssklower 		printf("control data unexpectedly retained in tp_usrreq()");
76341924Ssklower 	}
76436420Ssklower 	splx(s);
76536420Ssklower 	return error;
76636420Ssklower }
76739196Ssklower tp_ltrace(so, uio)
76839196Ssklower struct socket *so;
76939196Ssklower struct uio *uio;
77039196Ssklower {
77139196Ssklower 	IFTRACE(D_DATA)
77239196Ssklower 		register struct tp_pcb *tpcb =  sototpcb(so);
77339196Ssklower 		if (tpcb) {
77439196Ssklower 			tptraceTPCB(TPPTmisc, "sosend so resid iovcnt", so,
77539196Ssklower 				uio->uio_resid, uio->uio_iovcnt, 0);
77639196Ssklower 		}
77739196Ssklower 	ENDTRACE
77839196Ssklower }
77937469Ssklower 
78038841Ssklower tp_confirm(tpcb)
78138841Ssklower register struct tp_pcb *tpcb;
78237469Ssklower {
78338841Ssklower 	struct tp_event E;
78438841Ssklower 	if (tpcb->tp_state == TP_CONFIRMING)
78538841Ssklower 	    return DoEvent(T_ACPT_req);
78638841Ssklower 	printf("Tp confirm called when not confirming; tpcb 0x%x, state 0x%x\n",
78738841Ssklower 		tpcb, tpcb->tp_state);
78838841Ssklower 	return 0;
78937469Ssklower }
79037469Ssklower 
79137469Ssklower /*
79237469Ssklower  * Process control data sent with sendmsg()
79337469Ssklower  */
79441924Ssklower tp_snd_control(m, so, data)
79541924Ssklower 	struct mbuf *m;
79637469Ssklower 	struct socket *so;
79737469Ssklower 	register struct mbuf **data;
79837469Ssklower {
79942468Ssklower 	register struct cmsghdr *ch;
80037469Ssklower 	int error = 0;
80137469Ssklower 
80241924Ssklower 	if (m && m->m_len) {
80342468Ssklower 		ch = mtod(m, struct cmsghdr *);
80441924Ssklower 		m->m_len -= sizeof (*ch);
80541924Ssklower 		m->m_data += sizeof (*ch);
80637469Ssklower 		error = tp_ctloutput(PRCO_SETOPT,
80737469Ssklower 							 so, ch->cmsg_level, ch->cmsg_type, &m);
80837469Ssklower 		if (ch->cmsg_type == TPOPT_DISC_DATA) {
80937469Ssklower 			if (data && *data) {
81037469Ssklower 				m_freem(*data);
81137469Ssklower 				*data = 0;
81237469Ssklower 			}
81341924Ssklower 			error = tp_usrreq(so, PRU_DISCONNECT, (struct mbuf *)0,
81441924Ssklower 								(caddr_t)0, (struct mbuf *)0);
81537469Ssklower 		}
81637469Ssklower 	}
81741924Ssklower 	if (m)
81841924Ssklower 		m_freem(m);
81937469Ssklower 	return error;
82037469Ssklower }
821