xref: /csrg-svn/sys/netiso/tp_usrreq.c (revision 50236)
149268Sbostic /*-
249268Sbostic  * Copyright (c) 1991 The Regents of the University of California.
349268Sbostic  * All rights reserved.
449268Sbostic  *
549268Sbostic  * %sccs.include.redist.c%
649268Sbostic  *
7*50236Ssklower  *	@(#)tp_usrreq.c	7.17 (Berkeley) 06/27/91
849268Sbostic  */
949268Sbostic 
1036420Ssklower /***********************************************************
1139196Ssklower 				Copyright IBM Corporation 1987
1236420Ssklower 
1336420Ssklower                       All Rights Reserved
1436420Ssklower 
1536420Ssklower Permission to use, copy, modify, and distribute this software and its
1636420Ssklower documentation for any purpose and without fee is hereby granted,
1736420Ssklower provided that the above copyright notice appear in all copies and that
1836420Ssklower both that copyright notice and this permission notice appear in
1936420Ssklower supporting documentation, and that the name of IBM not be
2036420Ssklower used in advertising or publicity pertaining to distribution of the
2136420Ssklower software without specific, written prior permission.
2236420Ssklower 
2336420Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
2436420Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
2536420Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
2636420Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
2736420Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2836420Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2936420Ssklower SOFTWARE.
3036420Ssklower 
3136420Ssklower ******************************************************************/
3236420Ssklower 
3336420Ssklower /*
3436420Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
3536420Ssklower  */
3636420Ssklower /*
3736420Ssklower  * ARGO TP
3836420Ssklower  *
3936420Ssklower  * $Header: tp_usrreq.c,v 5.4 88/11/18 17:29:18 nhall Exp $
4036420Ssklower  * $Source: /usr/argo/sys/netiso/RCS/tp_usrreq.c,v $
4136420Ssklower  *
4236420Ssklower  * tp_usrreq(), the fellow that gets called from most of the socket code.
4336420Ssklower  * Pretty straighforward.
4436420Ssklower  * THe only really awful stuff here is the OOB processing, which is done
4536420Ssklower  * wholly here.
4636420Ssklower  * tp_rcvoob() and tp_sendoob() are contained here and called by tp_usrreq().
4736420Ssklower  */
4836420Ssklower 
4936420Ssklower #include "param.h"
5036420Ssklower #include "systm.h"
5136420Ssklower #include "mbuf.h"
5236420Ssklower #include "socket.h"
5336420Ssklower #include "socketvar.h"
5436420Ssklower #include "domain.h"
5536420Ssklower #include "protosw.h"
5636420Ssklower #include "errno.h"
57*50236Ssklower #include "time.h"
5836420Ssklower 
5937469Ssklower #include "tp_param.h"
6037469Ssklower #include "tp_timer.h"
6137469Ssklower #include "tp_stat.h"
6237469Ssklower #include "tp_seq.h"
6337469Ssklower #include "tp_ip.h"
6437469Ssklower #include "tp_pcb.h"
6537469Ssklower #include "argo_debug.h"
6637469Ssklower #include "tp_trace.h"
6737469Ssklower #include "tp_meas.h"
6837469Ssklower #include "iso.h"
6937469Ssklower #include "iso_errno.h"
7036420Ssklower 
7136420Ssklower int tp_attach(), tp_driver();
7239937Ssklower int TNew;
7339937Ssklower int TPNagle1, TPNagle2;
7444424Ssklower struct tp_pcb *tp_listeners, *tp_intercepts;
7536420Ssklower 
7636420Ssklower #ifdef ARGO_DEBUG
7736420Ssklower /*
7836420Ssklower  * CALLED FROM:
7936420Ssklower  *  anywhere you want to debug...
8036420Ssklower  * FUNCTION and ARGUMENTS:
8136420Ssklower  *  print (str) followed by the control info in the mbufs of an mbuf chain (n)
8236420Ssklower  */
8336420Ssklower void
8436420Ssklower dump_mbuf(n, str)
8536420Ssklower 	struct mbuf *n;
8636420Ssklower 	char *str;
8736420Ssklower {
8836420Ssklower 	struct mbuf *nextrecord;
8936420Ssklower 
9036420Ssklower 	printf("dump %s\n", str);
9136420Ssklower 
9244310Ssklower 	if (n == MNULL)  {
9336420Ssklower 		printf("EMPTY:\n");
9436420Ssklower 		return;
9536420Ssklower 	}
9636420Ssklower 
9744310Ssklower 	while (n) {
9836420Ssklower 		nextrecord = n->m_act;
9936420Ssklower 		printf("RECORD:\n");
10036420Ssklower 		while (n) {
10137469Ssklower 			printf("%x : Len %x Data %x A %x Nx %x Tp %x\n",
10237469Ssklower 				n, n->m_len, n->m_data, n->m_act, n->m_next, n->m_type);
10336420Ssklower #ifdef notdef
10436420Ssklower 			{
10536420Ssklower 				register char *p = mtod(n, char *);
10636420Ssklower 				register int i;
10736420Ssklower 
10836420Ssklower 				printf("data: ");
10944310Ssklower 				for (i = 0; i < n->m_len; i++) {
11044310Ssklower 					if (i%8 == 0)
11136420Ssklower 						printf("\n");
11236420Ssklower 					printf("0x%x ", *(p+i));
11336420Ssklower 				}
11436420Ssklower 				printf("\n");
11536420Ssklower 			}
11636420Ssklower #endif notdef
11744310Ssklower 			if (n->m_next == n) {
11836420Ssklower 				printf("LOOP!\n");
11936420Ssklower 				return;
12036420Ssklower 			}
12136420Ssklower 			n = n->m_next;
12236420Ssklower 		}
12336420Ssklower 		n = nextrecord;
12436420Ssklower 	}
12536420Ssklower 	printf("\n");
12636420Ssklower }
12736420Ssklower 
12836420Ssklower #endif ARGO_DEBUG
12936420Ssklower 
13036420Ssklower /*
13136420Ssklower  * CALLED FROM:
13236420Ssklower  *  tp_usrreq(), PRU_RCVOOB
13336420Ssklower  * FUNCTION and ARGUMENTS:
13436420Ssklower  * 	Copy data from the expedited data socket buffer into
13536420Ssklower  * 	the pre-allocated mbuf m.
13636420Ssklower  * 	There is an isomorphism between XPD TPDUs and expedited data TSDUs.
13736420Ssklower  * 	XPD tpdus are limited to 16 bytes of data so they fit in one mbuf.
13836420Ssklower  * RETURN VALUE:
13936420Ssklower  *  EINVAL if debugging is on and a disaster has occurred
14036420Ssklower  *  ENOTCONN if the socket isn't connected
14136420Ssklower  *  EWOULDBLOCK if the socket is in non-blocking mode and there's no
14236420Ssklower  *		xpd data in the buffer
14336420Ssklower  *  E* whatever is returned from the fsm.
14436420Ssklower  */
14536420Ssklower tp_rcvoob(tpcb, so, m, outflags, inflags)
14636420Ssklower 	struct tp_pcb	*tpcb;
14736420Ssklower 	register struct socket	*so;
14836420Ssklower 	register struct mbuf 	*m;
14936420Ssklower 	int 		 	*outflags;
15036420Ssklower 	int 		 	inflags;
15136420Ssklower {
15236420Ssklower 	register struct mbuf *n;
15337469Ssklower 	register struct sockbuf *sb = &so->so_rcv;
15436420Ssklower 	struct tp_event E;
15536420Ssklower 	int error = 0;
15637469Ssklower 	register struct mbuf **nn;
15736420Ssklower 
15836420Ssklower 	IFDEBUG(D_XPD)
15936420Ssklower 		printf("PRU_RCVOOB, sostate 0x%x\n", so->so_state);
16036420Ssklower 	ENDDEBUG
16136420Ssklower 
16236420Ssklower 	/* if you use soreceive */
16344310Ssklower 	if (m == MNULL)
16436420Ssklower 		return ENOBUFS;
16536420Ssklower 
16636420Ssklower restart:
16736420Ssklower 	if ((((so->so_state & SS_ISCONNECTED) == 0)
16836420Ssklower 		 || (so->so_state & SS_ISDISCONNECTING) != 0) &&
16936420Ssklower 		(so->so_proto->pr_flags & PR_CONNREQUIRED)) {
17036420Ssklower 			return ENOTCONN;
17136420Ssklower 	}
17236420Ssklower 
17337469Ssklower 	/* Take the first mbuf off the chain.
17437469Ssklower 	 * Each XPD TPDU gives you a complete TSDU so the chains don't get
17537469Ssklower 	 * coalesced, but one TSDU may span several mbufs.
17637469Ssklower 	 * Nevertheless, since n should have a most 16 bytes, it
17737469Ssklower 	 * will fit into m.  (size was checked in tp_input() )
17837469Ssklower 	 */
17937469Ssklower 
18037469Ssklower 	/*
18137469Ssklower 	 * Code for excision of OOB data should be added to
18237469Ssklower 	 * uipc_socket2.c (like sbappend).
18337469Ssklower 	 */
18437469Ssklower 
18538841Ssklower 	sblock(sb);
18637469Ssklower 	for (nn = &sb->sb_mb; n = *nn; nn = &n->m_act)
18737469Ssklower 		if (n->m_type == MT_OOBDATA)
18837469Ssklower 			break;
18937469Ssklower 
19037469Ssklower 	if (n == 0) {
19136420Ssklower 		IFDEBUG(D_XPD)
19236420Ssklower 			printf("RCVOOB: empty queue!\n");
19336420Ssklower 		ENDDEBUG
19438841Ssklower 		sbunlock(sb);
19536420Ssklower 		if (so->so_state & SS_NBIO) {
19636420Ssklower 			return  EWOULDBLOCK;
19736420Ssklower 		}
19836420Ssklower 		sbwait(sb);
19936420Ssklower 		goto restart;
20036420Ssklower 	}
20136420Ssklower 	m->m_len = 0;
20236420Ssklower 
20336420Ssklower 	/* Assuming at most one xpd tpdu is in the buffer at once */
20444310Ssklower 	while (n != MNULL) {
20536420Ssklower 		m->m_len += n->m_len;
20637469Ssklower 		bcopy(mtod(n, caddr_t), mtod(m, caddr_t), (unsigned)n->m_len);
20737469Ssklower 		m->m_data += n->m_len; /* so mtod() in bcopy() above gives right addr */
20836420Ssklower 		n = n->m_next;
20936420Ssklower 	}
21037469Ssklower 	m->m_data = m->m_dat;
21137469Ssklower 	m->m_flags |= M_EOR;
21236420Ssklower 
21336420Ssklower 	IFDEBUG(D_XPD)
21436420Ssklower 		printf("tp_rcvoob: xpdlen 0x%x\n", m->m_len);
21536420Ssklower 		dump_mbuf(so->so_rcv.sb_mb, "RCVOOB: Rcv socketbuf");
21636420Ssklower 		dump_mbuf(sb->sb_mb, "RCVOOB: Xrcv socketbuf");
21736420Ssklower 	ENDDEBUG
21836420Ssklower 
21944310Ssklower 	if ((inflags & MSG_PEEK) == 0) {
22037469Ssklower 		n = *nn;
22137469Ssklower 		*nn = n->m_act;
22237469Ssklower 		sb->sb_cc -= m->m_len;
22337469Ssklower 	}
22436420Ssklower 
22536420Ssklower release:
22636420Ssklower 	sbunlock(sb);
22736420Ssklower 
22836420Ssklower 	IFTRACE(D_XPD)
22936420Ssklower 		tptraceTPCB(TPPTmisc, "PRU_RCVOOB @ release sb_cc m_len",
23044310Ssklower 			tpcb->tp_Xrcv.sb_cc, m->m_len, 0, 0);
23136420Ssklower 	ENDTRACE
23236420Ssklower 	if (error == 0)
23336420Ssklower 		error = DoEvent(T_USR_Xrcvd);
23436420Ssklower 	return error;
23536420Ssklower }
23636420Ssklower 
23736420Ssklower /*
23836420Ssklower  * CALLED FROM:
23936420Ssklower  *  tp_usrreq(), PRU_SENDOOB
24036420Ssklower  * FUNCTION and ARGUMENTS:
24136420Ssklower  * 	Send what's in the mbuf chain (m) as an XPD TPDU.
24236420Ssklower  * 	The mbuf may not contain more then 16 bytes of data.
24336420Ssklower  * 	XPD TSDUs aren't segmented, so they translate into
24436420Ssklower  * 	exactly one XPD TPDU, with EOT bit set.
24536420Ssklower  * RETURN VALUE:
24636420Ssklower  *  EWOULDBLOCK if socket is in non-blocking mode and the previous
24736420Ssklower  *   xpd data haven't been acked yet.
24836420Ssklower  *  EMSGSIZE if trying to send > max-xpd bytes (16)
24936420Ssklower  *  ENOBUFS if ran out of mbufs
25036420Ssklower  */
25136420Ssklower tp_sendoob(tpcb, so, xdata, outflags)
25236420Ssklower 	struct tp_pcb	*tpcb;
25336420Ssklower 	register struct socket	*so;
25436420Ssklower 	register struct mbuf 	*xdata;
25536420Ssklower 	int 		 	*outflags; /* not used */
25636420Ssklower {
25736420Ssklower 	/*
25836420Ssklower 	 * Each mbuf chain represents a sequence # in the XPD seq space.
25936420Ssklower 	 * The first one in the queue has sequence # tp_Xuna.
26036420Ssklower 	 * When we add to the XPD queue, we stuff a zero-length
26136420Ssklower 	 * mbuf (mark) into the DATA queue, with its sequence number in m_next
26236420Ssklower 	 * to be assigned to this XPD tpdu, so data xfer can stop
26336420Ssklower 	 * when it reaches the zero-length mbuf if this XPD TPDU hasn't
26436420Ssklower 	 * yet been acknowledged.
26536420Ssklower 	 */
26636420Ssklower 	register struct sockbuf *sb = &(tpcb->tp_Xsnd);
26736420Ssklower 	register struct mbuf 	*xmark;
26836420Ssklower 	register int 			len=0;
26936420Ssklower 	struct tp_event E;
27036420Ssklower 
27136420Ssklower 	IFDEBUG(D_XPD)
27236420Ssklower 		printf("tp_sendoob:");
27344310Ssklower 		if (xdata)
27436420Ssklower 			printf("xdata len 0x%x\n", xdata->m_len);
27536420Ssklower 	ENDDEBUG
27636420Ssklower 	/* DO NOT LOCK the Xsnd buffer!!!! You can have at MOST one
27736420Ssklower 	 * socket buf locked at any time!!! (otherwise you might
27836420Ssklower 	 * sleep() in sblock() w/ a signal pending and cause the
27936420Ssklower 	 * system call to be aborted w/ a locked socketbuf, which
28036420Ssklower 	 * is a problem.  So the so_snd buffer lock
28136420Ssklower 	 * (done in sosend()) serves as the lock for Xpd.
28236420Ssklower 	 */
28338841Ssklower 	if (sb->sb_mb) { /* Anything already in eXpedited data sockbuf? */
28436420Ssklower 		if (so->so_state & SS_NBIO) {
28536420Ssklower 			return EWOULDBLOCK;
28636420Ssklower 		}
28738841Ssklower 		while (sb->sb_mb) {
28838841Ssklower 			sbunlock(&so->so_snd); /* already locked by sosend */
28938841Ssklower 			sbwait(&so->so_snd);
29038841Ssklower 			sblock(&so->so_snd);  /* sosend will unlock on return */
29138841Ssklower 		}
29236420Ssklower 	}
29336420Ssklower 
29436420Ssklower 	if (xdata == (struct mbuf *)0) {
29536420Ssklower 		/* empty xpd packet */
29637469Ssklower 		MGETHDR(xdata, M_WAIT, MT_OOBDATA);
29736420Ssklower 		if (xdata == NULL) {
29836420Ssklower 			return ENOBUFS;
29936420Ssklower 		}
30036420Ssklower 		xdata->m_len = 0;
30137469Ssklower 		xdata->m_pkthdr.len = 0;
30236420Ssklower 	}
30336420Ssklower 	IFDEBUG(D_XPD)
30436420Ssklower 		printf("tp_sendoob 1:");
30544310Ssklower 		if (xdata)
30636420Ssklower 			printf("xdata len 0x%x\n", xdata->m_len);
30736420Ssklower 	ENDDEBUG
30836420Ssklower 	xmark = xdata; /* temporary use of variable xmark */
30936420Ssklower 	while (xmark) {
31036420Ssklower 		len += xmark->m_len;
31136420Ssklower 		xmark = xmark->m_next;
31236420Ssklower 	}
31336420Ssklower 	if (len > TP_MAX_XPD_DATA) {
31436420Ssklower 		return EMSGSIZE;
31536420Ssklower 	}
31636420Ssklower 	IFDEBUG(D_XPD)
31736420Ssklower 		printf("tp_sendoob 2:");
31844310Ssklower 		if (xdata)
31936420Ssklower 			printf("xdata len 0x%x\n", len);
32036420Ssklower 	ENDDEBUG
32136420Ssklower 
32236420Ssklower 
32336420Ssklower 	IFTRACE(D_XPD)
32438841Ssklower 		tptraceTPCB(TPPTmisc, "XPD mark m_next ", xdata->m_next, 0, 0, 0);
32536420Ssklower 	ENDTRACE
32636420Ssklower 
32736420Ssklower 	sbappendrecord(sb, xdata);
32836420Ssklower 
32936420Ssklower 	IFDEBUG(D_XPD)
33036420Ssklower 		printf("tp_sendoob len 0x%x\n", len);
33136420Ssklower 		dump_mbuf(so->so_snd.sb_mb, "XPD request Regular sndbuf:");
33236420Ssklower 		dump_mbuf(tpcb->tp_Xsnd.sb_mb, "XPD request Xsndbuf:");
33336420Ssklower 	ENDDEBUG
33436420Ssklower 	return DoEvent(T_XPD_req);
33536420Ssklower }
33636420Ssklower 
33736420Ssklower /*
33836420Ssklower  * CALLED FROM:
33936420Ssklower  *  the socket routines
34036420Ssklower  * FUNCTION and ARGUMENTS:
34136420Ssklower  * 	Handles all "user requests" except the [gs]ockopts() requests.
34236420Ssklower  * 	The argument (req) is the request type (PRU*),
34336420Ssklower  * 	(m) is an mbuf chain, generally used for send and
34436420Ssklower  * 	receive type requests only.
34536420Ssklower  * 	(nam) is used for addresses usually, in particular for the bind request.
34636420Ssklower  *
34736420Ssklower  */
34836420Ssklower /*ARGSUSED*/
34936420Ssklower ProtoHook
35040773Ssklower tp_usrreq(so, req, m, nam, controlp)
35136420Ssklower 	struct socket *so;
35236420Ssklower 	u_int req;
35340773Ssklower 	struct mbuf *m, *nam, *controlp;
35436420Ssklower {
35536420Ssklower 	register struct tp_pcb *tpcb =  sototpcb(so);
35636420Ssklower 	int s = splnet();
35736420Ssklower 	int error = 0;
35837469Ssklower 	int flags, *outflags = &flags;
35936420Ssklower 	u_long eotsdu = 0;
36036420Ssklower 	struct tp_event E;
36136420Ssklower 
36236420Ssklower 	IFDEBUG(D_REQUEST)
36336420Ssklower 		printf("usrreq(0x%x,%d,0x%x,0x%x,0x%x)\n",so,req,m,nam,outflags);
36444310Ssklower 		if (so->so_error)
36536420Ssklower 			printf("WARNING!!! so->so_error is 0x%x\n", so->so_error);
36636420Ssklower 	ENDDEBUG
36736420Ssklower 	IFTRACE(D_REQUEST)
36836420Ssklower 		tptraceTPCB(TPPTusrreq, "req so m state [", req, so, m,
36936420Ssklower 			tpcb?tpcb->tp_state:0);
37036420Ssklower 	ENDTRACE
37136420Ssklower 
37236420Ssklower 	if ((u_int)tpcb == 0 && req != PRU_ATTACH) {
37336420Ssklower 		IFTRACE(D_REQUEST)
37436420Ssklower 			tptraceTPCB(TPPTusrreq, "req failed NO TPCB[", 0, 0, 0, 0);
37536420Ssklower 		ENDTRACE
37636420Ssklower 		splx(s);
37736420Ssklower 		return ENOTCONN;
37836420Ssklower 	}
37936420Ssklower 
38036420Ssklower 	switch (req) {
38136420Ssklower 
38236420Ssklower 	case PRU_ATTACH:
38336420Ssklower 		if (tpcb) {
38436420Ssklower 			error = EISCONN;
38536420Ssklower 			break;
38636420Ssklower 		}
38744310Ssklower 		if (error = tp_attach(so, so->so_proto->pr_domain->dom_family))
38836420Ssklower 			break;
38936420Ssklower 		tpcb = sototpcb(so);
39036420Ssklower 		break;
39136420Ssklower 
39236420Ssklower 	case PRU_ABORT: 	/* called from close() */
39336420Ssklower 		/* called for each incoming connect queued on the
39436420Ssklower 		 *	parent (accepting) socket
39536420Ssklower 		 */
39644310Ssklower 		if (tpcb->tp_state == TP_OPEN) {
39736420Ssklower 			E.ATTR(T_DISC_req).e_reason = E_TP_NO_SESSION;
39836420Ssklower 			error = DoEvent(T_DISC_req); /* pretend it was a close() */
39936420Ssklower 			break;
40036420Ssklower 		} /* else DROP THROUGH */
40136420Ssklower 
40236420Ssklower 	case PRU_DETACH: 	/* called from close() */
40336420Ssklower 		/* called only after disconnect was called */
40444424Ssklower 		if (tpcb->tp_state == TP_LISTENING) {
40544424Ssklower 			register struct tp_pcb **tt;
40644424Ssklower 			for (tt = &tp_listeners; *tt; tt = &((*tt)->tp_nextlisten))
40744424Ssklower 				if (*tt == tpcb)
40844424Ssklower 					break;
40944424Ssklower 			if (*tt)
41044424Ssklower 				*tt = tpcb->tp_nextlisten;
41144424Ssklower 			else {
41244424Ssklower 				for (tt = &tp_intercepts; *tt; tt = &((*tt)->tp_nextlisten))
41344424Ssklower 					if (*tt == tpcb)
41444424Ssklower 						break;
41544424Ssklower 				if (*tt)
41644424Ssklower 					*tt = tpcb->tp_nextlisten;
41744424Ssklower 				else
41844424Ssklower 					printf("tp_usrreq - detach: should panic\n");
41944424Ssklower 			}
42044424Ssklower 		}
42144424Ssklower 		if (tpcb->tp_next)
42244424Ssklower 			remque(tpcb);
42336420Ssklower 		error = DoEvent(T_DETACH);
42437469Ssklower 		if (tpcb->tp_state == TP_CLOSED) {
42537469Ssklower 			free((caddr_t)tpcb, M_PCB);
42637469Ssklower 			tpcb = 0;
42737469Ssklower 		}
42836420Ssklower 		break;
42936420Ssklower 
43036420Ssklower 	case PRU_SHUTDOWN:
43136420Ssklower 		/* recv end may have been released; local credit might be zero  */
43236420Ssklower 	case PRU_DISCONNECT:
43336420Ssklower 		E.ATTR(T_DISC_req).e_reason = E_TP_NORMAL_DISC;
43436420Ssklower 		error = DoEvent(T_DISC_req);
43536420Ssklower 		break;
43636420Ssklower 
43736420Ssklower 	case PRU_BIND:
43844310Ssklower 		error =  (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, nam);
43936420Ssklower 		if (error == 0) {
44037469Ssklower 			(tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
44144310Ssklower 				tpcb->tp_lsuffix, TP_LOCAL);
44236420Ssklower 		}
44336420Ssklower 		break;
44436420Ssklower 
44536420Ssklower 	case PRU_LISTEN:
44644310Ssklower 		if (tpcb->tp_lsuffixlen == 0) {
44744310Ssklower 			if (error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL))
44836420Ssklower 				break;
44937469Ssklower 			(tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
45044310Ssklower 				tpcb->tp_lsuffix, TP_LOCAL);
45136420Ssklower 		}
45244424Ssklower 		if (tpcb->tp_next == 0) {
45344424Ssklower 			tpcb->tp_next = tpcb->tp_prev = tpcb;
45444424Ssklower 			tpcb->tp_nextlisten = tp_listeners;
45544601Ssklower 			tp_listeners = tpcb;
45644424Ssklower 		}
45736420Ssklower 		IFDEBUG(D_TPISO)
45844310Ssklower 			if (tpcb->tp_state != TP_CLOSED)
45936420Ssklower 				printf("LISTEN ERROR: state 0x%x\n", tpcb->tp_state);
46036420Ssklower 		ENDDEBUG
46136420Ssklower 		error = DoEvent(T_LISTEN_req);
46236420Ssklower 		break;
46336420Ssklower 
46436420Ssklower 	case PRU_CONNECT2:
46536420Ssklower 		error = EOPNOTSUPP; /* for unix domain sockets */
46636420Ssklower 		break;
46736420Ssklower 
46836420Ssklower 	case PRU_CONNECT:
46936420Ssklower 		IFTRACE(D_CONN)
47036420Ssklower 			tptraceTPCB(TPPTmisc,
47137469Ssklower 			"PRU_CONNECT: so 0x%x *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x",
47236420Ssklower 			tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen,
47336420Ssklower 				tpcb->tp_class);
47436420Ssklower 		ENDTRACE
47536420Ssklower 		IFDEBUG(D_CONN)
47636420Ssklower 			printf("PRU_CONNECT: so *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x",
47736420Ssklower 			tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen,
47836420Ssklower 				tpcb->tp_class);
47936420Ssklower 		ENDDEBUG
48044310Ssklower 		if (tpcb->tp_lsuffixlen == 0) {
48144310Ssklower 			if (error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL)) {
48236420Ssklower 				IFDEBUG(D_CONN)
48344310Ssklower 					printf("pcbbind returns error 0x%x\n", error);
48436420Ssklower 				ENDDEBUG
48536420Ssklower 				break;
48636420Ssklower 			}
48737469Ssklower 			(tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
48844310Ssklower 				tpcb->tp_lsuffix, TP_LOCAL);
48937469Ssklower 		}
49036420Ssklower 
49136420Ssklower 		IFDEBUG(D_CONN)
49236420Ssklower 			printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb);
49344310Ssklower 			dump_buf(tpcb->tp_npcb, 16);
49436420Ssklower 		ENDDEBUG
49544310Ssklower 		if (error = tp_route_to(nam, tpcb, /* channel */0))
49636420Ssklower 			break;
49736420Ssklower 		IFDEBUG(D_CONN)
49836420Ssklower 			printf(
49936420Ssklower 				"PRU_CONNECT after tpcb 0x%x so 0x%x npcb 0x%x flags 0x%x\n",
50036420Ssklower 				tpcb, so, tpcb->tp_npcb, tpcb->tp_flags);
50136420Ssklower 			printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb);
50244310Ssklower 			dump_buf(tpcb->tp_npcb, 16);
50336420Ssklower 		ENDDEBUG
50444310Ssklower 		if (tpcb->tp_fsuffixlen ==  0) {
50536420Ssklower 			/* didn't set peer extended suffix */
50637469Ssklower 			(tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_fsuffixlen,
50744310Ssklower 				tpcb->tp_fsuffix, TP_FOREIGN);
50836420Ssklower 		}
50936420Ssklower 		(void) (tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb,
51036420Ssklower 					&tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0);
51144310Ssklower 		if (tpcb->tp_state == TP_CLOSED) {
51236420Ssklower 			soisconnecting(so);
51336420Ssklower 			error = DoEvent(T_CONN_req);
51436420Ssklower 		} else {
51536420Ssklower 			(tpcb->tp_nlproto->nlp_pcbdisc)(so->so_pcb);
51636420Ssklower 			error = EISCONN;
51736420Ssklower 		}
51836420Ssklower 		IFPERF(tpcb)
51936420Ssklower 			u_int lsufx, fsufx;
52039196Ssklower 			lsufx = *(u_short *)(tpcb->tp_lsuffix);
52139196Ssklower 			fsufx = *(u_short *)(tpcb->tp_fsuffix);
52236420Ssklower 
52344310Ssklower 			tpmeas(tpcb->tp_lref,
52444310Ssklower 				TPtime_open | (tpcb->tp_xtd_format << 4),
52536420Ssklower 				&time, lsufx, fsufx, tpcb->tp_fref);
52636420Ssklower 		ENDPERF
52736420Ssklower 		break;
52836420Ssklower 
52936420Ssklower 	case PRU_ACCEPT:
53038841Ssklower 		(tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN);
53136420Ssklower 		IFDEBUG(D_REQUEST)
53238841Ssklower 			printf("ACCEPT PEERADDDR:");
53338841Ssklower 			dump_buf(mtod(nam, char *), nam->m_len);
53436420Ssklower 		ENDDEBUG
53536420Ssklower 		IFPERF(tpcb)
53636420Ssklower 			u_int lsufx, fsufx;
53739196Ssklower 			lsufx = *(u_short *)(tpcb->tp_lsuffix);
53839196Ssklower 			fsufx = *(u_short *)(tpcb->tp_fsuffix);
53936420Ssklower 
54044310Ssklower 			tpmeas(tpcb->tp_lref, TPtime_open,
54136420Ssklower 				&time, lsufx, fsufx, tpcb->tp_fref);
54236420Ssklower 		ENDPERF
54336420Ssklower 		break;
54436420Ssklower 
54536420Ssklower 	case PRU_RCVD:
54638841Ssklower 		if (so->so_state & SS_ISCONFIRMING) {
54738841Ssklower 			if (tpcb->tp_state == TP_CONFIRMING)
54838841Ssklower 				error = tp_confirm(tpcb);
54938841Ssklower 			break;
55038841Ssklower 		}
55136420Ssklower 		IFTRACE(D_DATA)
55236420Ssklower 			tptraceTPCB(TPPTmisc,
55336420Ssklower 			"RCVD BF: lcredit sent_lcdt cc hiwat \n",
55436420Ssklower 				tpcb->tp_lcredit, tpcb->tp_sent_lcdt,
55536420Ssklower 				so->so_rcv.sb_cc, so->so_rcv.sb_hiwat);
55636420Ssklower 			LOCAL_CREDIT(tpcb);
55736420Ssklower 			tptraceTPCB(TPPTmisc,
55836420Ssklower 				"PRU_RCVD AF sbspace lcredit hiwat cc",
55936420Ssklower 				sbspace(&so->so_rcv), tpcb->tp_lcredit,
56036420Ssklower 				so->so_rcv.sb_cc, so->so_rcv.sb_hiwat);
56136420Ssklower 		ENDTRACE
56237469Ssklower 		IFDEBUG(D_REQUEST)
56337469Ssklower 			printf("RCVD: cc %d space %d hiwat %d\n",
56437469Ssklower 				so->so_rcv.sb_cc, sbspace(&so->so_rcv),
56537469Ssklower 				so->so_rcv.sb_hiwat);
56637469Ssklower 		ENDDEBUG
56737469Ssklower 		if (((int)nam) & MSG_OOB)
56837469Ssklower 			error = DoEvent(T_USR_Xrcvd);
56937469Ssklower 		else
57037469Ssklower 			error = DoEvent(T_USR_rcvd);
57136420Ssklower 		break;
57236420Ssklower 
57336420Ssklower 	case PRU_RCVOOB:
57436420Ssklower 		if ((so->so_state & SS_ISCONNECTED) == 0) {
57536420Ssklower 			error = ENOTCONN;
57636420Ssklower 			break;
57736420Ssklower 		}
57844310Ssklower 		if (! tpcb->tp_xpd_service) {
57936420Ssklower 			error = EOPNOTSUPP;
58036420Ssklower 			break;
58136420Ssklower 		}
58236420Ssklower 		/* kludge - nam is really flags here */
58336420Ssklower 		error = tp_rcvoob(tpcb, so, m, outflags, (int)nam);
58436420Ssklower 		break;
58536420Ssklower 
58638841Ssklower 	case PRU_SEND:
58736420Ssklower 	case PRU_SENDOOB:
58841924Ssklower 		if (controlp) {
58941924Ssklower 			error = tp_snd_control(controlp, so, &m);
59041924Ssklower 			controlp = NULL;
59141924Ssklower 			if (error)
59241924Ssklower 				break;
59341924Ssklower 		}
59448736Ssklower 		if ((so->so_state & SS_ISCONFIRMING) &&
59548736Ssklower 		    (tpcb->tp_state == TP_CONFIRMING) &&
59648736Ssklower 		    (error = tp_confirm(tpcb)))
59748736Ssklower 			    break;
59848736Ssklower 		if (req == PRU_SENDOOB) {
59948736Ssklower 			error = (tpcb->tp_xpd_service == 0) ?
60048736Ssklower 						EOPNOTSUPP : tp_sendoob(tpcb, so, m, outflags);
60138841Ssklower 			break;
60238841Ssklower 		}
60337469Ssklower 		if (m == 0)
60437469Ssklower 			break;
60548736Ssklower 		if (m->m_flags & M_EOR) {
60648736Ssklower 			eotsdu = 1;
60748736Ssklower 			m->m_flags &= ~M_EOR;
60848736Ssklower 		}
60948736Ssklower 		if (eotsdu == 0 && m->m_pkthdr.len == 0)
61036420Ssklower 			break;
61148736Ssklower 		if (tpcb->tp_state != TP_AKWAIT && tpcb->tp_state != TP_OPEN) {
61248736Ssklower 			error = ENOTCONN;
61348736Ssklower 			break;
61436420Ssklower 		}
61536420Ssklower 		/*
61636420Ssklower 		 * The protocol machine copies mbuf chains,
61736420Ssklower 		 * prepends headers, assigns seq numbers, and
61836420Ssklower 		 * puts the packets on the device.
61936420Ssklower 		 * When they are acked they are removed from the socket buf.
62036420Ssklower 		 *
62136420Ssklower 		 * sosend calls this up until sbspace goes negative.
62236420Ssklower 		 * Sbspace may be made negative by appending this mbuf chain,
62336420Ssklower 		 * possibly by a whole cluster.
62436420Ssklower 		 */
62536420Ssklower 		{
62637469Ssklower 			register struct mbuf *n = m;
62736420Ssklower 			register struct sockbuf *sb = &so->so_snd;
62837469Ssklower 			int	maxsize = tpcb->tp_l_tpdusize
62937469Ssklower 				    - tp_headersize(DT_TPDU_type, tpcb)
63037469Ssklower 				    - (tpcb->tp_use_checksum?4:0) ;
63137469Ssklower 			int totlen = n->m_pkthdr.len;
63239937Ssklower 			int	mbufcnt = 0;
63339196Ssklower 			struct mbuf *nn;
63436420Ssklower 
63537469Ssklower 			/*
63637469Ssklower 			 * Could have eotsdu and no data.(presently MUST have
63737469Ssklower 			 * an mbuf though, even if its length == 0)
63837469Ssklower 			 */
63936420Ssklower 			IFPERF(tpcb)
64037469Ssklower 			   PStat(tpcb, Nb_from_sess) += totlen;
64136420Ssklower 			   tpmeas(tpcb->tp_lref, TPtime_from_session, 0, 0,
64237469Ssklower 					PStat(tpcb, Nb_from_sess), totlen);
64336420Ssklower 			ENDPERF
64436420Ssklower 			IFDEBUG(D_SYSCALL)
64536420Ssklower 				printf(
64636420Ssklower 				"PRU_SEND: eot %d before sbappend 0x%x len 0x%x to sb @ 0x%x\n",
64739937Ssklower 					eotsdu, m, totlen, sb);
64836420Ssklower 				dump_mbuf(sb->sb_mb, "so_snd.sb_mb");
64936420Ssklower 				dump_mbuf(m, "m : to be added");
65036420Ssklower 			ENDDEBUG
65137469Ssklower 			/*
65237469Ssklower 			 * Pre-packetize the data in the sockbuf
65337469Ssklower 			 * according to negotiated mtu.  Do it here
65437469Ssklower 			 * where we can safely wait for mbufs.
65539196Ssklower 			 *
65639196Ssklower 			 * This presumes knowledge of sockbuf conventions.
65736420Ssklower 			 */
65839196Ssklower 			if (n = sb->sb_mb)
65939196Ssklower 				while (n->m_act)
66039196Ssklower 					n = n->m_act;
66139647Ssklower 			if ((nn = n) && n->m_pkthdr.len < maxsize) {
66239937Ssklower 				u_int space = maxsize - n->m_pkthdr.len;
66339647Ssklower 
66439647Ssklower 				do {
66539647Ssklower 					if (n->m_flags & M_EOR)
66639647Ssklower 						goto on1;
66739647Ssklower 				} while (n->m_next && (n = n->m_next));
66839937Ssklower 				if (totlen <= space) {
66939937Ssklower 					TPNagle1++;
67039196Ssklower 					n->m_next = m;
67139937Ssklower 					nn->m_pkthdr.len += totlen;
67239937Ssklower 					while (n = n->m_next)
67339937Ssklower 						sballoc(sb, n);
67439196Ssklower 					if (eotsdu)
67539196Ssklower 						nn->m_flags |= M_EOR;
67639196Ssklower 					goto on2;
67739937Ssklower 				} else {
67839937Ssklower 					/*
67939937Ssklower 					 * Can't sleep here, because when you wake up
68039937Ssklower 					 * packet you want to attach to may be gone!
68139937Ssklower 					 */
68239937Ssklower 					if (TNew && (n->m_next = m_copym(m, 0, space, M_NOWAIT))) {
68339937Ssklower 						nn->m_pkthdr.len += space;
68439937Ssklower 						TPNagle2++;
68539937Ssklower 						while (n = n->m_next)
68639937Ssklower 							sballoc(sb, n);
68739937Ssklower 						m_adj(m, space);
68839937Ssklower 					}
68939196Ssklower 				}
69039196Ssklower 			}
69139937Ssklower 	on1:	mbufcnt++;
69239196Ssklower 			for (n = m; n->m_pkthdr.len > maxsize;) {
69339937Ssklower 				nn = m_copym(n, 0, maxsize, M_WAIT);
69437469Ssklower 				sbappendrecord(sb, nn);
69537469Ssklower 				m_adj(n, maxsize);
69639937Ssklower 				mbufcnt++;
69737469Ssklower 			}
69839196Ssklower 			if (eotsdu)
69939196Ssklower 				n->m_flags |= M_EOR;
70037469Ssklower 			sbappendrecord(sb, n);
70139196Ssklower 	on2:
70239196Ssklower 			IFTRACE(D_DATA)
70339196Ssklower 				tptraceTPCB(TPPTmisc,
70439937Ssklower 				"SEND BF: maxsize totlen mbufcnt eotsdu",
70539937Ssklower 					maxsize, totlen, mbufcnt, eotsdu);
70639196Ssklower 			ENDTRACE
70736420Ssklower 			IFDEBUG(D_SYSCALL)
70839937Ssklower 				printf("PRU_SEND: eot %d after sbappend 0x%x mbufcnt 0x%x\n",
70939937Ssklower 					eotsdu, n, mbufcnt);
71036420Ssklower 				dump_mbuf(sb->sb_mb, "so_snd.sb_mb");
71136420Ssklower 			ENDDEBUG
71248736Ssklower 			if (tpcb->tp_state == TP_OPEN)
71348736Ssklower 				error = DoEvent(T_DATA_req);
71436420Ssklower 			IFDEBUG(D_SYSCALL)
71536420Ssklower 				printf("PRU_SEND: after driver error 0x%x \n",error);
71637469Ssklower 				printf("so_snd 0x%x cc 0t%d mbcnt 0t%d\n",
71737469Ssklower 						sb, sb->sb_cc, sb->sb_mbcnt);
71837469Ssklower 				dump_mbuf(sb->sb_mb, "so_snd.sb_mb after driver");
71936420Ssklower 			ENDDEBUG
72036420Ssklower 		}
72136420Ssklower 		break;
72236420Ssklower 
72337469Ssklower 	case PRU_SOCKADDR:
72437469Ssklower 		(tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_LOCAL);
72536420Ssklower 		break;
72636420Ssklower 
72736420Ssklower 	case PRU_PEERADDR:
72838841Ssklower 		(tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN);
72936420Ssklower 		break;
73036420Ssklower 
73136420Ssklower 	case PRU_CONTROL:
73236420Ssklower 		error = EOPNOTSUPP;
73336420Ssklower 		break;
73436420Ssklower 
73536420Ssklower 	case PRU_PROTOSEND:
73636420Ssklower 	case PRU_PROTORCV:
73736420Ssklower 	case PRU_SENSE:
73836420Ssklower 	case PRU_SLOWTIMO:
73936420Ssklower 	case PRU_FASTTIMO:
74036420Ssklower 		error = EOPNOTSUPP;
74136420Ssklower 		break;
74236420Ssklower 
74336420Ssklower 	default:
74436420Ssklower #ifdef ARGO_DEBUG
74536420Ssklower 		printf("tp_usrreq UNKNOWN PRU %d\n", req);
74636420Ssklower #endif ARGO_DEBUG
74736420Ssklower 		error = EOPNOTSUPP;
74836420Ssklower 	}
74936420Ssklower 
75036420Ssklower 	IFDEBUG(D_REQUEST)
75138841Ssklower 		printf("%s, so 0x%x, tpcb 0x%x, error %d, state %d\n",
75238841Ssklower 			"returning from tp_usrreq", so, tpcb, error,
75338841Ssklower 			tpcb ? 0 : tpcb->tp_state);
75436420Ssklower 	ENDDEBUG
75536420Ssklower 	IFTRACE(D_REQUEST)
75636420Ssklower 		tptraceTPCB(TPPTusrreq, "END req so m state [", req, so, m,
75736420Ssklower 			tpcb?0:tpcb->tp_state);
75836420Ssklower 	ENDTRACE
75941924Ssklower 	if (controlp) {
76041924Ssklower 		m_freem(controlp);
76141924Ssklower 		printf("control data unexpectedly retained in tp_usrreq()");
76241924Ssklower 	}
76336420Ssklower 	splx(s);
76436420Ssklower 	return error;
76536420Ssklower }
76639196Ssklower tp_ltrace(so, uio)
76739196Ssklower struct socket *so;
76839196Ssklower struct uio *uio;
76939196Ssklower {
77039196Ssklower 	IFTRACE(D_DATA)
77139196Ssklower 		register struct tp_pcb *tpcb =  sototpcb(so);
77239196Ssklower 		if (tpcb) {
77339196Ssklower 			tptraceTPCB(TPPTmisc, "sosend so resid iovcnt", so,
77439196Ssklower 				uio->uio_resid, uio->uio_iovcnt, 0);
77539196Ssklower 		}
77639196Ssklower 	ENDTRACE
77739196Ssklower }
77837469Ssklower 
77938841Ssklower tp_confirm(tpcb)
78038841Ssklower register struct tp_pcb *tpcb;
78137469Ssklower {
78238841Ssklower 	struct tp_event E;
78338841Ssklower 	if (tpcb->tp_state == TP_CONFIRMING)
78438841Ssklower 	    return DoEvent(T_ACPT_req);
78538841Ssklower 	printf("Tp confirm called when not confirming; tpcb 0x%x, state 0x%x\n",
78638841Ssklower 		tpcb, tpcb->tp_state);
78738841Ssklower 	return 0;
78837469Ssklower }
78937469Ssklower 
79037469Ssklower /*
79137469Ssklower  * Process control data sent with sendmsg()
79237469Ssklower  */
79341924Ssklower tp_snd_control(m, so, data)
79441924Ssklower 	struct mbuf *m;
79537469Ssklower 	struct socket *so;
79637469Ssklower 	register struct mbuf **data;
79737469Ssklower {
79842468Ssklower 	register struct cmsghdr *ch;
79937469Ssklower 	int error = 0;
80037469Ssklower 
80141924Ssklower 	if (m && m->m_len) {
80242468Ssklower 		ch = mtod(m, struct cmsghdr *);
80341924Ssklower 		m->m_len -= sizeof (*ch);
80441924Ssklower 		m->m_data += sizeof (*ch);
80537469Ssklower 		error = tp_ctloutput(PRCO_SETOPT,
80637469Ssklower 							 so, ch->cmsg_level, ch->cmsg_type, &m);
80737469Ssklower 		if (ch->cmsg_type == TPOPT_DISC_DATA) {
80837469Ssklower 			if (data && *data) {
80937469Ssklower 				m_freem(*data);
81037469Ssklower 				*data = 0;
81137469Ssklower 			}
81241924Ssklower 			error = tp_usrreq(so, PRU_DISCONNECT, (struct mbuf *)0,
81341924Ssklower 								(caddr_t)0, (struct mbuf *)0);
81437469Ssklower 		}
81537469Ssklower 	}
81641924Ssklower 	if (m)
81741924Ssklower 		m_freem(m);
81837469Ssklower 	return error;
81937469Ssklower }
820