summaryrefslogtreecommitdiff
path: root/sys/netiso/tp_usrreq.c
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
commitd6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch)
treeece253b876159b39c620e62b6c9b1174642e070e /sys/netiso/tp_usrreq.c
initial import of NetBSD tree
Diffstat (limited to 'sys/netiso/tp_usrreq.c')
-rw-r--r--sys/netiso/tp_usrreq.c753
1 files changed, 753 insertions, 0 deletions
diff --git a/sys/netiso/tp_usrreq.c b/sys/netiso/tp_usrreq.c
new file mode 100644
index 00000000000..2925f28ad07
--- /dev/null
+++ b/sys/netiso/tp_usrreq.c
@@ -0,0 +1,753 @@
+/* $NetBSD: tp_usrreq.c,v 1.7 1995/08/12 23:59:52 mycroft Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)tp_usrreq.c 8.1 (Berkeley) 6/10/93
+ */
+
+/***********************************************************
+ Copyright IBM Corporation 1987
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of IBM not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+/*
+ * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
+ */
+/*
+ * tp_usrreq(), the fellow that gets called from most of the socket code.
+ * Pretty straighforward.
+ * THe only really awful stuff here is the OOB processing, which is done
+ * wholly here.
+ * tp_rcvoob() and tp_sendoob() are contained here and called by tp_usrreq().
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/domain.h>
+#include <sys/protosw.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+
+#include <netiso/tp_param.h>
+#include <netiso/tp_timer.h>
+#include <netiso/tp_stat.h>
+#include <netiso/tp_seq.h>
+#include <netiso/tp_ip.h>
+#include <netiso/tp_pcb.h>
+#include <netiso/argo_debug.h>
+#include <netiso/tp_trace.h>
+#include <netiso/tp_meas.h>
+#include <netiso/iso.h>
+#include <netiso/iso_errno.h>
+
+int tp_attach(), tp_pcbbind();
+int TNew;
+int TPNagle1, TPNagle2;
+struct tp_pcb *tp_listeners, *tp_intercepts;
+
+#ifdef ARGO_DEBUG
+/*
+ * CALLED FROM:
+ * anywhere you want to debug...
+ * FUNCTION and ARGUMENTS:
+ * print (str) followed by the control info in the mbufs of an mbuf chain (n)
+ */
+void
+dump_mbuf(n, str)
+ struct mbuf *n;
+ char *str;
+{
+ struct mbuf *nextrecord;
+
+ printf("dump %s\n", str);
+
+ if (n == MNULL) {
+ printf("EMPTY:\n");
+ return;
+ }
+
+ while (n) {
+ nextrecord = n->m_act;
+ printf("RECORD:\n");
+ while (n) {
+ printf("%x : Len %x Data %x A %x Nx %x Tp %x\n",
+ n, n->m_len, n->m_data, n->m_act, n->m_next, n->m_type);
+#ifdef notdef
+ {
+ register char *p = mtod(n, char *);
+ register int i;
+
+ printf("data: ");
+ for (i = 0; i < n->m_len; i++) {
+ if (i%8 == 0)
+ printf("\n");
+ printf("0x%x ", *(p+i));
+ }
+ printf("\n");
+ }
+#endif /* notdef */
+ if (n->m_next == n) {
+ printf("LOOP!\n");
+ return;
+ }
+ n = n->m_next;
+ }
+ n = nextrecord;
+ }
+ printf("\n");
+}
+
+#endif /* ARGO_DEBUG */
+
+/*
+ * CALLED FROM:
+ * tp_usrreq(), PRU_RCVOOB
+ * FUNCTION and ARGUMENTS:
+ * Copy data from the expedited data socket buffer into
+ * the pre-allocated mbuf m.
+ * There is an isomorphism between XPD TPDUs and expedited data TSDUs.
+ * XPD tpdus are limited to 16 bytes of data so they fit in one mbuf.
+ * RETURN VALUE:
+ * EINVAL if debugging is on and a disaster has occurred
+ * ENOTCONN if the socket isn't connected
+ * EWOULDBLOCK if the socket is in non-blocking mode and there's no
+ * xpd data in the buffer
+ * E* whatever is returned from the fsm.
+ */
+tp_rcvoob(tpcb, so, m, outflags, inflags)
+ struct tp_pcb *tpcb;
+ register struct socket *so;
+ register struct mbuf *m;
+ int *outflags;
+ int inflags;
+{
+ register struct mbuf *n;
+ register struct sockbuf *sb = &so->so_rcv;
+ struct tp_event E;
+ int error = 0;
+ register struct mbuf **nn;
+
+ IFDEBUG(D_XPD)
+ printf("PRU_RCVOOB, sostate 0x%x\n", so->so_state);
+ ENDDEBUG
+
+ /* if you use soreceive */
+ if (m == MNULL)
+ return ENOBUFS;
+
+restart:
+ if ((((so->so_state & SS_ISCONNECTED) == 0)
+ || (so->so_state & SS_ISDISCONNECTING) != 0) &&
+ (so->so_proto->pr_flags & PR_CONNREQUIRED)) {
+ return ENOTCONN;
+ }
+
+ /* Take the first mbuf off the chain.
+ * Each XPD TPDU gives you a complete TSDU so the chains don't get
+ * coalesced, but one TSDU may span several mbufs.
+ * Nevertheless, since n should have a most 16 bytes, it
+ * will fit into m. (size was checked in tp_input() )
+ */
+
+ /*
+ * Code for excision of OOB data should be added to
+ * uipc_socket2.c (like sbappend).
+ */
+
+ sblock(sb, M_WAITOK);
+ for (nn = &sb->sb_mb; n = *nn; nn = &n->m_act)
+ if (n->m_type == MT_OOBDATA)
+ break;
+
+ if (n == 0) {
+ IFDEBUG(D_XPD)
+ printf("RCVOOB: empty queue!\n");
+ ENDDEBUG
+ sbunlock(sb);
+ if (so->so_state & SS_NBIO) {
+ return EWOULDBLOCK;
+ }
+ sbwait(sb);
+ goto restart;
+ }
+ m->m_len = 0;
+
+ /* Assuming at most one xpd tpdu is in the buffer at once */
+ while (n != MNULL) {
+ m->m_len += n->m_len;
+ bcopy(mtod(n, caddr_t), mtod(m, caddr_t), (unsigned)n->m_len);
+ m->m_data += n->m_len; /* so mtod() in bcopy() above gives right addr */
+ n = n->m_next;
+ }
+ m->m_data = m->m_dat;
+ m->m_flags |= M_EOR;
+
+ IFDEBUG(D_XPD)
+ printf("tp_rcvoob: xpdlen 0x%x\n", m->m_len);
+ dump_mbuf(so->so_rcv.sb_mb, "RCVOOB: Rcv socketbuf");
+ dump_mbuf(sb->sb_mb, "RCVOOB: Xrcv socketbuf");
+ ENDDEBUG
+
+ if ((inflags & MSG_PEEK) == 0) {
+ n = *nn;
+ *nn = n->m_act;
+ for (; n; n = m_free(n))
+ sbfree(sb, n);
+ }
+
+release:
+ sbunlock(sb);
+
+ IFTRACE(D_XPD)
+ tptraceTPCB(TPPTmisc, "PRU_RCVOOB @ release sb_cc m_len",
+ tpcb->tp_Xrcv.sb_cc, m->m_len, 0, 0);
+ ENDTRACE
+ if (error == 0)
+ error = DoEvent(T_USR_Xrcvd);
+ return error;
+}
+
+/*
+ * CALLED FROM:
+ * tp_usrreq(), PRU_SENDOOB
+ * FUNCTION and ARGUMENTS:
+ * Send what's in the mbuf chain (m) as an XPD TPDU.
+ * The mbuf may not contain more then 16 bytes of data.
+ * XPD TSDUs aren't segmented, so they translate into
+ * exactly one XPD TPDU, with EOT bit set.
+ * RETURN VALUE:
+ * EWOULDBLOCK if socket is in non-blocking mode and the previous
+ * xpd data haven't been acked yet.
+ * EMSGSIZE if trying to send > max-xpd bytes (16)
+ * ENOBUFS if ran out of mbufs
+ */
+tp_sendoob(tpcb, so, xdata, outflags)
+ struct tp_pcb *tpcb;
+ register struct socket *so;
+ register struct mbuf *xdata;
+ int *outflags; /* not used */
+{
+ /*
+ * Each mbuf chain represents a sequence # in the XPD seq space.
+ * The first one in the queue has sequence # tp_Xuna.
+ * When we add to the XPD queue, we stuff a zero-length
+ * mbuf (mark) into the DATA queue, with its sequence number in m_next
+ * to be assigned to this XPD tpdu, so data xfer can stop
+ * when it reaches the zero-length mbuf if this XPD TPDU hasn't
+ * yet been acknowledged.
+ */
+ register struct sockbuf *sb = &(tpcb->tp_Xsnd);
+ register struct mbuf *xmark;
+ register int len=0;
+ struct tp_event E;
+
+ IFDEBUG(D_XPD)
+ printf("tp_sendoob:");
+ if (xdata)
+ printf("xdata len 0x%x\n", xdata->m_len);
+ ENDDEBUG
+ /* DO NOT LOCK the Xsnd buffer!!!! You can have at MOST one
+ * socket buf locked at any time!!! (otherwise you might
+ * sleep() in sblock() w/ a signal pending and cause the
+ * system call to be aborted w/ a locked socketbuf, which
+ * is a problem. So the so_snd buffer lock
+ * (done in sosend()) serves as the lock for Xpd.
+ */
+ if (sb->sb_mb) { /* Anything already in eXpedited data sockbuf? */
+ if (so->so_state & SS_NBIO) {
+ return EWOULDBLOCK;
+ }
+ while (sb->sb_mb) {
+ sbunlock(&so->so_snd); /* already locked by sosend */
+ sbwait(&so->so_snd);
+ sblock(&so->so_snd, M_WAITOK); /* sosend will unlock on return */
+ }
+ }
+
+ if (xdata == (struct mbuf *)0) {
+ /* empty xpd packet */
+ MGETHDR(xdata, M_WAIT, MT_OOBDATA);
+ if (xdata == NULL) {
+ return ENOBUFS;
+ }
+ xdata->m_len = 0;
+ xdata->m_pkthdr.len = 0;
+ }
+ IFDEBUG(D_XPD)
+ printf("tp_sendoob 1:");
+ if (xdata)
+ printf("xdata len 0x%x\n", xdata->m_len);
+ ENDDEBUG
+ xmark = xdata; /* temporary use of variable xmark */
+ while (xmark) {
+ len += xmark->m_len;
+ xmark = xmark->m_next;
+ }
+ if (len > TP_MAX_XPD_DATA) {
+ return EMSGSIZE;
+ }
+ IFDEBUG(D_XPD)
+ printf("tp_sendoob 2:");
+ if (xdata)
+ printf("xdata len 0x%x\n", len);
+ ENDDEBUG
+
+
+ IFTRACE(D_XPD)
+ tptraceTPCB(TPPTmisc, "XPD mark m_next ", xdata->m_next, 0, 0, 0);
+ ENDTRACE
+
+ sbappendrecord(sb, xdata);
+
+ IFDEBUG(D_XPD)
+ printf("tp_sendoob len 0x%x\n", len);
+ dump_mbuf(so->so_snd.sb_mb, "XPD request Regular sndbuf:");
+ dump_mbuf(tpcb->tp_Xsnd.sb_mb, "XPD request Xsndbuf:");
+ ENDDEBUG
+ return DoEvent(T_XPD_req);
+}
+
+/*
+ * CALLED FROM:
+ * the socket routines
+ * FUNCTION and ARGUMENTS:
+ * Handles all "user requests" except the [gs]ockopts() requests.
+ * The argument (req) is the request type (PRU*),
+ * (m) is an mbuf chain, generally used for send and
+ * receive type requests only.
+ * (nam) is used for addresses usually, in particular for the bind request.
+ *
+ */
+/*ARGSUSED*/
+int
+tp_usrreq(so, req, m, nam, controlp)
+ struct socket *so;
+ u_int req;
+ struct mbuf *m, *nam, *controlp;
+{
+ register struct tp_pcb *tpcb = sototpcb(so);
+ int s = splsoftnet();
+ int error = 0;
+ int flags, *outflags = &flags;
+ u_long eotsdu = 0;
+ struct tp_event E;
+
+ IFDEBUG(D_REQUEST)
+ printf("usrreq(0x%x,%d,0x%x,0x%x,0x%x)\n",so,req,m,nam,outflags);
+ if (so->so_error)
+ printf("WARNING!!! so->so_error is 0x%x\n", so->so_error);
+ ENDDEBUG
+ IFTRACE(D_REQUEST)
+ tptraceTPCB(TPPTusrreq, "req so m state [", req, so, m,
+ tpcb?tpcb->tp_state:0);
+ ENDTRACE
+
+ if ((u_long)tpcb == 0 && req != PRU_ATTACH) {
+ IFTRACE(D_REQUEST)
+ tptraceTPCB(TPPTusrreq, "req failed NO TPCB[", 0, 0, 0, 0);
+ ENDTRACE
+ splx(s);
+ return ENOTCONN;
+ }
+
+ switch (req) {
+
+ case PRU_ATTACH:
+ if (tpcb) {
+ error = EISCONN;
+ } else if ((error = tp_attach(so, (long)nam)) == 0)
+ tpcb = sototpcb(so);
+ break;
+
+ case PRU_ABORT: /* called from close() */
+ /* called for each incoming connect queued on the
+ * parent (accepting) socket
+ */
+ if (tpcb->tp_state == TP_OPEN || tpcb->tp_state == TP_CONFIRMING) {
+ E.ATTR(T_DISC_req).e_reason = E_TP_NO_SESSION ^ TP_ERROR_MASK;
+ error = DoEvent(T_DISC_req); /* pretend it was a close() */
+ break;
+ } /* else DROP THROUGH */
+
+ case PRU_DETACH: /* called from close() */
+ /* called only after disconnect was called */
+ error = DoEvent(T_DETACH);
+ if (tpcb->tp_state == TP_CLOSED) {
+ if (tpcb->tp_notdetached) {
+ IFDEBUG(D_CONN)
+ printf("PRU_DETACH: not detached\n");
+ ENDDEBUG
+ tp_detach(tpcb);
+ }
+ free((caddr_t)tpcb, M_PCB);
+ tpcb = 0;
+ }
+ break;
+
+ case PRU_SHUTDOWN:
+ /* recv end may have been released; local credit might be zero */
+ case PRU_DISCONNECT:
+ E.ATTR(T_DISC_req).e_reason = E_TP_NORMAL_DISC ^ TP_ERROR_MASK;
+ error = DoEvent(T_DISC_req);
+ break;
+
+ case PRU_BIND:
+ error = tp_pcbbind(tpcb, nam);
+ break;
+
+ case PRU_LISTEN:
+ if (tpcb->tp_state != TP_CLOSED || tpcb->tp_lsuffixlen == 0 ||
+ tpcb->tp_next == 0)
+ error = EINVAL;
+ else {
+ register struct tp_pcb **tt;
+ remque(tpcb);
+ tpcb->tp_next = tpcb->tp_prev = tpcb;
+ for (tt = &tp_listeners; *tt; tt = &((*tt)->tp_nextlisten))
+ if ((*tt)->tp_lsuffixlen)
+ break;
+ tpcb->tp_nextlisten = *tt;
+ *tt = tpcb;
+ error = DoEvent(T_LISTEN_req);
+ }
+ break;
+
+ case PRU_CONNECT2:
+ error = EOPNOTSUPP; /* for unix domain sockets */
+ break;
+
+ case PRU_CONNECT:
+ IFTRACE(D_CONN)
+ tptraceTPCB(TPPTmisc,
+ "PRU_CONNECT: so 0x%x *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x",
+ tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen,
+ tpcb->tp_class);
+ ENDTRACE
+ IFDEBUG(D_CONN)
+ printf("PRU_CONNECT: so *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x",
+ tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen,
+ tpcb->tp_class);
+ ENDDEBUG
+ if (tpcb->tp_lsuffixlen == 0) {
+ if (error = tp_pcbbind(tpcb, MNULL)) {
+ IFDEBUG(D_CONN)
+ printf("pcbbind returns error 0x%x\n", error);
+ ENDDEBUG
+ break;
+ }
+ }
+ IFDEBUG(D_CONN)
+ printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb);
+ dump_buf(tpcb->tp_npcb, 16);
+ ENDDEBUG
+ if (error = tp_route_to(nam, tpcb, /* channel */0))
+ break;
+ IFDEBUG(D_CONN)
+ printf(
+ "PRU_CONNECT after tpcb 0x%x so 0x%x npcb 0x%x flags 0x%x\n",
+ tpcb, so, tpcb->tp_npcb, tpcb->tp_flags);
+ printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb);
+ dump_buf(tpcb->tp_npcb, 16);
+ ENDDEBUG
+ if (tpcb->tp_fsuffixlen == 0) {
+ /* didn't set peer extended suffix */
+ (tpcb->tp_nlproto->nlp_getsufx)(tpcb->tp_npcb, &tpcb->tp_fsuffixlen,
+ tpcb->tp_fsuffix, TP_FOREIGN);
+ }
+ if (tpcb->tp_state == TP_CLOSED) {
+ soisconnecting(so);
+ error = DoEvent(T_CONN_req);
+ } else {
+ (tpcb->tp_nlproto->nlp_pcbdisc)(tpcb->tp_npcb);
+ error = EISCONN;
+ }
+ IFPERF(tpcb)
+ u_int lsufx, fsufx;
+ lsufx = *(u_short *)(tpcb->tp_lsuffix);
+ fsufx = *(u_short *)(tpcb->tp_fsuffix);
+
+ tpmeas(tpcb->tp_lref,
+ TPtime_open | (tpcb->tp_xtd_format << 4),
+ &time, lsufx, fsufx, tpcb->tp_fref);
+ ENDPERF
+ break;
+
+ case PRU_ACCEPT:
+ (tpcb->tp_nlproto->nlp_getnetaddr)(tpcb->tp_npcb, nam, TP_FOREIGN);
+ IFDEBUG(D_REQUEST)
+ printf("ACCEPT PEERADDDR:");
+ dump_buf(mtod(nam, char *), nam->m_len);
+ ENDDEBUG
+ IFPERF(tpcb)
+ u_int lsufx, fsufx;
+ lsufx = *(u_short *)(tpcb->tp_lsuffix);
+ fsufx = *(u_short *)(tpcb->tp_fsuffix);
+
+ tpmeas(tpcb->tp_lref, TPtime_open,
+ &time, lsufx, fsufx, tpcb->tp_fref);
+ ENDPERF
+ break;
+
+ case PRU_RCVD:
+ if (so->so_state & SS_ISCONFIRMING) {
+ if (tpcb->tp_state == TP_CONFIRMING)
+ error = tp_confirm(tpcb);
+ break;
+ }
+ IFTRACE(D_DATA)
+ tptraceTPCB(TPPTmisc,
+ "RCVD BF: lcredit sent_lcdt cc hiwat \n",
+ tpcb->tp_lcredit, tpcb->tp_sent_lcdt,
+ so->so_rcv.sb_cc, so->so_rcv.sb_hiwat);
+ LOCAL_CREDIT(tpcb);
+ tptraceTPCB(TPPTmisc,
+ "PRU_RCVD AF sbspace lcredit hiwat cc",
+ sbspace(&so->so_rcv), tpcb->tp_lcredit,
+ so->so_rcv.sb_cc, so->so_rcv.sb_hiwat);
+ ENDTRACE
+ IFDEBUG(D_REQUEST)
+ printf("RCVD: cc %d space %d hiwat %d\n",
+ so->so_rcv.sb_cc, sbspace(&so->so_rcv),
+ so->so_rcv.sb_hiwat);
+ ENDDEBUG
+ if (((long)nam) & MSG_OOB)
+ error = DoEvent(T_USR_Xrcvd);
+ else
+ error = DoEvent(T_USR_rcvd);
+ break;
+
+ case PRU_RCVOOB:
+ if ((so->so_state & SS_ISCONNECTED) == 0) {
+ error = ENOTCONN;
+ break;
+ }
+ if (! tpcb->tp_xpd_service) {
+ error = EOPNOTSUPP;
+ break;
+ }
+ /* kludge - nam is really flags here */
+ error = tp_rcvoob(tpcb, so, m, outflags, (long)nam);
+ break;
+
+ case PRU_SEND:
+ case PRU_SENDOOB:
+ if (controlp) {
+ error = tp_snd_control(controlp, so, &m);
+ controlp = NULL;
+ if (error)
+ break;
+ }
+ if ((so->so_state & SS_ISCONFIRMING) &&
+ (tpcb->tp_state == TP_CONFIRMING) &&
+ (error = tp_confirm(tpcb)))
+ break;
+ if (req == PRU_SENDOOB) {
+ error = (tpcb->tp_xpd_service == 0) ?
+ EOPNOTSUPP : tp_sendoob(tpcb, so, m, outflags);
+ break;
+ }
+ if (m == 0)
+ break;
+ if (m->m_flags & M_EOR) {
+ eotsdu = 1;
+ m->m_flags &= ~M_EOR;
+ }
+ if (eotsdu == 0 && m->m_pkthdr.len == 0)
+ break;
+ if (tpcb->tp_state != TP_AKWAIT && tpcb->tp_state != TP_OPEN) {
+ error = ENOTCONN;
+ break;
+ }
+ /*
+ * The protocol machine copies mbuf chains,
+ * prepends headers, assigns seq numbers, and
+ * puts the packets on the device.
+ * When they are acked they are removed from the socket buf.
+ *
+ * sosend calls this up until sbspace goes negative.
+ * Sbspace may be made negative by appending this mbuf chain,
+ * possibly by a whole cluster.
+ */
+ {
+ /*
+ * Could have eotsdu and no data.(presently MUST have
+ * an mbuf though, even if its length == 0)
+ */
+ int totlen = m->m_pkthdr.len;
+ struct sockbuf *sb = &so->so_snd;
+ IFPERF(tpcb)
+ PStat(tpcb, Nb_from_sess) += totlen;
+ tpmeas(tpcb->tp_lref, TPtime_from_session, 0, 0,
+ PStat(tpcb, Nb_from_sess), totlen);
+ ENDPERF
+ IFDEBUG(D_SYSCALL)
+ printf(
+ "PRU_SEND: eot %d before sbappend 0x%x len 0x%x to sb @ 0x%x\n",
+ eotsdu, m, totlen, sb);
+ dump_mbuf(sb->sb_mb, "so_snd.sb_mb");
+ dump_mbuf(m, "m : to be added");
+ ENDDEBUG
+ tp_packetize(tpcb, m, eotsdu);
+ IFDEBUG(D_SYSCALL)
+ printf("PRU_SEND: eot %d after sbappend 0x%x\n", eotsdu, m);
+ dump_mbuf(sb->sb_mb, "so_snd.sb_mb");
+ ENDDEBUG
+ if (tpcb->tp_state == TP_OPEN)
+ error = DoEvent(T_DATA_req);
+ IFDEBUG(D_SYSCALL)
+ printf("PRU_SEND: after driver error 0x%x \n",error);
+ printf("so_snd 0x%x cc 0t%d mbcnt 0t%d\n",
+ sb, sb->sb_cc, sb->sb_mbcnt);
+ dump_mbuf(sb->sb_mb, "so_snd.sb_mb after driver");
+ ENDDEBUG
+ }
+ break;
+
+ case PRU_SOCKADDR:
+ (tpcb->tp_nlproto->nlp_getnetaddr)(tpcb->tp_npcb, nam, TP_LOCAL);
+ break;
+
+ case PRU_PEERADDR:
+ (tpcb->tp_nlproto->nlp_getnetaddr)(tpcb->tp_npcb, nam, TP_FOREIGN);
+ break;
+
+ case PRU_CONTROL:
+ error = EOPNOTSUPP;
+ break;
+
+ case PRU_PROTOSEND:
+ case PRU_PROTORCV:
+ case PRU_SENSE:
+ case PRU_SLOWTIMO:
+ case PRU_FASTTIMO:
+ error = EOPNOTSUPP;
+ break;
+
+ default:
+#ifdef ARGO_DEBUG
+ printf("tp_usrreq UNKNOWN PRU %d\n", req);
+#endif /* ARGO_DEBUG */
+ error = EOPNOTSUPP;
+ }
+
+ IFDEBUG(D_REQUEST)
+ printf("%s, so 0x%x, tpcb 0x%x, error %d, state %d\n",
+ "returning from tp_usrreq", so, tpcb, error,
+ tpcb ? tpcb->tp_state : 0);
+ ENDDEBUG
+ IFTRACE(D_REQUEST)
+ tptraceTPCB(TPPTusrreq, "END req so m state [", req, so, m,
+ tpcb ? tpcb->tp_state : 0);
+ ENDTRACE
+ if (controlp) {
+ m_freem(controlp);
+ printf("control data unexpectedly retained in tp_usrreq()");
+ }
+ splx(s);
+ return error;
+}
+tp_ltrace(so, uio)
+struct socket *so;
+struct uio *uio;
+{
+ IFTRACE(D_DATA)
+ register struct tp_pcb *tpcb = sototpcb(so);
+ if (tpcb) {
+ tptraceTPCB(TPPTmisc, "sosend so resid iovcnt", so,
+ uio->uio_resid, uio->uio_iovcnt, 0);
+ }
+ ENDTRACE
+}
+
+tp_confirm(tpcb)
+register struct tp_pcb *tpcb;
+{
+ struct tp_event E;
+ if (tpcb->tp_state == TP_CONFIRMING)
+ return DoEvent(T_ACPT_req);
+ printf("Tp confirm called when not confirming; tpcb 0x%x, state 0x%x\n",
+ tpcb, tpcb->tp_state);
+ return 0;
+}
+
+/*
+ * Process control data sent with sendmsg()
+ */
+tp_snd_control(m, so, data)
+ struct mbuf *m;
+ struct socket *so;
+ register struct mbuf **data;
+{
+ register struct cmsghdr *ch;
+ int error = 0;
+
+ if (m && m->m_len) {
+ ch = mtod(m, struct cmsghdr *);
+ m->m_len -= sizeof (*ch);
+ m->m_data += sizeof (*ch);
+ error = tp_ctloutput(PRCO_SETOPT,
+ so, ch->cmsg_level, ch->cmsg_type, &m);
+ if (ch->cmsg_type == TPOPT_DISC_DATA) {
+ if (data && *data) {
+ m_freem(*data);
+ *data = 0;
+ }
+ error = tp_usrreq(so, PRU_DISCONNECT, (struct mbuf *)0,
+ (caddr_t)0, (struct mbuf *)0);
+ }
+ }
+ if (m)
+ m_freem(m);
+ return error;
+}