136420Ssklower /*********************************************************** 236420Ssklower 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 $ 3236420Ssklower * 3336420Ssklower * tp_usrreq(), the fellow that gets called from most of the socket code. 3436420Ssklower * Pretty straighforward. 3536420Ssklower * THe only really awful stuff here is the OOB processing, which is done 3636420Ssklower * wholly here. 3736420Ssklower * tp_rcvoob() and tp_sendoob() are contained here and called by tp_usrreq(). 3836420Ssklower */ 3936420Ssklower 4036420Ssklower #ifndef lint 4136420Ssklower static char *rcsid = "$Header: tp_usrreq.c,v 5.4 88/11/18 17:29:18 nhall Exp $"; 4236420Ssklower #endif lint 4336420Ssklower 4436420Ssklower #include "param.h" 4536420Ssklower #include "systm.h" 4636420Ssklower #include "dir.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 55*37469Ssklower #include "tp_param.h" 56*37469Ssklower #include "tp_timer.h" 57*37469Ssklower #include "tp_stat.h" 58*37469Ssklower #include "tp_seq.h" 59*37469Ssklower #include "tp_ip.h" 60*37469Ssklower #include "tp_pcb.h" 61*37469Ssklower #include "argo_debug.h" 62*37469Ssklower #include "tp_trace.h" 63*37469Ssklower #include "tp_meas.h" 64*37469Ssklower #include "iso.h" 65*37469Ssklower #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) { 94*37469Ssklower printf("%x : Len %x Data %x A %x Nx %x Tp %x\n", 95*37469Ssklower 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; 146*37469Ssklower register struct sockbuf *sb = &so->so_rcv; 14736420Ssklower struct tp_event E; 14836420Ssklower int error = 0; 149*37469Ssklower 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 sblock(sb); 16136420Ssklower 16236420Ssklower if ((((so->so_state & SS_ISCONNECTED) == 0) 16336420Ssklower || (so->so_state & SS_ISDISCONNECTING) != 0) && 16436420Ssklower (so->so_proto->pr_flags & PR_CONNREQUIRED)) { 16536420Ssklower return ENOTCONN; 16636420Ssklower } 16736420Ssklower 168*37469Ssklower /* Take the first mbuf off the chain. 169*37469Ssklower * Each XPD TPDU gives you a complete TSDU so the chains don't get 170*37469Ssklower * coalesced, but one TSDU may span several mbufs. 171*37469Ssklower * Nevertheless, since n should have a most 16 bytes, it 172*37469Ssklower * will fit into m. (size was checked in tp_input() ) 173*37469Ssklower */ 174*37469Ssklower 175*37469Ssklower /* 176*37469Ssklower * Code for excision of OOB data should be added to 177*37469Ssklower * uipc_socket2.c (like sbappend). 178*37469Ssklower */ 179*37469Ssklower 180*37469Ssklower for (nn = &sb->sb_mb; n = *nn; nn = &n->m_act) 181*37469Ssklower if (n->m_type == MT_OOBDATA) 182*37469Ssklower break; 183*37469Ssklower 184*37469Ssklower if (n == 0) { 18536420Ssklower ASSERT( (tpcb->tp_flags & TPF_DISC_DATA_IN) == 0 ); 18636420Ssklower IFDEBUG(D_XPD) 18736420Ssklower printf("RCVOOB: empty queue!\n"); 18836420Ssklower ENDDEBUG 18936420Ssklower if (so->so_state & SS_NBIO) { 19036420Ssklower return EWOULDBLOCK; 19136420Ssklower } 19236420Ssklower sbunlock(sb); 19336420Ssklower sbwait(sb); 19436420Ssklower goto restart; 19536420Ssklower } 19636420Ssklower m->m_len = 0; 19736420Ssklower 19836420Ssklower /* Assuming at most one xpd tpdu is in the buffer at once */ 19936420Ssklower while ( n != MNULL ) { 20036420Ssklower m->m_len += n->m_len; 201*37469Ssklower bcopy(mtod(n, caddr_t), mtod(m, caddr_t), (unsigned)n->m_len); 202*37469Ssklower m->m_data += n->m_len; /* so mtod() in bcopy() above gives right addr */ 20336420Ssklower n = n->m_next; 20436420Ssklower } 205*37469Ssklower m->m_data = m->m_dat; 206*37469Ssklower m->m_flags |= M_EOR; 20736420Ssklower 20836420Ssklower IFDEBUG(D_XPD) 20936420Ssklower printf("tp_rcvoob: xpdlen 0x%x\n", m->m_len); 21036420Ssklower dump_mbuf(so->so_rcv.sb_mb, "RCVOOB: Rcv socketbuf"); 21136420Ssklower dump_mbuf(sb->sb_mb, "RCVOOB: Xrcv socketbuf"); 21236420Ssklower ENDDEBUG 21336420Ssklower 214*37469Ssklower if( (inflags & MSG_PEEK) == 0 ) { 215*37469Ssklower n = *nn; 216*37469Ssklower *nn = n->m_act; 217*37469Ssklower sb->sb_cc -= m->m_len; 218*37469Ssklower } 21936420Ssklower 22036420Ssklower release: 22136420Ssklower sbunlock(sb); 22236420Ssklower 22336420Ssklower IFTRACE(D_XPD) 22436420Ssklower tptraceTPCB(TPPTmisc, "PRU_RCVOOB @ release sb_cc m_len", 22536420Ssklower tpcb->tp_Xrcv.sb_cc, m->m_len,0,0 ); 22636420Ssklower ENDTRACE 22736420Ssklower if (error == 0) 22836420Ssklower error = DoEvent(T_USR_Xrcvd); 22936420Ssklower return error; 23036420Ssklower } 23136420Ssklower 23236420Ssklower /* 23336420Ssklower * CALLED FROM: 23436420Ssklower * tp_usrreq(), PRU_SENDOOB 23536420Ssklower * FUNCTION and ARGUMENTS: 23636420Ssklower * Send what's in the mbuf chain (m) as an XPD TPDU. 23736420Ssklower * The mbuf may not contain more then 16 bytes of data. 23836420Ssklower * XPD TSDUs aren't segmented, so they translate into 23936420Ssklower * exactly one XPD TPDU, with EOT bit set. 24036420Ssklower * RETURN VALUE: 24136420Ssklower * EWOULDBLOCK if socket is in non-blocking mode and the previous 24236420Ssklower * xpd data haven't been acked yet. 24336420Ssklower * EMSGSIZE if trying to send > max-xpd bytes (16) 24436420Ssklower * ENOBUFS if ran out of mbufs 24536420Ssklower */ 24636420Ssklower tp_sendoob(tpcb, so, xdata, outflags) 24736420Ssklower struct tp_pcb *tpcb; 24836420Ssklower register struct socket *so; 24936420Ssklower register struct mbuf *xdata; 25036420Ssklower int *outflags; /* not used */ 25136420Ssklower { 25236420Ssklower /* 25336420Ssklower * Each mbuf chain represents a sequence # in the XPD seq space. 25436420Ssklower * The first one in the queue has sequence # tp_Xuna. 25536420Ssklower * When we add to the XPD queue, we stuff a zero-length 25636420Ssklower * mbuf (mark) into the DATA queue, with its sequence number in m_next 25736420Ssklower * to be assigned to this XPD tpdu, so data xfer can stop 25836420Ssklower * when it reaches the zero-length mbuf if this XPD TPDU hasn't 25936420Ssklower * yet been acknowledged. 26036420Ssklower */ 26136420Ssklower register struct sockbuf *sb = &(tpcb->tp_Xsnd); 26236420Ssklower register struct mbuf *xmark; 26336420Ssklower register int len=0; 26436420Ssklower struct tp_event E; 26536420Ssklower 26636420Ssklower IFDEBUG(D_XPD) 26736420Ssklower printf("tp_sendoob:"); 26836420Ssklower if(xdata) 26936420Ssklower printf("xdata len 0x%x\n", xdata->m_len); 27036420Ssklower ENDDEBUG 27136420Ssklower oob_again: 27236420Ssklower /* DO NOT LOCK the Xsnd buffer!!!! You can have at MOST one 27336420Ssklower * socket buf locked at any time!!! (otherwise you might 27436420Ssklower * sleep() in sblock() w/ a signal pending and cause the 27536420Ssklower * system call to be aborted w/ a locked socketbuf, which 27636420Ssklower * is a problem. So the so_snd buffer lock 27736420Ssklower * (done in sosend()) serves as the lock for Xpd. 27836420Ssklower */ 27936420Ssklower if (sb->sb_mb) { /* anything already in this sockbuf? */ 28036420Ssklower if (so->so_state & SS_NBIO) { 28136420Ssklower return EWOULDBLOCK; 28236420Ssklower } 28336420Ssklower sbunlock(&so->so_snd); 28436420Ssklower sbwait(&so->so_snd); 28536420Ssklower sblock(&so->so_snd); 28636420Ssklower goto oob_again; 28736420Ssklower } 28836420Ssklower 28936420Ssklower if (xdata == (struct mbuf *)0) { 29036420Ssklower /* empty xpd packet */ 291*37469Ssklower MGETHDR(xdata, M_WAIT, MT_OOBDATA); 29236420Ssklower if (xdata == NULL) { 29336420Ssklower return ENOBUFS; 29436420Ssklower } 29536420Ssklower xdata->m_len = 0; 296*37469Ssklower xdata->m_pkthdr.len = 0; 29736420Ssklower } 29836420Ssklower IFDEBUG(D_XPD) 29936420Ssklower printf("tp_sendoob 1:"); 30036420Ssklower if(xdata) 30136420Ssklower printf("xdata len 0x%x\n", xdata->m_len); 30236420Ssklower ENDDEBUG 30336420Ssklower xmark = xdata; /* temporary use of variable xmark */ 30436420Ssklower while (xmark) { 30536420Ssklower len += xmark->m_len; 30636420Ssklower xmark = xmark->m_next; 30736420Ssklower } 30836420Ssklower if (len > TP_MAX_XPD_DATA) { 30936420Ssklower return EMSGSIZE; 31036420Ssklower } 31136420Ssklower IFDEBUG(D_XPD) 31236420Ssklower printf("tp_sendoob 2:"); 31336420Ssklower if(xdata) 31436420Ssklower printf("xdata len 0x%x\n", len); 31536420Ssklower ENDDEBUG 31636420Ssklower 31736420Ssklower 31836420Ssklower IFTRACE(D_XPD) 31936420Ssklower tptraceTPCB(TPPTmisc, "XPD mark m_next ", xmark->m_next, 0, 0, 0); 32036420Ssklower ENDTRACE 32136420Ssklower 32236420Ssklower sbappendrecord(sb, xdata); 32336420Ssklower 32436420Ssklower IFDEBUG(D_XPD) 32536420Ssklower printf("tp_sendoob len 0x%x\n", len); 32636420Ssklower dump_mbuf(so->so_snd.sb_mb, "XPD request Regular sndbuf:"); 32736420Ssklower dump_mbuf(tpcb->tp_Xsnd.sb_mb, "XPD request Xsndbuf:"); 32836420Ssklower ENDDEBUG 32936420Ssklower return DoEvent(T_XPD_req); 33036420Ssklower 33136420Ssklower } 33236420Ssklower 33336420Ssklower /* 33436420Ssklower * CALLED FROM: 33536420Ssklower * the socket routines 33636420Ssklower * FUNCTION and ARGUMENTS: 33736420Ssklower * Handles all "user requests" except the [gs]ockopts() requests. 33836420Ssklower * The argument (req) is the request type (PRU*), 33936420Ssklower * (m) is an mbuf chain, generally used for send and 34036420Ssklower * receive type requests only. 34136420Ssklower * (nam) is used for addresses usually, in particular for the bind request. 34236420Ssklower * 34336420Ssklower * The last argument (rights in most usrreq()s) has been stolen for 34436420Ssklower * returning flags values. Since rights can't be passed around w/ tp, 34536420Ssklower * this field is used only for RCVOOB user requests, and is assumed 34636420Ssklower * to be either 0 (as soreceive() would have it) or a ptr to the int flags 34736420Ssklower * (as recvv()'s version of soreceive() would have it 34836420Ssklower */ 34936420Ssklower /*ARGSUSED*/ 35036420Ssklower ProtoHook 351*37469Ssklower tp_usrreq(so, req, m, nam, rightsp, controlp) 35236420Ssklower struct socket *so; 35336420Ssklower u_int req; 354*37469Ssklower struct mbuf *m, *nam, *rightsp, *controlp; 35536420Ssklower { 35636420Ssklower register struct tp_pcb *tpcb = sototpcb(so); 35736420Ssklower int s = splnet(); 35836420Ssklower int error = 0; 359*37469Ssklower int flags, *outflags = &flags; 36036420Ssklower u_long eotsdu = 0; 36136420Ssklower struct tp_event E; 36236420Ssklower 36336420Ssklower IFDEBUG(D_REQUEST) 36436420Ssklower printf("usrreq(0x%x,%d,0x%x,0x%x,0x%x)\n",so,req,m,nam,outflags); 36536420Ssklower if(so->so_error) 36636420Ssklower printf("WARNING!!! so->so_error is 0x%x\n", so->so_error); 36736420Ssklower ENDDEBUG 36836420Ssklower IFTRACE(D_REQUEST) 36936420Ssklower tptraceTPCB(TPPTusrreq, "req so m state [", req, so, m, 37036420Ssklower tpcb?tpcb->tp_state:0); 37136420Ssklower ENDTRACE 37236420Ssklower 37336420Ssklower if ((u_int)tpcb == 0 && req != PRU_ATTACH) { 37436420Ssklower IFTRACE(D_REQUEST) 37536420Ssklower tptraceTPCB(TPPTusrreq, "req failed NO TPCB[", 0, 0, 0, 0); 37636420Ssklower ENDTRACE 37736420Ssklower splx(s); 37836420Ssklower return ENOTCONN; 37936420Ssklower } 38036420Ssklower 38136420Ssklower switch (req) { 38236420Ssklower 38336420Ssklower case PRU_ATTACH: 38436420Ssklower if (tpcb) { 38536420Ssklower error = EISCONN; 38636420Ssklower break; 38736420Ssklower } 38836420Ssklower if( error = tp_attach(so, so->so_proto->pr_domain->dom_family ) ) 38936420Ssklower break; 39036420Ssklower tpcb = sototpcb(so); 39136420Ssklower break; 39236420Ssklower 39336420Ssklower case PRU_ABORT: /* called from close() */ 39436420Ssklower /* called for each incoming connect queued on the 39536420Ssklower * parent (accepting) socket 39636420Ssklower */ 39736420Ssklower if( tpcb->tp_state == TP_OPEN ) { 39836420Ssklower E.ATTR(T_DISC_req).e_reason = E_TP_NO_SESSION; 39936420Ssklower error = DoEvent(T_DISC_req); /* pretend it was a close() */ 40036420Ssklower break; 40136420Ssklower } /* else DROP THROUGH */ 40236420Ssklower 40336420Ssklower case PRU_DETACH: /* called from close() */ 40436420Ssklower /* called only after disconnect was called */ 40536420Ssklower error = DoEvent(T_DETACH); 406*37469Ssklower if (tpcb->tp_state == TP_CLOSED) { 407*37469Ssklower free((caddr_t)tpcb, M_PCB); 408*37469Ssklower tpcb = 0; 409*37469Ssklower } 41036420Ssklower break; 41136420Ssklower 41236420Ssklower case PRU_SHUTDOWN: 41336420Ssklower /* recv end may have been released; local credit might be zero */ 41436420Ssklower case PRU_DISCONNECT: 41536420Ssklower E.ATTR(T_DISC_req).e_reason = E_TP_NORMAL_DISC; 41636420Ssklower error = DoEvent(T_DISC_req); 41736420Ssklower break; 41836420Ssklower 41936420Ssklower case PRU_BIND: 42036420Ssklower error = (tpcb->tp_nlproto->nlp_pcbbind)( so->so_pcb, nam ); 42136420Ssklower if (error == 0) { 422*37469Ssklower (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen, 423*37469Ssklower tpcb->tp_lsuffix, TP_LOCAL ); 42436420Ssklower } 42536420Ssklower break; 42636420Ssklower 42736420Ssklower case PRU_LISTEN: 42836420Ssklower if ( *SHORT_LSUFXP(tpcb) == (short)0 ) { 42936420Ssklower /* note: this suffix is independent of the extended suffix */ 43036420Ssklower if( error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL) ) 43136420Ssklower break; 43236420Ssklower } 43336420Ssklower if( tpcb->tp_lsuffixlen == 0) { 434*37469Ssklower (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen, 435*37469Ssklower tpcb->tp_lsuffix, TP_LOCAL ); 43636420Ssklower } 43736420Ssklower IFDEBUG(D_TPISO) 43836420Ssklower if(tpcb->tp_state != TP_CLOSED) 43936420Ssklower printf("LISTEN ERROR: state 0x%x\n", tpcb->tp_state); 44036420Ssklower ENDDEBUG 44136420Ssklower error = DoEvent(T_LISTEN_req); 44236420Ssklower break; 44336420Ssklower 44436420Ssklower case PRU_CONNECT2: 44536420Ssklower error = EOPNOTSUPP; /* for unix domain sockets */ 44636420Ssklower break; 44736420Ssklower 44836420Ssklower case PRU_CONNECT: 44936420Ssklower IFTRACE(D_CONN) 45036420Ssklower tptraceTPCB(TPPTmisc, 451*37469Ssklower "PRU_CONNECT: so 0x%x *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x", 45236420Ssklower tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen, 45336420Ssklower tpcb->tp_class); 45436420Ssklower ENDTRACE 45536420Ssklower IFDEBUG(D_CONN) 45636420Ssklower printf("PRU_CONNECT: so *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x", 45736420Ssklower tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen, 45836420Ssklower tpcb->tp_class); 45936420Ssklower ENDDEBUG 46036420Ssklower if (*SHORT_LSUFXP(tpcb) == (short)0) { 46136420Ssklower /* no bind was done */ 46236420Ssklower /* note: this suffix is independent of the extended suffix */ 46336420Ssklower if( error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL) ) { 46436420Ssklower IFDEBUG(D_CONN) 46536420Ssklower printf("pcbbind returns error 0x%x\n", error ); 46636420Ssklower ENDDEBUG 46736420Ssklower break; 46836420Ssklower } 46936420Ssklower } 470*37469Ssklower if( tpcb->tp_lsuffixlen == 0) { 471*37469Ssklower (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen, 472*37469Ssklower tpcb->tp_lsuffix, TP_LOCAL ); 473*37469Ssklower } 47436420Ssklower 47536420Ssklower IFDEBUG(D_CONN) 47636420Ssklower printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb); 47736420Ssklower dump_buf( tpcb->tp_npcb, 16); 47836420Ssklower ENDDEBUG 47936420Ssklower if( error = tp_route_to( nam, tpcb, /* channel */0) ) 48036420Ssklower break; 48136420Ssklower IFDEBUG(D_CONN) 48236420Ssklower printf( 48336420Ssklower "PRU_CONNECT after tpcb 0x%x so 0x%x npcb 0x%x flags 0x%x\n", 48436420Ssklower tpcb, so, tpcb->tp_npcb, tpcb->tp_flags); 48536420Ssklower printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb); 48636420Ssklower dump_buf( tpcb->tp_npcb, 16); 48736420Ssklower ENDDEBUG 488*37469Ssklower if( tpcb->tp_fsuffixlen == 0) { 48936420Ssklower /* didn't set peer extended suffix */ 490*37469Ssklower (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_fsuffixlen, 491*37469Ssklower tpcb->tp_fsuffix, TP_FOREIGN ); 49236420Ssklower } 49336420Ssklower (void) (tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb, 49436420Ssklower &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0); 49536420Ssklower if( tpcb->tp_state == TP_CLOSED) { 49636420Ssklower soisconnecting(so); 49736420Ssklower error = DoEvent(T_CONN_req); 49836420Ssklower } else { 49936420Ssklower (tpcb->tp_nlproto->nlp_pcbdisc)(so->so_pcb); 50036420Ssklower error = EISCONN; 50136420Ssklower } 50236420Ssklower IFPERF(tpcb) 50336420Ssklower u_int lsufx, fsufx; 50436420Ssklower lsufx = *(u_int *)(tpcb->tp_lsuffix); 50536420Ssklower fsufx = *(u_int *)(tpcb->tp_fsuffix); 50636420Ssklower 50736420Ssklower tpmeas( tpcb->tp_lref, 50836420Ssklower TPtime_open | (tpcb->tp_xtd_format <<4 ), 50936420Ssklower &time, lsufx, fsufx, tpcb->tp_fref); 51036420Ssklower ENDPERF 51136420Ssklower break; 51236420Ssklower 51336420Ssklower case PRU_ACCEPT: 51436420Ssklower /* all this garbage is to keep accept from returning 51536420Ssklower * before the 3-way handshake is done in class 4. 51636420Ssklower * it'll have to be modified for other classes 51736420Ssklower */ 51836420Ssklower IFDEBUG(D_REQUEST) 51936420Ssklower printf("PRU_ACCEPT so_error 0x%x\n", so->so_error); 52036420Ssklower ENDDEBUG 52136420Ssklower so->so_error = 0; 52236420Ssklower if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTED)== 0) { 52336420Ssklower error = EWOULDBLOCK; 52436420Ssklower break; 52536420Ssklower } 52636420Ssklower while ((so->so_state & SS_ISCONNECTED) == 0 && so->so_error == 0) { 52736420Ssklower sleep((caddr_t)&so->so_timeo, PZERO+1); 52836420Ssklower } 52936420Ssklower if (so->so_error) { 53036420Ssklower error = so->so_error; 53136420Ssklower } else { 532*37469Ssklower (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN); 53336420Ssklower IFDEBUG(D_REQUEST) 53436420Ssklower printf("ACCEPT PEERADDDR:"); 535*37469Ssklower dump_buf(mtod(nam, char *), nam->m_len); 53636420Ssklower ENDDEBUG 53736420Ssklower } 53836420Ssklower IFPERF(tpcb) 53936420Ssklower u_int lsufx, fsufx; 54036420Ssklower lsufx = *(u_int *)(tpcb->tp_lsuffix); 54136420Ssklower fsufx = *(u_int *)(tpcb->tp_fsuffix); 54236420Ssklower 54336420Ssklower tpmeas( tpcb->tp_lref, TPtime_open, 54436420Ssklower &time, lsufx, fsufx, tpcb->tp_fref); 54536420Ssklower ENDPERF 54636420Ssklower break; 54736420Ssklower 54836420Ssklower case PRU_RCVD: 54936420Ssklower IFTRACE(D_DATA) 55036420Ssklower tptraceTPCB(TPPTmisc, 55136420Ssklower "RCVD BF: lcredit sent_lcdt cc hiwat \n", 55236420Ssklower tpcb->tp_lcredit, tpcb->tp_sent_lcdt, 55336420Ssklower so->so_rcv.sb_cc, so->so_rcv.sb_hiwat); 55436420Ssklower LOCAL_CREDIT(tpcb); 55536420Ssklower tptraceTPCB(TPPTmisc, 55636420Ssklower "PRU_RCVD AF sbspace lcredit hiwat cc", 55736420Ssklower sbspace(&so->so_rcv), tpcb->tp_lcredit, 55836420Ssklower so->so_rcv.sb_cc, so->so_rcv.sb_hiwat); 55936420Ssklower ENDTRACE 560*37469Ssklower IFDEBUG(D_REQUEST) 561*37469Ssklower printf("RCVD: cc %d space %d hiwat %d\n", 562*37469Ssklower so->so_rcv.sb_cc, sbspace(&so->so_rcv), 563*37469Ssklower so->so_rcv.sb_hiwat); 564*37469Ssklower ENDDEBUG 565*37469Ssklower if (((int)nam) & MSG_OOB) 566*37469Ssklower error = DoEvent(T_USR_Xrcvd); 567*37469Ssklower else 568*37469Ssklower error = DoEvent(T_USR_rcvd); 56936420Ssklower break; 57036420Ssklower 57136420Ssklower case PRU_RCVOOB: 57236420Ssklower if ((so->so_state & SS_ISCONNECTED) == 0) { 57336420Ssklower error = ENOTCONN; 57436420Ssklower break; 57536420Ssklower } 57636420Ssklower if( ! tpcb->tp_xpd_service ) { 57736420Ssklower error = EOPNOTSUPP; 57836420Ssklower break; 57936420Ssklower } 58036420Ssklower /* kludge - nam is really flags here */ 58136420Ssklower error = tp_rcvoob(tpcb, so, m, outflags, (int)nam); 58236420Ssklower break; 58336420Ssklower 58436420Ssklower case PRU_SENDOOB: 585*37469Ssklower if (controlp && (error = tp_snd_control(controlp, so, &m))) 58636420Ssklower break; 587*37469Ssklower if (m == 0) 588*37469Ssklower break; 589*37469Ssklower if (so->so_state & SS_ISCONFIRMING) 590*37469Ssklower tp_confirm(); 59136420Ssklower if( ! tpcb->tp_xpd_service ) { 59236420Ssklower error = EOPNOTSUPP; 59336420Ssklower break; 59436420Ssklower } 59536420Ssklower error = tp_sendoob(tpcb, so, m, outflags); 59636420Ssklower break; 59736420Ssklower 59836420Ssklower case PRU_SEND: 59936420Ssklower /* 60036420Ssklower * The protocol machine copies mbuf chains, 60136420Ssklower * prepends headers, assigns seq numbers, and 60236420Ssklower * puts the packets on the device. 60336420Ssklower * When they are acked they are removed from the socket buf. 60436420Ssklower * 60536420Ssklower * sosend calls this up until sbspace goes negative. 60636420Ssklower * Sbspace may be made negative by appending this mbuf chain, 60736420Ssklower * possibly by a whole cluster. 60836420Ssklower */ 609*37469Ssklower if (controlp && (error = tp_snd_control(controlp, so, &m))) 61036420Ssklower break; 611*37469Ssklower if (m == 0) 612*37469Ssklower break; 613*37469Ssklower if (so->so_state & SS_ISCONFIRMING) 614*37469Ssklower tp_confirm(); 61536420Ssklower { 616*37469Ssklower register struct mbuf *n = m; 61736420Ssklower register int len=0; 61836420Ssklower register struct sockbuf *sb = &so->so_snd; 619*37469Ssklower int maxsize = tpcb->tp_l_tpdusize 620*37469Ssklower - tp_headersize(DT_TPDU_type, tpcb) 621*37469Ssklower - (tpcb->tp_use_checksum?4:0) ; 622*37469Ssklower int totlen = n->m_pkthdr.len; 62336420Ssklower 624*37469Ssklower /* 625*37469Ssklower * Could have eotsdu and no data.(presently MUST have 626*37469Ssklower * an mbuf though, even if its length == 0) 627*37469Ssklower */ 628*37469Ssklower if (n->m_flags & M_EOR) 629*37469Ssklower eotsdu = 1; 63036420Ssklower IFPERF(tpcb) 631*37469Ssklower PStat(tpcb, Nb_from_sess) += totlen; 63236420Ssklower tpmeas(tpcb->tp_lref, TPtime_from_session, 0, 0, 633*37469Ssklower PStat(tpcb, Nb_from_sess), totlen); 63436420Ssklower ENDPERF 63536420Ssklower IFDEBUG(D_SYSCALL) 63636420Ssklower printf( 63736420Ssklower "PRU_SEND: eot %d before sbappend 0x%x len 0x%x to sb @ 0x%x\n", 638*37469Ssklower eotsdu, m,len, sb); 63936420Ssklower dump_mbuf(sb->sb_mb, "so_snd.sb_mb"); 64036420Ssklower dump_mbuf(m, "m : to be added"); 64136420Ssklower ENDDEBUG 642*37469Ssklower /* 643*37469Ssklower * Pre-packetize the data in the sockbuf 644*37469Ssklower * according to negotiated mtu. Do it here 645*37469Ssklower * where we can safely wait for mbufs. 64636420Ssklower */ 647*37469Ssklower while (n->m_pkthdr.len > maxsize) { 648*37469Ssklower struct mbuf *nn 649*37469Ssklower = m_copym(n, 0, maxsize, M_WAIT); 650*37469Ssklower if (eotsdu) 651*37469Ssklower n->m_flags &= ~M_EOR; 652*37469Ssklower sbappendrecord(sb, nn); 653*37469Ssklower m_adj(n, maxsize); 654*37469Ssklower } 655*37469Ssklower sbappendrecord(sb, n); 65636420Ssklower IFDEBUG(D_SYSCALL) 65736420Ssklower printf("PRU_SEND: eot %d after sbappend 0x%x len 0x%x\n", 658*37469Ssklower eotsdu, n, len); 65936420Ssklower dump_mbuf(sb->sb_mb, "so_snd.sb_mb"); 66036420Ssklower ENDDEBUG 66136420Ssklower error = DoEvent(T_DATA_req); 66236420Ssklower IFDEBUG(D_SYSCALL) 66336420Ssklower printf("PRU_SEND: after driver error 0x%x \n",error); 664*37469Ssklower printf("so_snd 0x%x cc 0t%d mbcnt 0t%d\n", 665*37469Ssklower sb, sb->sb_cc, sb->sb_mbcnt); 666*37469Ssklower dump_mbuf(sb->sb_mb, "so_snd.sb_mb after driver"); 66736420Ssklower ENDDEBUG 66836420Ssklower } 66936420Ssklower break; 67036420Ssklower 671*37469Ssklower case PRU_SOCKADDR: 672*37469Ssklower (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_LOCAL); 67336420Ssklower break; 67436420Ssklower 67536420Ssklower case PRU_PEERADDR: 676*37469Ssklower if ((so->so_state & SS_ISCONNECTED) && 677*37469Ssklower (so->so_state & SS_ISDISCONNECTING) == 0) { 678*37469Ssklower (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN); 679*37469Ssklower IFDEBUG(D_REQUEST) 680*37469Ssklower printf("PEERADDDR:"); 681*37469Ssklower dump_buf(mtod(nam, char *), nam->m_len); 682*37469Ssklower ENDDEBUG 68336420Ssklower } else 68436420Ssklower error = ENOTCONN; 68536420Ssklower break; 68636420Ssklower 68736420Ssklower case PRU_CONTROL: 68836420Ssklower error = EOPNOTSUPP; 68936420Ssklower break; 69036420Ssklower 69136420Ssklower case PRU_PROTOSEND: 69236420Ssklower case PRU_PROTORCV: 69336420Ssklower case PRU_SENSE: 69436420Ssklower case PRU_SLOWTIMO: 69536420Ssklower case PRU_FASTTIMO: 69636420Ssklower error = EOPNOTSUPP; 69736420Ssklower break; 69836420Ssklower 69936420Ssklower default: 70036420Ssklower #ifdef ARGO_DEBUG 70136420Ssklower printf("tp_usrreq UNKNOWN PRU %d\n", req); 70236420Ssklower #endif ARGO_DEBUG 70336420Ssklower error = EOPNOTSUPP; 70436420Ssklower } 70536420Ssklower 70636420Ssklower IFDEBUG(D_REQUEST) 70736420Ssklower printf("returning from tp_usrreq(so 0x%x) error 0x%x\n", so, error); 70836420Ssklower ENDDEBUG 70936420Ssklower IFTRACE(D_REQUEST) 71036420Ssklower tptraceTPCB(TPPTusrreq, "END req so m state [", req, so, m, 71136420Ssklower tpcb?0:tpcb->tp_state); 71236420Ssklower ENDTRACE 71336420Ssklower splx(s); 71436420Ssklower return error; 71536420Ssklower } 716*37469Ssklower 717*37469Ssklower /* 718*37469Ssklower * Stub for future negotiated confirmation of connections. 719*37469Ssklower */ 720*37469Ssklower tp_confirm() 721*37469Ssklower { 722*37469Ssklower } 723*37469Ssklower 724*37469Ssklower /* 725*37469Ssklower * Process control data sent with sendmsg() 726*37469Ssklower */ 727*37469Ssklower tp_snd_control(m0, so, data) 728*37469Ssklower register struct mbuf *m0; 729*37469Ssklower struct socket *so; 730*37469Ssklower register struct mbuf **data; 731*37469Ssklower { 732*37469Ssklower register struct tp_control_hdr *ch; 733*37469Ssklower struct mbuf *m; 734*37469Ssklower int error = 0; 735*37469Ssklower 736*37469Ssklower if (m0 && m0->m_len) { 737*37469Ssklower ch = mtod(m0, struct tp_control_hdr *); 738*37469Ssklower m0->m_len -= sizeof (*ch); 739*37469Ssklower m0->m_data += sizeof (*ch); 740*37469Ssklower m = m_copym(m0, 0, M_COPYALL, M_WAIT); 741*37469Ssklower error = tp_ctloutput(PRCO_SETOPT, 742*37469Ssklower so, ch->cmsg_level, ch->cmsg_type, &m); 743*37469Ssklower if (m) 744*37469Ssklower m_freem(m); 745*37469Ssklower if (ch->cmsg_type == TPOPT_DISC_DATA) { 746*37469Ssklower if (data && *data) { 747*37469Ssklower m_freem(*data); 748*37469Ssklower *data = 0; 749*37469Ssklower } 750*37469Ssklower m0 = 0; 751*37469Ssklower error = tp_usrreq(so, PRU_DISCONNECT, m0, (caddr_t)0, m0, m0); 752*37469Ssklower } 753*37469Ssklower } 754*37469Ssklower return error; 755*37469Ssklower } 756