136401Ssklower /*********************************************************** 236401Ssklower Copyright IBM Corporation 1987 336401Ssklower 436401Ssklower All Rights Reserved 536401Ssklower 636401Ssklower Permission to use, copy, modify, and distribute this software and its 736401Ssklower documentation for any purpose and without fee is hereby granted, 836401Ssklower provided that the above copyright notice appear in all copies and that 936401Ssklower both that copyright notice and this permission notice appear in 1036401Ssklower supporting documentation, and that the name of IBM not be 1136401Ssklower used in advertising or publicity pertaining to distribution of the 1236401Ssklower software without specific, written prior permission. 1336401Ssklower 1436401Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 1536401Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 1636401Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 1736401Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 1836401Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 1936401Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 2036401Ssklower SOFTWARE. 2136401Ssklower 2236401Ssklower ******************************************************************/ 2336401Ssklower 2436401Ssklower /* 2536401Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 2636401Ssklower */ 2736401Ssklower /* 2836401Ssklower * ARGO TP 2936401Ssklower * 3036401Ssklower * $Header: tp_input.c,v 5.6 88/11/18 17:27:38 nhall Exp $ 3136401Ssklower * $Source: /usr/argo/sys/netiso/RCS/tp_input.c,v $ 3236401Ssklower * 3336401Ssklower * tp_input() gets an mbuf chain from ip. Actually, not directly 3436401Ssklower * from ip, because ip calls a net-level routine that strips off 3536401Ssklower * the net header and then calls tp_input(), passing the proper type 3636401Ssklower * of addresses for the address family in use (how it figures out 3736401Ssklower * which AF is not yet determined. 3836401Ssklower * 3936401Ssklower * Decomposing the tpdu is some of the most laughable code. The variable-length 4036401Ssklower * parameters and the problem of non-aligned memory references 4136401Ssklower * necessitates such abominations as the macros WHILE_OPTIONS (q.v. below) 4236401Ssklower * to loop through the header and decompose it. 4336401Ssklower * 4436401Ssklower * The routine tp_newsocket() is called when a CR comes in for a listening 4536401Ssklower * socket. tp_input calls sonewconn() and tp_newsocket() to set up the 4636401Ssklower * "child" socket. Most tpcb values are copied from the parent tpcb into 4736401Ssklower * the child. 4836401Ssklower * 4936401Ssklower * Also in here is tp_headersize() (grot) which tells the expected size 5036401Ssklower * of a tp header, to be used by other layers. It's in here because it 5136401Ssklower * uses the static structure tpdu_info. 5236401Ssklower */ 5336401Ssklower 5436401Ssklower #ifndef lint 5536401Ssklower static char *rcsid = "$Header: tp_input.c,v 5.6 88/11/18 17:27:38 nhall Exp $"; 5636401Ssklower #endif lint 5736401Ssklower 5836401Ssklower #include "argoxtwentyfive.h" 5936401Ssklower #include "param.h" 6036401Ssklower #include "mbuf.h" 6136401Ssklower #include "socket.h" 6236401Ssklower #include "socketvar.h" 6336401Ssklower #include "domain.h" 6436401Ssklower #include "protosw.h" 6536401Ssklower #include "errno.h" 6636401Ssklower #include "time.h" 6736401Ssklower #include "kernel.h" 6836401Ssklower #include "types.h" 69*37469Ssklower #include "iso_errno.h" 70*37469Ssklower #include "tp_param.h" 71*37469Ssklower #include "tp_timer.h" 72*37469Ssklower #include "tp_stat.h" 73*37469Ssklower #include "tp_pcb.h" 74*37469Ssklower #include "argo_debug.h" 75*37469Ssklower #include "tp_trace.h" 76*37469Ssklower #include "tp_tpdu.h" 77*37469Ssklower #include "iso.h" 78*37469Ssklower #include "cons.h" 7936401Ssklower 8036401Ssklower int iso_check_csum(), tp_driver(), tp_headersize(), tp_error_emit(); 8136401Ssklower 82*37469Ssklower /* 83*37469Ssklower #ifdef lint 84*37469Ssklower #undef ATTR 85*37469Ssklower #define ATTR(X)ev_number 86*37469Ssklower #endif lint 87*37469Ssklower */ 8836401Ssklower 8936401Ssklower struct mbuf * 9036401Ssklower tp_inputprep(m) 91*37469Ssklower register struct mbuf *m; 9236401Ssklower { 93*37469Ssklower int hdrlen; 9436401Ssklower 9536401Ssklower IFDEBUG(D_TPINPUT) 96*37469Ssklower printf("tp_inputprep: m 0x%x\n", m) ; 9736401Ssklower ENDDEBUG 9836401Ssklower 9936401Ssklower while( m->m_len < 1 ) { 10036401Ssklower if( (m = m_free(m)) == MNULL ) { 10136401Ssklower return (struct mbuf *)0; 10236401Ssklower } 10336401Ssklower } 104*37469Ssklower if(((int)m->m_data) & 0x3) { 105*37469Ssklower /* If we are not 4-byte aligned, we have to be 106*37469Ssklower * above the beginning of the mbuf, and it is ok just 107*37469Ssklower * to slide it back. 108*37469Ssklower */ 109*37469Ssklower caddr_t ocp = m->m_data; 11036401Ssklower 111*37469Ssklower m->m_data = (caddr_t)(((int)m->m_data) & ~0x3); 112*37469Ssklower ovbcopy(ocp, m->m_data, (unsigned)m->m_len); 11336401Ssklower } 11436401Ssklower CHANGE_MTYPE(m, TPMT_DATA); 11536401Ssklower 116*37469Ssklower /* we KNOW that there is at least 1 byte in this mbuf 117*37469Ssklower and that it is hdr->tpdu_li XXXXXXX! */ 11836401Ssklower 119*37469Ssklower hdrlen = 1 + *mtod( m, u_char *); 12036401Ssklower 12136401Ssklower /* 12236401Ssklower * now pull up the whole tp header 12336401Ssklower */ 124*37469Ssklower if ( m->m_len < hdrlen) { 125*37469Ssklower if ((m = m_pullup(m, hdrlen)) == MNULL ) { 12636401Ssklower IncStat(ts_recv_drop); 12736401Ssklower return (struct mbuf *)0; 12836401Ssklower } 12936401Ssklower } 13036401Ssklower IFDEBUG(D_INPUT) 13136401Ssklower printf( 13236401Ssklower " at end: m 0x%x hdr->tpdu_li 0x%x m_len 0x%x\n",m, 133*37469Ssklower hdrlen, m->m_len); 13436401Ssklower ENDDEBUG 13536401Ssklower return m; 13636401Ssklower } 13736401Ssklower 13836401Ssklower /* begin groan 13936401Ssklower * -- this array and the following macros allow you to step through the 14036401Ssklower * parameters of the variable part of a header 14136401Ssklower * note that if for any reason the values of the **_TPDU macros (in tp_events.h) 14236401Ssklower * should change, this array has to be rearranged 14336401Ssklower */ 14436401Ssklower 14536401Ssklower #define TP_LEN_CLASS_0_INDEX 2 14636401Ssklower #define TP_MAX_DATA_INDEX 3 14736401Ssklower 14836401Ssklower static u_char tpdu_info[][4] = 14936401Ssklower { 15036401Ssklower /* length max data len */ 15136401Ssklower /* reg fmt xtd fmt class 0 */ 15236401Ssklower /* UNUSED 0x0 */ 0x0 , 0x0, 0x0, 0x0, 15336401Ssklower /* XPD_TPDU_type 0x1 */ 0x5, 0x8, 0x0, TP_MAX_XPD_DATA, 15436401Ssklower /* XAK_TPDU_type 0x2 */ 0x5 , 0x8, 0x0, 0x0, 15536401Ssklower /* GR_TPDU_type 0x3 */ 0x0 , 0x0, 0x0, 0x0, 15636401Ssklower /* UNUSED 0x4 */ 0x0 , 0x0, 0x0, 0x0, 15736401Ssklower /* UNUSED 0x5 */ 0x0 , 0x0, 0x0, 0x0, 15836401Ssklower /* AK_TPDU_type 0x6 */ 0x5, 0xa, 0x0, 0x0, 15936401Ssklower /* ER_TPDU_type 0x7 */ 0x5, 0x5, 0x0, 0x0, 16036401Ssklower /* DR_TPDU_type 0x8 */ 0x7, 0x7, 0x7, TP_MAX_DR_DATA, 16136401Ssklower /* UNUSED 0x9 */ 0x0 , 0x0, 0x0, 0x0, 16236401Ssklower /* UNUSED 0xa */ 0x0 , 0x0, 0x0, 0x0, 16336401Ssklower /* UNUSED 0xb */ 0x0 , 0x0, 0x0, 0x0, 16436401Ssklower /* DC_TPDU_type 0xc */ 0x6, 0x6, 0x0, 0x0, 16536401Ssklower /* CC_TPDU_type 0xd */ 0x7, 0x7, 0x7, TP_MAX_CC_DATA, 16636401Ssklower /* CR_TPDU_type 0xe */ 0x7, 0x7, 0x7, TP_MAX_CR_DATA, 16736401Ssklower /* DT_TPDU_type 0xf */ 0x5, 0x8, 0x3, 0x0, 16836401Ssklower }; 16936401Ssklower 17036401Ssklower /* 17136401Ssklower * WHENEVER YOU USE THE FOLLOWING MACRO, 17236401Ssklower * BE SURE THE TPDUTYPE IS A LEGIT VALUE FIRST! 17336401Ssklower */ 17436401Ssklower 17536401Ssklower #define WHILE_OPTIONS(P, hdr,format)\ 17636401Ssklower { register caddr_t P;\ 17736401Ssklower P = (caddr_t)(hdr) +\ 17836401Ssklower tpdu_info[(hdr)->tpdu_type][(format)];\ 17936401Ssklower while( P < (caddr_t)(hdr) + (int)((hdr)->tpdu_li) ) { 18036401Ssklower 18136401Ssklower #define END_WHILE_OPTIONS(P)\ 18236401Ssklower P = P + 2 + (int)((struct tp_vbp *)P)->tpv_len ;\ 18336401Ssklower } } 18436401Ssklower 18536401Ssklower #define CHECK(Phrase, Erval, Stat, Whattodo, Loc)\ 18636401Ssklower if(Phrase) { error = (Erval); errloc = (caddr_t)(Loc); IncStat(Stat); \ 18736401Ssklower goto Whattodo; } 18836401Ssklower 18936401Ssklower /* end groan */ 19036401Ssklower 19136401Ssklower /* 19236401Ssklower * NAME: tp_newsocket() 19336401Ssklower * 19436401Ssklower * CALLED FROM: 19536401Ssklower * tp_input() on incoming CR, when a socket w/ the called suffix 19636401Ssklower * is awaiting a connection request 19736401Ssklower * 19836401Ssklower * FUNCTION and ARGUMENTS: 19936401Ssklower * Create a new socket structure, attach to it a new transport pcb, 20036401Ssklower * using a copy of the net level pcb for the parent socket. 20136401Ssklower * (so) is the parent socket. 20236401Ssklower * (fname) is the foreign address (all that's used is the nsap portion) 20336401Ssklower * 20436401Ssklower * RETURN VALUE: 20536401Ssklower * a new socket structure, being this end of the newly formed connection. 20636401Ssklower * 20736401Ssklower * SIDE EFFECTS: 20836401Ssklower * Sets a few things in the tpcb and net level pcb 20936401Ssklower * 21036401Ssklower * NOTES: 21136401Ssklower */ 21236401Ssklower static struct socket * 21336401Ssklower tp_newsocket(so, fname, cons_channel, class_to_use, netservice) 21436401Ssklower struct socket *so; 21536401Ssklower struct sockaddr *fname; 21636401Ssklower u_int cons_channel; 21736401Ssklower u_char class_to_use; 21836401Ssklower u_int netservice; 21936401Ssklower { 22036401Ssklower register struct tp_pcb *tpcb = sototpcb(so); /* old tpcb, needed below */ 22136401Ssklower struct tp_pcb * newtpcb; 22236401Ssklower struct proc * selproc = so->so_rcv.sb_sel; /* kludge for select */ 22336401Ssklower 22436401Ssklower /* 22536401Ssklower * sonewconn() gets a new socket structure, 22636401Ssklower * a new lower layer pcb and a new tpcb, 22736401Ssklower * but the pcbs are unnamed (not bound) 22836401Ssklower */ 22936401Ssklower IFTRACE(D_NEWSOCK) 23036401Ssklower tptraceTPCB(TPPTmisc, "newsock: listg_so,_tpcb selproc, so_head", 23136401Ssklower so, tpcb, selproc, so->so_head); 23236401Ssklower ENDTRACE 23336401Ssklower 23436401Ssklower if ((so = sonewconn(so)) == (struct socket *)0) 23536401Ssklower return so; 23636401Ssklower IFTRACE(D_NEWSOCK) 23736401Ssklower tptraceTPCB(TPPTmisc, "newsock: after newconn so, selproc, so_head", 23836401Ssklower so, selproc, so->so_head, 0); 23936401Ssklower ENDTRACE 24036401Ssklower 24136401Ssklower so->so_rcv.sb_sel = selproc; /* so that soisconnected() after receipt 24236401Ssklower * of the ack will wake this guy up if he's selecting on the 24336401Ssklower * listening socket 24436401Ssklower */ 24536401Ssklower IFDEBUG(D_NEWSOCK) 246*37469Ssklower printf("tp_newsocket(channel 0x%x) after sonewconn so 0x%x \n", 247*37469Ssklower cons_channel, so); 248*37469Ssklower dump_addr(fname); 24936401Ssklower { 25036401Ssklower struct socket *t, *head ; 25136401Ssklower 25236401Ssklower head = so->so_head; 25336401Ssklower t = so; 25436401Ssklower printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n", 25536401Ssklower t, t->so_head, t->so_q0, t->so_q0len); 25636401Ssklower while( (t=t->so_q0) && t!= so && t!= head) 25736401Ssklower printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n", 25836401Ssklower t, t->so_head, t->so_q0, t->so_q0len); 25936401Ssklower } 26036401Ssklower ENDDEBUG 26136401Ssklower 26236401Ssklower /* 26336401Ssklower * before we clobber the old tpcb ptr, get these items from the parent pcb 26436401Ssklower */ 26536401Ssklower newtpcb = sototpcb(so); 26636401Ssklower newtpcb->_tp_param = tpcb->_tp_param; 26736401Ssklower newtpcb->tp_flags = tpcb->tp_flags; 26836401Ssklower newtpcb->tp_lcredit = tpcb->tp_lcredit; 26936401Ssklower newtpcb->tp_l_tpdusize = tpcb->tp_l_tpdusize; 27036401Ssklower newtpcb->tp_lsuffixlen = tpcb->tp_lsuffixlen; 27136401Ssklower bcopy( tpcb->tp_lsuffix, newtpcb->tp_lsuffix, newtpcb->tp_lsuffixlen); 272*37469Ssklower soreserve(so, (u_long)tpcb->tp_winsize, (u_long)tpcb->tp_winsize); 27336401Ssklower 274*37469Ssklower if( /* old */ tpcb->tp_ucddata) { 27536401Ssklower /* 276*37469Ssklower * These data are the connect- , confirm- or disconnect- data. 27736401Ssklower */ 27836401Ssklower struct mbuf *conndata; 27936401Ssklower 280*37469Ssklower conndata = m_copy(tpcb->tp_ucddata, 0, (int)M_COPYALL); 28136401Ssklower IFDEBUG(D_CONN) 28236401Ssklower dump_mbuf(conndata, "conndata after mcopy"); 28336401Ssklower ENDDEBUG 284*37469Ssklower newtpcb->tp_ucddata = conndata; 28536401Ssklower } 28636401Ssklower 28736401Ssklower tpcb = newtpcb; 28836401Ssklower tpcb->tp_state = TP_LISTENING; 28936401Ssklower tpcb->tp_class = class_to_use; 29036401Ssklower tpcb->tp_netservice = netservice; 29136401Ssklower 29236401Ssklower 29336401Ssklower ASSERT( fname != 0 ) ; /* just checking */ 29436401Ssklower if ( fname ) { 29536401Ssklower /* 29636401Ssklower * tp_route_to takes its address argument in the form of an mbuf. 29736401Ssklower */ 29836401Ssklower struct mbuf *m; 29936401Ssklower int err; 30036401Ssklower 30136401Ssklower MGET(m, M_DONTWAIT, MT_SONAME); /* mbuf type used is confusing */ 30236401Ssklower if (m) { 30336401Ssklower /* 30436401Ssklower * this seems a bit grotesque, but tp_route_to expects 30536401Ssklower * an mbuf * instead of simply a sockaddr; it calls the ll 30636401Ssklower * pcb_connect, which expects the name/addr in an mbuf as well. 30736401Ssklower * sigh. 30836401Ssklower */ 309*37469Ssklower bcopy((caddr_t)fname, mtod(m, caddr_t), fname->sa_len); 310*37469Ssklower m->m_len = fname->sa_len; 31136401Ssklower 31236401Ssklower /* grot : have to say the kernel can override params in 31336401Ssklower * the passive open case 31436401Ssklower */ 31536401Ssklower tpcb->tp_dont_change_params = 0; 31636401Ssklower err = tp_route_to( m, tpcb, cons_channel); 31736401Ssklower m_free(m); 31836401Ssklower 31936401Ssklower if (!err) 32036401Ssklower goto ok; 32136401Ssklower } 32236401Ssklower IFDEBUG(D_CONN) 32336401Ssklower printf("tp_route_to FAILED! detaching tpcb 0x%x, so 0x%x\n", 32436401Ssklower tpcb, so); 32536401Ssklower ENDDEBUG 32636401Ssklower (void) tp_detach(tpcb); 32736401Ssklower return 0; 32836401Ssklower } 32936401Ssklower ok: 33036401Ssklower IFDEBUG(D_TPINPUT) 33136401Ssklower printf("tp_newsocket returning so 0x%x, sototpcb(so) 0x%x\n", 33236401Ssklower so, sototpcb(so)); 33336401Ssklower ENDDEBUG 33436401Ssklower return so; 33536401Ssklower } 33636401Ssklower 33736401Ssklower #ifndef CONS 33836401Ssklower tpcons_output() 33936401Ssklower { 34036401Ssklower return(0); 34136401Ssklower } 34236401Ssklower #endif !CONS 34336401Ssklower 34436401Ssklower /* 34536401Ssklower * NAME: tp_input() 34636401Ssklower * 34736401Ssklower * CALLED FROM: 34836401Ssklower * net layer input routine 34936401Ssklower * 35036401Ssklower * FUNCTION and ARGUMENTS: 35136401Ssklower * Process an incoming TPDU (m), finding the associated tpcb if there 35236401Ssklower * is one. Create the appropriate type of event and call the driver. 35336401Ssklower * (faddr) and (laddr) are the foreign and local addresses. 35436401Ssklower * 35536401Ssklower * When tp_input() is called we KNOW that the ENTIRE TP HEADER 35636401Ssklower * has been m_pullup-ed. 35736401Ssklower * 35836401Ssklower * RETURN VALUE: Nada 35936401Ssklower * 36036401Ssklower * SIDE EFFECTS: 36136401Ssklower * When using COSNS it may affect the state of the net-level pcb 36236401Ssklower * 36336401Ssklower * NOTE: 36436401Ssklower * The initial value of acktime is 2 so that we will never 36536401Ssklower * have a 0 value for tp_peer_acktime. It gets used in the 36636401Ssklower * computation of the retransmission timer value, and so it 36736401Ssklower * mustn't be zero. 36836401Ssklower * 2 seems like a reasonable minimum. 36936401Ssklower */ 37036401Ssklower ProtoHook 37136401Ssklower tp_input(m, faddr, laddr, cons_channel, dgout_routine) 37236401Ssklower register struct mbuf *m; 37336401Ssklower struct sockaddr *faddr, *laddr; /* NSAP addresses */ 37436401Ssklower u_int cons_channel; 37536401Ssklower int (*dgout_routine)(); 37636401Ssklower 37736401Ssklower { 37836401Ssklower register struct tp_pcb *tpcb = (struct tp_pcb *)0; 37936401Ssklower register struct tpdu *hdr = mtod(m, struct tpdu *); 38036401Ssklower struct socket *so; 38136401Ssklower struct tp_event e; 38236401Ssklower int error = 0; 38336401Ssklower unsigned dutype; 38436401Ssklower u_short dref, sref, acktime, subseq; /*VAX*/ 38536401Ssklower u_char preferred_class=0, class_to_use=0; 38636401Ssklower u_char opt, dusize, addlopt; 38736401Ssklower #ifdef TP_PERF_MEAS 38836401Ssklower u_char perf_meas=0; 38936401Ssklower #endif TP_PERF_MEAS 39036401Ssklower u_char fsufxlen; 39136401Ssklower u_char lsufxlen; 39236401Ssklower caddr_t fsufxloc=0, lsufxloc=0; 39336401Ssklower int tpdu_len; 39436401Ssklower u_int takes_data; 39536401Ssklower u_int fcc_present; 39636401Ssklower caddr_t errloc=0; 39736401Ssklower struct tp_conn_param tpp; 39836401Ssklower int tpcons_output(); 39936401Ssklower 40036401Ssklower #ifdef TP_PERF_MEAS 40136401Ssklower GET_CUR_TIME( &e.e_time ); 40236401Ssklower #endif TP_PERF_MEAS 40336401Ssklower 40436401Ssklower IFDEBUG(D_TPINPUT) 40536401Ssklower printf("tp_input(0x%x, ... 0x%x)\n", m, cons_channel); 40636401Ssklower ENDDEBUG 40736401Ssklower 40836401Ssklower again: 40936401Ssklower 41036401Ssklower tpdu_len = 0; 41136401Ssklower tpcb = (struct tp_pcb *)0; 41236401Ssklower fsufxlen = 0; 41336401Ssklower lsufxlen = 0; 41436401Ssklower addlopt = 0; 41536401Ssklower acktime = 2; 41636401Ssklower dusize = TP_DFL_TPDUSIZE; 41736401Ssklower sref = 0; 41836401Ssklower subseq = 0; 41936401Ssklower takes_data = FALSE; 42036401Ssklower fcc_present = FALSE; 42136401Ssklower 42236401Ssklower /* 42336401Ssklower * get the actual tpdu length - necessary for monitoring 42436401Ssklower * and for checksumming 42536401Ssklower * 42636401Ssklower * Also, maybe measure the mbuf chain lengths and sizes. 42736401Ssklower */ 42836401Ssklower 42936401Ssklower { register struct mbuf *n=m; 43036401Ssklower # ifdef ARGO_DEBUG 43136401Ssklower int chain_length = 0; 43236401Ssklower # endif ARGO_DEBUG 43336401Ssklower 43436401Ssklower for(;;) { 43536401Ssklower tpdu_len += n->m_len; 43636401Ssklower IFDEBUG(D_MBUF_MEAS) 437*37469Ssklower if( n->m_flags & M_EXT) { 43836401Ssklower IncStat(ts_mb_cluster); 43936401Ssklower } else { 44036401Ssklower IncStat(ts_mb_small); 44136401Ssklower } 44236401Ssklower chain_length ++; 44336401Ssklower ENDDEBUG 44436401Ssklower if (n->m_next == MNULL ) { 44536401Ssklower break; 44636401Ssklower } 44736401Ssklower n = n->m_next; 44836401Ssklower } 44936401Ssklower IFDEBUG(D_MBUF_MEAS) 45036401Ssklower if(chain_length > 16) 45136401Ssklower chain_length = 0; /* zero used for anything > 16 */ 45236401Ssklower tp_stat.ts_mb_len_distr[chain_length] ++; 45336401Ssklower ENDDEBUG 45436401Ssklower } 45536401Ssklower IFTRACE(D_TPINPUT) 45636401Ssklower tptraceTPCB(TPPTtpduin, hdr->tpdu_type, hdr, hdr->tpdu_li+1, tpdu_len, 45736401Ssklower 0); 45836401Ssklower ENDTRACE 45936401Ssklower 46036401Ssklower dref = ntohs((short)hdr->tpdu_dref); 46136401Ssklower sref = ntohs((short)hdr->tpdu_sref); 46236401Ssklower dutype = (int)hdr->tpdu_type; 46336401Ssklower 46436401Ssklower IFDEBUG(D_TPINPUT) 46536401Ssklower printf("input: dutype 0x%x cons_channel 0x%x dref 0x%x\n", dutype, 46636401Ssklower cons_channel, dref); 46736401Ssklower printf("input: dref 0x%x sref 0x%x\n", dref, sref); 46836401Ssklower ENDDEBUG 46936401Ssklower IFTRACE(D_TPINPUT) 47036401Ssklower tptrace(TPPTmisc, "channel dutype dref ", 47136401Ssklower cons_channel, dutype, dref, 0); 47236401Ssklower ENDTRACE 47336401Ssklower 47436401Ssklower 47536401Ssklower #ifdef ARGO_DEBUG 47636401Ssklower if( (dutype < TP_MIN_TPDUTYPE) || (dutype > TP_MAX_TPDUTYPE)) { 47736401Ssklower printf("BAD dutype! 0x%x, channel 0x%x dref 0x%x\n", 47836401Ssklower dutype, cons_channel, dref); 47936401Ssklower dump_buf (m, sizeof( struct mbuf )); 48036401Ssklower 48136401Ssklower IncStat(ts_inv_dutype); 48236401Ssklower goto discard; 48336401Ssklower } 48436401Ssklower #endif ARGO_DEBUG 48536401Ssklower 48636401Ssklower CHECK( (dutype < TP_MIN_TPDUTYPE || dutype > TP_MAX_TPDUTYPE), 48736401Ssklower E_TP_INV_TPDU, ts_inv_dutype, respond, 48836401Ssklower 2 ); 48936401Ssklower /* unfortunately we can't take the address of the tpdu_type field, 49036401Ssklower * since it's a bit field - so we just use the constant offset 2 49136401Ssklower */ 49236401Ssklower 49336401Ssklower /* Now this isn't very neat but since you locate a pcb one way 49436401Ssklower * at the beginning of connection establishment, and by 49536401Ssklower * the dref for each tpdu after that, we have to treat CRs differently 49636401Ssklower */ 49736401Ssklower if ( dutype == CR_TPDU_type ) { 49836401Ssklower u_char alt_classes = 0; 49936401Ssklower 50036401Ssklower #ifdef notdef /* This is done up above */ 50136401Ssklower sref = hdr->tpdu_CRsref; 50236401Ssklower #endif notdef 503*37469Ssklower preferred_class = 1 << hdr->tpdu_CRclass; 50436401Ssklower opt = hdr->tpdu_CRoptions; 50536401Ssklower 50636401Ssklower WHILE_OPTIONS(P, hdr, 1 ) /* { */ 50736401Ssklower 50836401Ssklower switch( vbptr(P)->tpv_code ) { 50936401Ssklower 51036401Ssklower case TPP_tpdu_size: 51136401Ssklower vb_getval(P, u_char, dusize); 51236401Ssklower IFDEBUG(D_TPINPUT) 51336401Ssklower printf("CR dusize 0x%x\n", dusize); 51436401Ssklower ENDDEBUG 51536401Ssklower CHECK( (dusize < TP_MIN_TPDUSIZE || dusize > TP_MAX_TPDUSIZE), 51636401Ssklower E_TP_INV_PVAL, ts_inv_pval, respond, 51736401Ssklower (1 + (caddr_t)&vbptr(P)->tpv_val - P) ) 51836401Ssklower break; 51936401Ssklower case TPP_addl_opt: 52036401Ssklower vb_getval(P, u_char, addlopt); 52136401Ssklower break; 52236401Ssklower case TPP_calling_sufx: 52336401Ssklower /* could use vb_getval, but we want to save the loc & len 52436401Ssklower * for later use 52536401Ssklower */ 52636401Ssklower fsufxloc = (caddr_t) &vbptr(P)->tpv_val; 52736401Ssklower fsufxlen = vbptr(P)->tpv_len; 52836401Ssklower IFDEBUG(D_TPINPUT) 52936401Ssklower printf("CR fsufx:"); 53036401Ssklower { register int j; 53136401Ssklower for(j=0; j<fsufxlen; j++ ) { 53236401Ssklower printf(" 0x%x. ", *((caddr_t)(fsufxloc+j)) ); 53336401Ssklower } 53436401Ssklower printf("\n"); 53536401Ssklower } 53636401Ssklower ENDDEBUG 53736401Ssklower break; 53836401Ssklower case TPP_called_sufx: 53936401Ssklower /* could use vb_getval, but we want to save the loc & len 54036401Ssklower * for later use 54136401Ssklower */ 54236401Ssklower lsufxloc = (caddr_t) &vbptr(P)->tpv_val; 54336401Ssklower lsufxlen = vbptr(P)->tpv_len; 54436401Ssklower IFDEBUG(D_TPINPUT) 54536401Ssklower printf("CR lsufx:"); 54636401Ssklower { register int j; 54736401Ssklower for(j=0; j<lsufxlen; j++ ) { 548*37469Ssklower printf(" 0x%x. ", *((u_char *)(lsufxloc+j)) ); 54936401Ssklower } 55036401Ssklower printf("\n"); 55136401Ssklower } 55236401Ssklower ENDDEBUG 55336401Ssklower break; 55436401Ssklower 55536401Ssklower #ifdef TP_PERF_MEAS 55636401Ssklower case TPP_perf_meas: 55736401Ssklower vb_getval(P, u_char, perf_meas); 55836401Ssklower break; 55936401Ssklower #endif TP_PERF_MEAS 56036401Ssklower 56136401Ssklower case TPP_vers: 56236401Ssklower /* not in class 0; 1 octet; in CR_TPDU only */ 56336401Ssklower CHECK( (vbval(P, u_char) != TP_VERSION ), 56436401Ssklower E_TP_INV_PVAL, ts_inv_pval, respond, 56536401Ssklower (1 + (caddr_t)&vbptr(P)->tpv_val - P) ) 56636401Ssklower break; 56736401Ssklower case TPP_acktime: 56836401Ssklower vb_getval(P, u_short, acktime); 56936401Ssklower acktime = ntohs(acktime); 57036401Ssklower acktime = acktime/500; /* convert to slowtimo ticks */ 57136401Ssklower if((short)acktime <=0 ) 57236401Ssklower acktime = 2; /* don't allow a bad peer to screw us up */ 57336401Ssklower IFDEBUG(D_TPINPUT) 57436401Ssklower printf("CR acktime 0x%x\n", acktime); 57536401Ssklower ENDDEBUG 57636401Ssklower break; 57736401Ssklower 57836401Ssklower case TPP_alt_class: 57936401Ssklower { 58036401Ssklower u_char *aclass = 0; 58136401Ssklower register int i; 58236401Ssklower 58336401Ssklower for (i = ((struct tp_vbp *)P)->tpv_len; i>0; i--) { 58436401Ssklower aclass = 58536401Ssklower (u_char *) &(((struct tp_vbp *)P)->tpv_val); 586*37469Ssklower alt_classes |= (1<<((*aclass)>>4)); 58736401Ssklower } 58836401Ssklower IFDEBUG(D_TPINPUT) 58936401Ssklower printf("alt_classes 0x%x\n", alt_classes); 59036401Ssklower ENDDEBUG 59136401Ssklower } 59236401Ssklower break; 59336401Ssklower 59436401Ssklower case TPP_security: 59536401Ssklower case TPP_residER: 59636401Ssklower case TPP_priority: 59736401Ssklower case TPP_transdelay: 59836401Ssklower case TPP_throughput: 59936401Ssklower case TPP_addl_info: 60036401Ssklower case TPP_subseq: 60136401Ssklower IFDEBUG(D_TPINPUT) 60236401Ssklower printf("param ignored CR_TPDU code= 0x%x\n", 60336401Ssklower vbptr(P)->tpv_code); 60436401Ssklower ENDDEBUG 60536401Ssklower IncStat(ts_param_ignored); 60636401Ssklower break; 60736401Ssklower 60836401Ssklower case TPP_checksum: 60936401Ssklower IFDEBUG(D_TPINPUT) 61036401Ssklower printf("CR before cksum\n"); 61136401Ssklower ENDDEBUG 61236401Ssklower 61336401Ssklower CHECK( iso_check_csum(m, tpdu_len), 61436401Ssklower E_TP_INV_PVAL, ts_bad_csum, discard, 0) 61536401Ssklower 61636401Ssklower IFDEBUG(D_TPINPUT) 61736401Ssklower printf("CR before cksum\n"); 61836401Ssklower ENDDEBUG 61936401Ssklower break; 62036401Ssklower 62136401Ssklower default: 62236401Ssklower IncStat(ts_inv_pcode); 62336401Ssklower error = E_TP_INV_PCODE; 62436401Ssklower goto discard; 62536401Ssklower 62636401Ssklower } 62736401Ssklower 62836401Ssklower /* } */ END_WHILE_OPTIONS(P) 62936401Ssklower 63036401Ssklower if( lsufxlen == 0) { 63136401Ssklower /* can't look for a tpcb w/o any called sufx */ 63236401Ssklower error = E_TP_LENGTH_INVAL; 63336401Ssklower IncStat(ts_inv_sufx); 63436401Ssklower goto respond; 63536401Ssklower } else { 63636401Ssklower register struct tp_ref *rp; 63736401Ssklower register int r; 63836401Ssklower extern int tp_maxrefopen; 63936401Ssklower 64036401Ssklower rp = &tp_ref[1]; /* zero-th one is never open */ 64136401Ssklower for( r=1 ; (r <= tp_maxrefopen) ; r++,rp++ ) { 64236401Ssklower if (rp->tpr_state!=REF_OPENING) 64336401Ssklower continue; 64436401Ssklower if ( bcmp(lsufxloc, rp->tpr_pcb->tp_lsuffix, lsufxlen)==0 ) { 64536401Ssklower tpcb = rp->tpr_pcb; 64636401Ssklower if( laddr->sa_family != 64736401Ssklower tpcb->tp_sock->so_proto->pr_domain->dom_family ) { 64836401Ssklower IFDEBUG(D_CONN) 64936401Ssklower printf( 65036401Ssklower "MISMATCHED AF on CR! laddr.family 0x%x expected 0x%x\n", 65136401Ssklower laddr->sa_family, 65236401Ssklower tpcb->tp_sock->so_proto->pr_domain->dom_family ); 65336401Ssklower ENDDEBUG 65436401Ssklower continue; 65536401Ssklower } 65636401Ssklower IFTRACE(D_TPINPUT) 65736401Ssklower tptrace(TPPTmisc, "tp_input: ref *lsufxloc refstate", 65836401Ssklower r, *lsufxloc, rp->tpr_state, 0); 65936401Ssklower ENDTRACE 66036401Ssklower /* found it */ 66136401Ssklower break; 66236401Ssklower } 66336401Ssklower } 66436401Ssklower 66536401Ssklower CHECK( (r > tp_maxrefopen), E_TP_NO_SESSION, ts_inv_sufx, respond, 66636401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 66736401Ssklower /* _tpduf is the fixed part; add 2 to get the dref bits of 66836401Ssklower * the fixed part (can't take the address of a bit field) 66936401Ssklower */ 67036401Ssklower } 67136401Ssklower 67236401Ssklower /* 67336401Ssklower * WE HAVE A TPCB 67436401Ssklower * already know that the classes in the CR match at least 67536401Ssklower * one class implemented, but we don't know yet if they 67636401Ssklower * include any classes permitted by this server. 67736401Ssklower */ 67836401Ssklower 67936401Ssklower IFDEBUG(D_TPINPUT) 68036401Ssklower printf("HAVE A TPCB 1: 0x%x\n", tpcb); 68136401Ssklower ENDDEBUG 68236401Ssklower IFDEBUG(D_CONN) 68336401Ssklower printf( 68436401Ssklower "CR: bef CHKS: flags 0x%x class_to_use 0x%x alt 0x%x opt 0x%x tp_class 0x%x\n", 68536401Ssklower tpcb->tp_flags, class_to_use, alt_classes, opt, tpcb->tp_class); 68636401Ssklower ENDDEBUG 68736401Ssklower /* tpcb->tp_class doesn't include any classes not implemented */ 68836401Ssklower class_to_use = (preferred_class & tpcb->tp_class); 68936401Ssklower if( (class_to_use = preferred_class & tpcb->tp_class) == 0 ) 69036401Ssklower class_to_use = alt_classes & tpcb->tp_class; 69136401Ssklower 69236401Ssklower class_to_use = 1 << tp_mask_to_num(class_to_use); 69336401Ssklower 69436401Ssklower { 69536401Ssklower tpp = tpcb->_tp_param; 69636401Ssklower tpp.p_class = class_to_use; 69736401Ssklower tpp.p_tpdusize = dusize; 69836401Ssklower tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT; 69936401Ssklower tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD; 70036401Ssklower tpp.p_use_checksum = (tpp.p_class == TP_CLASS_0)?0: 70136401Ssklower (addlopt & TPAO_NO_CSUM) == 0; 70236401Ssklower #ifdef notdef 70336401Ssklower tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC; 70436401Ssklower tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD; 70536401Ssklower tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC; 70636401Ssklower #endif notdef 70736401Ssklower 70836401Ssklower CHECK( 70936401Ssklower tp_consistency(tpcb, 0 /* not force or strict */, &tpp) != 0, 71036401Ssklower E_TP_NEGOT_FAILED, ts_negotfailed, respond, 71136401Ssklower (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 71236401Ssklower /* ^ more or less the location of class */ 71336401Ssklower ) 71436401Ssklower } 71536401Ssklower IFTRACE(D_CONN) 71636401Ssklower tptrace(TPPTmisc, 71736401Ssklower "after 1 consist class_to_use class, out, tpconsout", 71836401Ssklower class_to_use, 71936401Ssklower tpcb->tp_class, dgout_routine, tpcons_output 72036401Ssklower ); 72136401Ssklower ENDTRACE 72236401Ssklower CHECK( 72336401Ssklower ((class_to_use == TP_CLASS_0)&&(dgout_routine != tpcons_output)), 72436401Ssklower E_TP_NEGOT_FAILED, ts_negotfailed, respond, 72536401Ssklower (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 72636401Ssklower /* ^ more or less the location of class */ 72736401Ssklower ) 72836401Ssklower IFDEBUG(D_CONN) 72936401Ssklower printf("CR: after CRCCCHECKS: tpcb 0x%x, flags 0x%x\n", 73036401Ssklower tpcb, tpcb->tp_flags); 73136401Ssklower ENDDEBUG 73236401Ssklower takes_data = TRUE; 73336401Ssklower e.ATTR(CR_TPDU).e_cdt = hdr->tpdu_CRcdt; 73436401Ssklower e.ev_number = CR_TPDU; 73536401Ssklower 73636401Ssklower so = tpcb->tp_sock; 73736401Ssklower if (so->so_options & SO_ACCEPTCONN) { 73836401Ssklower /* 73936401Ssklower * Create a socket, tpcb, ll pcb, etc. 74036401Ssklower * for this newborn connection, and fill in all the values. 74136401Ssklower */ 74236401Ssklower IFDEBUG(D_CONN) 74336401Ssklower printf("abt to call tp_newsocket(0x%x, 0x%x, 0x%x, 0x%x)\n", 74436401Ssklower so, laddr, faddr, cons_channel); 74536401Ssklower ENDDEBUG 74636401Ssklower if( (so = 74736401Ssklower tp_newsocket(so, faddr, cons_channel, 74836401Ssklower class_to_use, 749*37469Ssklower ((tpcb->tp_netservice == IN_CLNS) ? IN_CLNS : 750*37469Ssklower (dgout_routine == tpcons_output)?ISO_CONS:ISO_CLNS)) 75136401Ssklower ) == (struct socket *)0 ) { 75236401Ssklower /* note - even if netservice is IN_CLNS, as far as 75336401Ssklower * the tp entity is concerned, the only differences 754*37469Ssklower * are CO vs CL 75536401Ssklower */ 75636401Ssklower IFDEBUG(D_CONN) 75736401Ssklower printf("tp_newsocket returns 0\n"); 75836401Ssklower ENDDEBUG 75936401Ssklower goto discard; 76036401Ssklower } 76136401Ssklower tpcb = sototpcb(so); 76236401Ssklower 76336401Ssklower /* 764*37469Ssklower * Stash the addresses in the net level pcb 76536401Ssklower * kind of like a pcbconnect() but don't need 76636401Ssklower * or want all those checks. 76736401Ssklower */ 76836401Ssklower (tpcb->tp_nlproto->nlp_putnetaddr)(so->so_pcb, faddr, TP_FOREIGN); 76936401Ssklower (tpcb->tp_nlproto->nlp_putnetaddr)(so->so_pcb, laddr, TP_LOCAL); 77036401Ssklower 771*37469Ssklower /* stash the f suffix in the new tpcb */ 772*37469Ssklower /* l suffix is already there */ 77336401Ssklower 774*37469Ssklower bcopy(fsufxloc, tpcb->tp_fsuffix, fsufxlen); 775*37469Ssklower (tpcb->tp_nlproto->nlp_putsufx) 776*37469Ssklower (so->so_pcb, fsufxloc, fsufxlen, TP_FOREIGN); 777*37469Ssklower 77836401Ssklower #ifdef TP_PERF_MEAS 77936401Ssklower if( tpcb->tp_perf_on = perf_meas ) { /* assignment */ 78036401Ssklower /* ok, let's create an mbuf for stashing the 78136401Ssklower * statistics if one doesn't already exist 78236401Ssklower */ 78336401Ssklower (void) tp_setup_perf(tpcb); 78436401Ssklower } 78536401Ssklower #endif TP_PERF_MEAS 78636401Ssklower tpcb->tp_fref = sref; 78736401Ssklower 78836401Ssklower /* We've already checked for consistency with the options 78936401Ssklower * set in tpp, but we couldn't set them earlier because 79036401Ssklower * we didn't want to change options in the LISTENING tpcb. 79136401Ssklower * Now we set the options in the new socket's tpcb. 79236401Ssklower */ 79336401Ssklower (void) tp_consistency( tpcb, TP_FORCE, &tpp); 79436401Ssklower 79536401Ssklower if(!tpcb->tp_use_checksum) 79636401Ssklower IncStat(ts_csum_off); 79736401Ssklower if(tpcb->tp_xpd_service) 79836401Ssklower IncStat(ts_use_txpd); 79936401Ssklower if(tpcb->tp_xtd_format) 80036401Ssklower IncStat(ts_xtd_fmt); 80136401Ssklower 80236401Ssklower /* 80336401Ssklower * Get the maximum transmission unit from the lower layer(s) 80436401Ssklower * so we can negotiate a reasonable max TPDU size. 80536401Ssklower */ 80636401Ssklower (tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb, 80736401Ssklower &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0); 80836401Ssklower tpcb->tp_peer_acktime = acktime; 80936401Ssklower 81036401Ssklower /* 81136401Ssklower * The following kludge is used to test retransmissions and 81236401Ssklower * timeout during connection establishment. 81336401Ssklower */ 81436401Ssklower IFDEBUG(D_ZDREF) 81536401Ssklower IncStat(ts_zdebug); 816*37469Ssklower /*tpcb->tp_fref = 0;*/ 81736401Ssklower ENDDEBUG 81836401Ssklower } 81936401Ssklower IncStat(ts_CR_rcvd); 82036401Ssklower } else if ( dutype == ER_TPDU_type ) { 82136401Ssklower /* 82236401Ssklower * ER TPDUs have to be recognized separately 82336401Ssklower * because they don't necessarily have a tpcb 82436401Ssklower * with them and we don't want err out looking for such 82536401Ssklower * a beast. 82636401Ssklower * We could put a bunch of little kludges in the 82736401Ssklower * next section of code so it would avoid references to tpcb 82836401Ssklower * if dutype == ER_TPDU_type but we don't want code for ERs to 82936401Ssklower * mess up code for data transfer. 83036401Ssklower */ 83136401Ssklower IncStat(ts_ER_rcvd); 83236401Ssklower e.ev_number = ER_TPDU; 83336401Ssklower e.ATTR(ER_TPDU).e_reason = (u_char)hdr->tpdu_ERreason; 83436401Ssklower takes_data = 1; 83536401Ssklower } else { 83636401Ssklower /* tpdu type is CC, XPD, XAK, GR, AK, DR, DC, or DT */ 83736401Ssklower 83836401Ssklower /* In the next 4 checks, 83936401Ssklower * _tpduf is the fixed part; add 2 to get the dref bits of 84036401Ssklower * the fixed part (can't take the address of a bit field) 84136401Ssklower */ 84236401Ssklower if(cons_channel) { 84336401Ssklower #if NARGOXTWENTYFIVE > 0 84436401Ssklower extern struct tp_pcb *cons_chan_to_tpcb(); 84536401Ssklower 84636401Ssklower tpcb = cons_chan_to_tpcb( cons_channel ); 84736401Ssklower /* Problem: We may have a legit 84836401Ssklower * error situation yet we may or may not have 84936401Ssklower * a correspondence between the tpcb and the vc, 85036401Ssklower * e.g., TP4cr--> <no dice, respond w/ DR on vc> 85136401Ssklower * <--- DR 85236401Ssklower * Now it's up to TP to look at the tpdu and do one of: 85336401Ssklower * confirm(dgm)(cr), confirm(circuit)(cr), reject(cr), or 85436401Ssklower * nothing, if the circuit is already open (any other tpdu). 85536401Ssklower * Sigh. 85636401Ssklower */ 85736401Ssklower 85836401Ssklower /* I don't know about this error value */ 85936401Ssklower CHECK( (tpcb == (struct tp_pcb *)0) , 86036401Ssklower E_TP_NO_CR_ON_NC, ts_inv_dref, respond, 86136401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 86236401Ssklower #else 86336401Ssklower printf("tp_input(): X25 NOT CONFIGURED!!\n"); 86436401Ssklower #endif NARGOXTWENTYFIVE > 0 86536401Ssklower 86636401Ssklower } else { 86736401Ssklower 86836401Ssklower CHECK( ((int)dref <= 0 || dref >= N_TPREF) , 86936401Ssklower E_TP_MISM_REFS,ts_inv_dref, respond, 87036401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 87136401Ssklower CHECK( ((tpcb = tp_ref[dref].tpr_pcb ) == (struct tp_pcb *) 0 ), 87236401Ssklower E_TP_MISM_REFS,ts_inv_dref, respond, 87336401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 87436401Ssklower CHECK( (tpcb->tp_refp->tpr_state == REF_FREE), 87536401Ssklower E_TP_MISM_REFS,ts_inv_dref, respond, 87636401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 87736401Ssklower } 87836401Ssklower 87936401Ssklower IFDEBUG(D_TPINPUT) 88036401Ssklower printf("HAVE A TPCB 2: 0x%x\n", tpcb); 88136401Ssklower ENDDEBUG 88236401Ssklower 88336401Ssklower /* causes a DR to be sent for CC; ER for all else */ 88436401Ssklower CHECK( (tpcb->tp_refp->tpr_state == REF_FROZEN), 88536401Ssklower (dutype == CC_TPDU_type?E_TP_NO_SESSION:E_TP_MISM_REFS), 88636401Ssklower ts_inv_dref, respond, 88736401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 88836401Ssklower 88936401Ssklower IFDEBUG(D_TPINPUT) 89036401Ssklower printf("state of dref %d ok, tpcb 0x%x\n", dref,tpcb); 89136401Ssklower ENDDEBUG 89236401Ssklower /* 89336401Ssklower * At this point the state of the dref could be 89436401Ssklower * FROZEN: tpr_pcb == NULL, has ( reference only) timers 89536401Ssklower * for example, DC may arrive after the close() has detached 89636401Ssklower * the tpcb (e.g., if user turned off SO_LISTEN option) 89736401Ssklower * OPENING : a tpcb exists but no timers yet 89836401Ssklower * OPEN : tpcb exists & timers are outstanding 89936401Ssklower */ 90036401Ssklower 90136401Ssklower dusize = tpcb->tp_tpdusize; 90236401Ssklower 90336401Ssklower dutype = hdr->tpdu_type << 8; /* for the switch below */ 90436401Ssklower 90536401Ssklower WHILE_OPTIONS(P, hdr, tpcb->tp_xtd_format) /* { */ 90636401Ssklower 907*37469Ssklower #define caseof(x,y) case (((x)<<8)+(y)) 90836401Ssklower switch( dutype | vbptr(P)->tpv_code ) { 90936401Ssklower 91036401Ssklower caseof( CC_TPDU_type, TPP_addl_opt ): 91136401Ssklower /* not in class 0; 1 octet */ 91236401Ssklower vb_getval(P, u_char, addlopt); 91336401Ssklower break; 91436401Ssklower caseof( CC_TPDU_type, TPP_tpdu_size ): 91536401Ssklower vb_getval(P, u_char, dusize); 91636401Ssklower CHECK( (dusize < TP_MIN_TPDUSIZE || dusize > 91736401Ssklower TP_MAX_TPDUSIZE), E_TP_INV_PVAL, ts_inv_pval, respond, 91836401Ssklower (1 + (caddr_t)&vbptr(P)->tpv_val - P) ) 91936401Ssklower IFDEBUG(D_TPINPUT) 92036401Ssklower printf("CC dusize 0x%x\n", dusize); 92136401Ssklower ENDDEBUG 92236401Ssklower break; 92336401Ssklower caseof( CC_TPDU_type, TPP_calling_sufx): 92436401Ssklower IFDEBUG(D_TPINPUT) 92536401Ssklower printf("CC calling (local) sufxlen 0x%x\n", lsufxlen); 92636401Ssklower ENDDEBUG 92736401Ssklower lsufxloc = (caddr_t) &vbptr(P)->tpv_val; 92836401Ssklower lsufxlen = vbptr(P)->tpv_len; 92936401Ssklower break; 93036401Ssklower caseof( CC_TPDU_type, TPP_acktime ): 93136401Ssklower /* class 4 only, 2 octets */ 93236401Ssklower vb_getval(P, u_short, acktime); 93336401Ssklower acktime = acktime/500; /* convert to slowtimo ticks */ 93436401Ssklower if( (short)acktime <=0 ) 93536401Ssklower acktime = 2; 93636401Ssklower break; 93736401Ssklower caseof( CC_TPDU_type, TPP_called_sufx): 93836401Ssklower fsufxloc = (caddr_t) &vbptr(P)->tpv_val; 93936401Ssklower fsufxlen = vbptr(P)->tpv_len; 94036401Ssklower IFDEBUG(D_TPINPUT) 94136401Ssklower printf("CC called (foreign) sufx len %d\n", fsufxlen); 94236401Ssklower ENDDEBUG 94336401Ssklower break; 94436401Ssklower 94536401Ssklower caseof( CC_TPDU_type, TPP_checksum): 94636401Ssklower caseof( DR_TPDU_type, TPP_checksum): 94736401Ssklower caseof( DT_TPDU_type, TPP_checksum): 94836401Ssklower caseof( XPD_TPDU_type, TPP_checksum): 94936401Ssklower if( tpcb->tp_use_checksum ) { 95036401Ssklower CHECK( iso_check_csum(m, tpdu_len), 95136401Ssklower E_TP_INV_PVAL, ts_bad_csum, discard, 0) 95236401Ssklower } 95336401Ssklower break; 95436401Ssklower 95536401Ssklower /* this is different from the above because in the context 95636401Ssklower * of concat/ sep tpdu_len might not be the same as hdr len 95736401Ssklower */ 95836401Ssklower caseof( AK_TPDU_type, TPP_checksum): 95936401Ssklower caseof( XAK_TPDU_type, TPP_checksum): 96036401Ssklower caseof( DC_TPDU_type, TPP_checksum): 96136401Ssklower if( tpcb->tp_use_checksum ) { 962*37469Ssklower CHECK( iso_check_csum(m, (int)hdr->tpdu_li + 1), 96336401Ssklower E_TP_INV_PVAL, ts_bad_csum, discard, 0) 96436401Ssklower } 96536401Ssklower break; 96636401Ssklower #ifdef notdef 96736401Ssklower caseof( DR_TPDU_type, TPP_addl_info ): 96836401Ssklower /* ignore - its length and meaning are 96936401Ssklower * user defined and there's no way 97036401Ssklower * to pass this info to the user anyway 97136401Ssklower */ 97236401Ssklower break; 97336401Ssklower #endif notdef 97436401Ssklower 97536401Ssklower caseof( AK_TPDU_type, TPP_subseq ): 97636401Ssklower /* used after reduction of window */ 97736401Ssklower vb_getval(P, u_short, subseq); 97836401Ssklower subseq = ntohs(subseq); 97936401Ssklower IFDEBUG(D_ACKRECV) 98036401Ssklower printf("AK Subsequence # 0x%x\n", subseq); 98136401Ssklower ENDDEBUG 98236401Ssklower break; 98336401Ssklower 98436401Ssklower caseof( AK_TPDU_type, TPP_flow_cntl_conf ): 98536401Ssklower { 98636401Ssklower u_int ylwe; 98736401Ssklower u_short ysubseq, ycredit; 98836401Ssklower 98936401Ssklower fcc_present = TRUE; 99036401Ssklower vb_getval(P, u_int, ylwe); 99136401Ssklower vb_getval(P, u_short, ysubseq); 99236401Ssklower vb_getval(P, u_short, ycredit); 99336401Ssklower ylwe = ntohl(ylwe); 99436401Ssklower ysubseq = ntohs(ysubseq); 99536401Ssklower ycredit = ntohs(ycredit); 99636401Ssklower IFDEBUG(D_ACKRECV) 99736401Ssklower printf("AK FCC lwe 0x%x, subseq 0x%x, cdt 0x%x\n", 99836401Ssklower ylwe, ysubseq, ycredit); 99936401Ssklower ENDDEBUG 100036401Ssklower } 100136401Ssklower break; 100236401Ssklower 100336401Ssklower default: 100436401Ssklower IFDEBUG(D_TPINPUT) 100536401Ssklower printf("param ignored dutype 0x%x, code 0x%x\n", 100636401Ssklower dutype, vbptr(P)->tpv_code); 100736401Ssklower ENDDEBUG 100836401Ssklower IFTRACE(D_TPINPUT) 100936401Ssklower tptrace(TPPTmisc, "param ignored dutype code ", 101036401Ssklower dutype, vbptr(P)->tpv_code ,0,0); 101136401Ssklower ENDTRACE 101236401Ssklower IncStat(ts_param_ignored); 101336401Ssklower break; 101436401Ssklower #undef caseof 101536401Ssklower } 101636401Ssklower /* } */ END_WHILE_OPTIONS(P) 101736401Ssklower 101836401Ssklower /* NOTE: the variable dutype has been shifted left! */ 101936401Ssklower 102036401Ssklower switch( hdr->tpdu_type ) { 102136401Ssklower case CC_TPDU_type: 102236401Ssklower /* If CC comes back with an unacceptable class 102336401Ssklower * respond with a DR or ER 102436401Ssklower */ 102536401Ssklower 102636401Ssklower opt = hdr->tpdu_CCoptions; /* 1 byte */ 102736401Ssklower 102836401Ssklower { 102936401Ssklower tpp = tpcb->_tp_param; 103036401Ssklower tpp.p_class = (1<<hdr->tpdu_CCclass); 103136401Ssklower tpp.p_tpdusize = dusize; 103236401Ssklower tpp.p_dont_change_params = 0; 103336401Ssklower tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT; 103436401Ssklower tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD; 103536401Ssklower tpp.p_use_checksum = (addlopt & TPAO_NO_CSUM) == 0; 103636401Ssklower #ifdef notdef 103736401Ssklower tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC; 103836401Ssklower tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD; 103936401Ssklower tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC; 104036401Ssklower #endif notdef 104136401Ssklower 104236401Ssklower CHECK( 104336401Ssklower tp_consistency(tpcb, TP_FORCE, &tpp) != 0, 104436401Ssklower E_TP_NEGOT_FAILED, ts_negotfailed, respond, 104536401Ssklower (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 104636401Ssklower /* ^ more or less the location of class */ 104736401Ssklower ) 104836401Ssklower IFTRACE(D_CONN) 104936401Ssklower tptrace(TPPTmisc, 105036401Ssklower "after 1 consist class, out, tpconsout", 105136401Ssklower tpcb->tp_class, dgout_routine, tpcons_output, 0 105236401Ssklower ); 105336401Ssklower ENDTRACE 105436401Ssklower CHECK( 105536401Ssklower ((class_to_use == TP_CLASS_0)&& 105636401Ssklower (dgout_routine != tpcons_output)), 105736401Ssklower E_TP_NEGOT_FAILED, ts_negotfailed, respond, 105836401Ssklower (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 105936401Ssklower /* ^ more or less the location of class */ 106036401Ssklower ) 106136401Ssklower } 106236401Ssklower if( ! tpcb->tp_use_checksum) 106336401Ssklower IncStat(ts_csum_off); 106436401Ssklower if(tpcb->tp_xpd_service) 106536401Ssklower IncStat(ts_use_txpd); 106636401Ssklower if(tpcb->tp_xtd_format) 106736401Ssklower IncStat(ts_xtd_fmt); 106836401Ssklower 106936401Ssklower IFTRACE(D_CONN) 107036401Ssklower tptrace(TPPTmisc, "after CC class flags dusize CCclass", 107136401Ssklower tpcb->tp_class, tpcb->tp_flags, tpcb->tp_tpdusize, 107236401Ssklower hdr->tpdu_CCclass); 107336401Ssklower ENDTRACE 107436401Ssklower 107536401Ssklower /* 107636401Ssklower * Get the maximum transmission unit from the lower layer(s) 107736401Ssklower * so we can decide how large a TPDU size to negotiate. 107836401Ssklower * It would be nice if the arguments to this 107936401Ssklower * were more reasonable. 108036401Ssklower */ 108136401Ssklower (tpcb->tp_nlproto->nlp_mtu)(tpcb->tp_sock, tpcb->tp_sock->so_pcb, 108236401Ssklower &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0); 108336401Ssklower 108436401Ssklower #ifdef CONS 108536401Ssklower /* Could be that this CC came in on a NEW vc, in which case 108636401Ssklower * we have to confirm it. 108736401Ssklower */ 108836401Ssklower if( cons_channel ) 108936401Ssklower cons_netcmd( CONN_CONFIRM, tpcb->tp_npcb, cons_channel, 109036401Ssklower tpcb->tp_class == TP_CLASS_4); 109136401Ssklower #endif CONS 109236401Ssklower 109336401Ssklower tpcb->tp_peer_acktime = acktime; 109436401Ssklower 109536401Ssklower /* if called or calling suffices appeared on the CC, 109636401Ssklower * they'd better jive with what's in the pcb 109736401Ssklower */ 109836401Ssklower if( fsufxlen ) { 109936401Ssklower CHECK( ((tpcb->tp_fsuffixlen != fsufxlen) || 110036401Ssklower bcmp(fsufxloc, tpcb->tp_fsuffix, fsufxlen)), 110136401Ssklower E_TP_INV_PVAL,ts_inv_sufx, respond, 110236401Ssklower (1+fsufxloc - (caddr_t)hdr)) 110336401Ssklower } 110436401Ssklower if( lsufxlen ) { 110536401Ssklower CHECK( ((tpcb->tp_lsuffixlen != lsufxlen) || 110636401Ssklower bcmp(lsufxloc, tpcb->tp_lsuffix, lsufxlen)), 110736401Ssklower E_TP_INV_PVAL,ts_inv_sufx, respond, 110836401Ssklower (1+lsufxloc - (caddr_t)hdr)) 110936401Ssklower } 111036401Ssklower 111136401Ssklower #ifdef notdef 111236401Ssklower e.ATTR(CC_TPDU).e_sref = (u_short)hdr->tpdu_CCsref; 111336401Ssklower #else 111436401Ssklower e.ATTR(CC_TPDU).e_sref = sref; 111536401Ssklower #endif notdef 111636401Ssklower e.ATTR(CC_TPDU).e_cdt = hdr->tpdu_CCcdt; 111736401Ssklower takes_data = TRUE; 111836401Ssklower e.ev_number = CC_TPDU; 111936401Ssklower IncStat(ts_CC_rcvd); 112036401Ssklower break; 112136401Ssklower 112236401Ssklower case DC_TPDU_type: 112336401Ssklower #ifdef notdef 112436401Ssklower if (hdr->tpdu_DCsref != tpcb->tp_fref) 112536401Ssklower printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n", 112636401Ssklower hdr->tpdu_DCsref, tpcb->tp_fref); 112736401Ssklower #else 112836401Ssklower if (sref != tpcb->tp_fref) 112936401Ssklower printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n", 113036401Ssklower sref, tpcb->tp_fref); 113136401Ssklower #endif notdef 113236401Ssklower 113336401Ssklower #ifdef notdef 113436401Ssklower CHECK( (hdr->tpdu_DCsref != tpcb->tp_fref), 113536401Ssklower E_TP_MISM_REFS, ts_inv_sufx, respond, 113636401Ssklower (1 + (caddr_t)&hdr->tpdu_DCsref - (caddr_t)hdr)) 113736401Ssklower #else 113836401Ssklower CHECK( (sref != tpcb->tp_fref), 113936401Ssklower E_TP_MISM_REFS, ts_inv_sufx, respond, 114036401Ssklower (1 + (caddr_t)&hdr->tpdu_DCsref - (caddr_t)hdr)) 114136401Ssklower #endif notdef 114236401Ssklower e.ev_number = DC_TPDU; 114336401Ssklower IncStat(ts_DC_rcvd); 114436401Ssklower break; 114536401Ssklower 114636401Ssklower case DR_TPDU_type: 114736401Ssklower IFTRACE(D_TPINPUT) 114836401Ssklower tptrace(TPPTmisc, "DR recvd", hdr->tpdu_DRreason, 0, 0, 0); 114936401Ssklower ENDTRACE 115036401Ssklower #ifdef vax 115136401Ssklower if(sref != tpcb->tp_fref) 115236401Ssklower printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n", 115336401Ssklower sref, tpcb->tp_fref); 115436401Ssklower 115536401Ssklower CHECK( (sref != tpcb->tp_fref), 115636401Ssklower E_TP_MISM_REFS,ts_inv_sufx, respond, 115736401Ssklower (1 + (caddr_t)&hdr->tpdu_DRsref - (caddr_t)hdr)) 115836401Ssklower 115936401Ssklower e.ATTR(DR_TPDU).e_reason = hdr->tpdu_DRreason; 116036401Ssklower e.ATTR(DR_TPDU).e_sref = (u_short)sref; 116136401Ssklower #else 116236401Ssklower if(hdr->tpdu_DRsref != tpcb->tp_fref) 116336401Ssklower printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n", 116436401Ssklower hdr->tpdu_DRsref, tpcb->tp_fref); 116536401Ssklower 116636401Ssklower CHECK( (hdr->tpdu_DRsref != tpcb->tp_fref), 116736401Ssklower E_TP_MISM_REFS,ts_inv_sufx, respond, 116836401Ssklower (1 + (caddr_t)&hdr->tpdu_DRsref - (caddr_t)hdr)) 116936401Ssklower 117036401Ssklower e.ATTR(DR_TPDU).e_reason = 117136401Ssklower hdr->tpdu_DRreason; 117236401Ssklower e.ATTR(DR_TPDU).e_sref = (u_short)hdr->tpdu_DRsref; 117336401Ssklower #endif vax 117436401Ssklower takes_data = TRUE; 117536401Ssklower e.ev_number = DR_TPDU; 117636401Ssklower IncStat(ts_DR_rcvd); 117736401Ssklower break; 117836401Ssklower 117936401Ssklower case ER_TPDU_type: 118036401Ssklower IFTRACE(D_TPINPUT) 118136401Ssklower tptrace(TPPTmisc, "ER recvd", hdr->tpdu_ERreason,0,0,0); 118236401Ssklower ENDTRACE 118336401Ssklower e.ev_number = ER_TPDU; 118436401Ssklower e.ATTR(ER_TPDU).e_reason = hdr->tpdu_ERreason; 118536401Ssklower IncStat(ts_ER_rcvd); 118636401Ssklower break; 118736401Ssklower 118836401Ssklower case AK_TPDU_type: 118936401Ssklower 119036401Ssklower e.ATTR(AK_TPDU).e_subseq = subseq; 119136401Ssklower e.ATTR(AK_TPDU).e_fcc_present = fcc_present; 119236401Ssklower 119336401Ssklower if (tpcb->tp_xtd_format) { 119436401Ssklower #ifdef BYTE_ORDER 119536401Ssklower union seq_type seqeotX; 119636401Ssklower 119736401Ssklower seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 119836401Ssklower e.ATTR(AK_TPDU).e_seq = seqeotX.s_seq; 119936401Ssklower e.ATTR(AK_TPDU).e_cdt = ntohs(hdr->tpdu_AKcdtX); 120036401Ssklower #else 120136401Ssklower e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdtX; 120236401Ssklower e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseqX; 120336401Ssklower #endif BYTE_ORDER 120436401Ssklower } else { 120536401Ssklower e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdt; 120636401Ssklower e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseq; 120736401Ssklower } 120836401Ssklower IFTRACE(D_TPINPUT) 120936401Ssklower tptrace(TPPTmisc, "AK recvd seq cdt subseq fcc_pres", 121036401Ssklower e.ATTR(AK_TPDU).e_seq, e.ATTR(AK_TPDU).e_cdt, 121136401Ssklower subseq, fcc_present); 121236401Ssklower ENDTRACE 121336401Ssklower 121436401Ssklower e.ev_number = AK_TPDU; 121536401Ssklower IncStat(ts_AK_rcvd); 121636401Ssklower IncPStat(tpcb, tps_AK_rcvd); 121736401Ssklower break; 121836401Ssklower 121936401Ssklower case XAK_TPDU_type: 122036401Ssklower if (tpcb->tp_xtd_format) { 122136401Ssklower #ifdef BYTE_ORDER 122236401Ssklower union seq_type seqeotX; 122336401Ssklower 122436401Ssklower seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 122536401Ssklower e.ATTR(XAK_TPDU).e_seq = seqeotX.s_seq; 122636401Ssklower #else 122736401Ssklower e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseqX; 122836401Ssklower #endif BYTE_ORDER 122936401Ssklower } else { 123036401Ssklower e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseq; 123136401Ssklower } 123236401Ssklower e.ev_number = XAK_TPDU; 123336401Ssklower IncStat(ts_XAK_rcvd); 123436401Ssklower IncPStat(tpcb, tps_XAK_rcvd); 123536401Ssklower break; 123636401Ssklower 123736401Ssklower case XPD_TPDU_type: 123836401Ssklower if (tpcb->tp_xtd_format) { 123936401Ssklower #ifdef BYTE_ORDER 124036401Ssklower union seq_type seqeotX; 124136401Ssklower 124236401Ssklower seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 124336401Ssklower e.ATTR(XPD_TPDU).e_seq = seqeotX.s_seq; 124436401Ssklower #else 124536401Ssklower e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseqX; 124636401Ssklower #endif BYTE_ORDER 124736401Ssklower } else { 124836401Ssklower e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseq; 124936401Ssklower } 125036401Ssklower takes_data = TRUE; 125136401Ssklower e.ev_number = XPD_TPDU; 125236401Ssklower IncStat(ts_XPD_rcvd); 125336401Ssklower IncPStat(tpcb, tps_XPD_rcvd); 125436401Ssklower break; 125536401Ssklower 125636401Ssklower case DT_TPDU_type: 125736401Ssklower { /* the y option will cause occasional packets to be dropped. 125836401Ssklower * A little crude but it works. 125936401Ssklower */ 126036401Ssklower 126136401Ssklower IFDEBUG(D_DROP) 126236401Ssklower if(time.tv_usec & 0x4 && hdr->tpdu_DTseq & 0x1) { 126336401Ssklower IncStat(ts_ydebug); 126436401Ssklower goto discard; 126536401Ssklower } 126636401Ssklower ENDDEBUG 126736401Ssklower } 126836401Ssklower if (tpcb->tp_class == TP_CLASS_0) { 126936401Ssklower e.ATTR(DT_TPDU).e_seq = 0; /* actually don't care */ 127036401Ssklower e.ATTR(DT_TPDU).e_eot = (((struct tp0du *)hdr)->tp0du_eot); 127136401Ssklower } else if (tpcb->tp_xtd_format) { 127236401Ssklower #ifdef BYTE_ORDER 127336401Ssklower union seq_type seqeotX; 127436401Ssklower 127536401Ssklower seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 127636401Ssklower e.ATTR(DT_TPDU).e_seq = seqeotX.s_seq; 127736401Ssklower e.ATTR(DT_TPDU).e_eot = seqeotX.s_eot; 127836401Ssklower #else 127936401Ssklower e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseqX; 128036401Ssklower e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeotX; 128136401Ssklower #endif BYTE_ORDER 128236401Ssklower } else { 128336401Ssklower e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseq; 128436401Ssklower e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeot; 128536401Ssklower } 128636401Ssklower if(e.ATTR(DT_TPDU).e_eot) 128736401Ssklower IncStat(ts_eot_input); 128836401Ssklower takes_data = TRUE; 128936401Ssklower e.ev_number = DT_TPDU; 129036401Ssklower IncStat(ts_DT_rcvd); 129136401Ssklower IncPStat(tpcb, tps_DT_rcvd); 129236401Ssklower break; 129336401Ssklower 129436401Ssklower case GR_TPDU_type: 129536401Ssklower tp_indicate(T_DISCONNECT, tpcb, ECONNABORTED); 129636401Ssklower /* drop through */ 129736401Ssklower default: 129836401Ssklower /* this should NEVER happen because there is a 129936401Ssklower * check for dutype well above here 130036401Ssklower */ 130136401Ssklower error = E_TP_INV_TPDU; /* causes an ER */ 130236401Ssklower IFDEBUG(D_TPINPUT) 130336401Ssklower printf("INVALID dutype 0x%x\n", hdr->tpdu_type); 130436401Ssklower ENDDEBUG 130536401Ssklower IncStat(ts_inv_dutype); 130636401Ssklower goto respond; 130736401Ssklower } 130836401Ssklower } 130936401Ssklower 131036401Ssklower /* peel off the tp header; 131136401Ssklower * remember that the du_li doesn't count itself. 131236401Ssklower * This may leave us w/ an empty mbuf at the front of a chain. 131336401Ssklower * We can't just throw away the empty mbuf because hdr still points 131436401Ssklower * into the mbuf's data area and we're still using hdr (the tpdu header) 131536401Ssklower */ 131636401Ssklower m->m_len -= ((int)hdr->tpdu_li + 1); 1317*37469Ssklower m->m_data += ((int)hdr->tpdu_li + 1); 131836401Ssklower 1319*37469Ssklower if (takes_data) { 1320*37469Ssklower int max = tpdu_info[ hdr->tpdu_type ] [TP_MAX_DATA_INDEX]; 1321*37469Ssklower int datalen = tpdu_len - hdr->tpdu_li - 1, mbtype = MT_DATA; 1322*37469Ssklower struct tp_control_hdr c_hdr; 1323*37469Ssklower struct mbuf *n; 132436401Ssklower 1325*37469Ssklower CHECK( (max && datalen > max), E_TP_LENGTH_INVAL, 1326*37469Ssklower ts_inv_length, respond, (max + hdr->tpdu_li + 1) ); 132736401Ssklower switch( hdr->tpdu_type ) { 1328*37469Ssklower 132936401Ssklower case CR_TPDU_type: 1330*37469Ssklower c_hdr.cmsg_type = TPOPT_CONN_DATA; 1331*37469Ssklower goto make_control_msg; 1332*37469Ssklower 133336401Ssklower case CC_TPDU_type: 1334*37469Ssklower c_hdr.cmsg_type = TPOPT_CFRM_DATA; 1335*37469Ssklower goto make_control_msg; 1336*37469Ssklower 133736401Ssklower case DR_TPDU_type: 1338*37469Ssklower c_hdr.cmsg_type = TPOPT_DISC_DATA; 1339*37469Ssklower make_control_msg: 1340*37469Ssklower c_hdr.cmsg_level = SOL_TRANSPORT; 1341*37469Ssklower mbtype = MT_CONTROL; 1342*37469Ssklower if (datalen > 0) { 1343*37469Ssklower datalen += sizeof(c_hdr); 1344*37469Ssklower m->m_len += sizeof(c_hdr); 1345*37469Ssklower m->m_data -= sizeof(c_hdr); 1346*37469Ssklower c_hdr.cmsg_len = datalen; 1347*37469Ssklower bcopy((caddr_t)&c_hdr, mtod(m, caddr_t), 1348*37469Ssklower sizeof(c_hdr)); 1349*37469Ssklower } 1350*37469Ssklower /* FALLTHROUGH */ 1351*37469Ssklower 135236401Ssklower case XPD_TPDU_type: 1353*37469Ssklower if (mbtype != MT_CONTROL) 1354*37469Ssklower mbtype = MT_OOBDATA; 1355*37469Ssklower m->m_flags |= M_EOR; 1356*37469Ssklower /* FALLTHROUGH */ 1357*37469Ssklower 135836401Ssklower case DT_TPDU_type: 1359*37469Ssklower for (n = m; n; n = n->m_next) { 1360*37469Ssklower MCHTYPE(n, mbtype); 1361*37469Ssklower } 1362*37469Ssklower e.ATTR(DT_TPDU).e_datalen = datalen; 136336401Ssklower e.ATTR(DT_TPDU).e_data = m; 136436401Ssklower break; 136536401Ssklower 136636401Ssklower default: 136736401Ssklower printf( 136836401Ssklower "ERROR in tp_input! hdr->tpdu_type 0x%x takes_data 0x%x m 0x%x\n", 136936401Ssklower hdr->tpdu_type, takes_data, m); 137036401Ssklower break; 137136401Ssklower } 137236401Ssklower /* prevent m_freem() after tp_driver() from throwing it all away */ 137336401Ssklower m = MNULL; 137436401Ssklower } 137536401Ssklower 137636401Ssklower IncStat(ts_tpdu_rcvd); 137736401Ssklower 137836401Ssklower IFDEBUG(D_TPINPUT) 137936401Ssklower printf( "tp_input: before driver, state 0x%x event 0x%x m 0x%x", 138036401Ssklower tpcb->tp_state, e.ev_number, m ); 138136401Ssklower printf(" e.e_data 0x%x\n", e.ATTR(DT_TPDU).e_data); 138236401Ssklower printf("takes_data 0x%x m_len 0x%x, tpdu_len 0x%x\n", 138336401Ssklower takes_data, (m==MNULL)?0:m->m_len, tpdu_len); 138436401Ssklower ENDDEBUG 138536401Ssklower 138636401Ssklower if( tpcb->tp_decbit != 0 ) /* unsigned 4 bits */ 138736401Ssklower tpcb->tp_decbit --; 138836401Ssklower 138936401Ssklower error = tp_driver(tpcb, &e); 139036401Ssklower 139136401Ssklower ASSERT(tpcb != (struct tp_pcb *)0); 139236401Ssklower ASSERT(tpcb->tp_sock != (struct socket *)0); 139336401Ssklower if( tpcb->tp_sock->so_error == 0 ) 139436401Ssklower tpcb->tp_sock->so_error = error; 139536401Ssklower 139636401Ssklower /* Kludge to keep the state tables under control (adding 139736401Ssklower * data on connect & disconnect & freeing the mbuf containing 139836401Ssklower * the data would have exploded the tables and made a big mess ). 139936401Ssklower */ 140036401Ssklower switch(e.ev_number) { 140136401Ssklower case CC_TPDU: 140236401Ssklower case DR_TPDU: 140336401Ssklower case CR_TPDU: 140436401Ssklower m = e.ATTR(CC_TPDU).e_data; /* same field for all three dutypes */ 140536401Ssklower IFDEBUG(D_TPINPUT) 140636401Ssklower printf("after driver, restoring m to 0x%x, takes_data 0x%x\n", 140736401Ssklower m, takes_data); 140836401Ssklower ENDDEBUG 140936401Ssklower break; 141036401Ssklower default: 141136401Ssklower break; 141236401Ssklower } 141336401Ssklower /* Concatenated sequences are terminated by any tpdu that 141436401Ssklower * carries data: CR, CC, DT, XPD, DR. 141536401Ssklower * All other tpdu types may be concatenated: AK, XAK, DC, ER. 141636401Ssklower */ 141736401Ssklower 141836401Ssklower separate: 141936401Ssklower if ( takes_data == 0 ) { 142036401Ssklower ASSERT( m != MNULL ); 142136401Ssklower /* 142236401Ssklower * we already peeled off the prev. tp header so 142336401Ssklower * we can just pull up some more and repeat 142436401Ssklower */ 142536401Ssklower 1426*37469Ssklower if( m = tp_inputprep(m) ) { 142736401Ssklower IFDEBUG(D_TPINPUT) 142836401Ssklower hdr = mtod(m, struct tpdu *); 142936401Ssklower printf("tp_input @ separate: hdr 0x%x size %d m 0x%x\n", 143036401Ssklower hdr, (int) hdr->tpdu_li + 1, m); 143136401Ssklower dump_mbuf(m, "tp_input after driver, at separate"); 143236401Ssklower ENDDEBUG 143336401Ssklower 143436401Ssklower IncStat(ts_concat_rcvd); 143536401Ssklower goto again; 143636401Ssklower } 143736401Ssklower } 143836401Ssklower if ( m != MNULL ) { 143936401Ssklower IFDEBUG(D_TPINPUT) 144036401Ssklower printf("tp_input : m_freem(0x%x)\n", m); 144136401Ssklower ENDDEBUG 144236401Ssklower m_freem(m); 144336401Ssklower IFDEBUG(D_TPINPUT) 144436401Ssklower printf("tp_input : after m_freem 0x%x\n", m); 144536401Ssklower ENDDEBUG 144636401Ssklower } 144736401Ssklower return (ProtoHook) tpcb; 144836401Ssklower 144936401Ssklower discard: 145036401Ssklower /* class 4: drop the tpdu */ 145136401Ssklower /* class 2,0: Should drop the net connection, if you can figure out 145236401Ssklower * to which connection it applies 145336401Ssklower */ 145436401Ssklower IFDEBUG(D_TPINPUT) 145536401Ssklower printf("tp_input DISCARD\n"); 145636401Ssklower ENDDEBUG 145736401Ssklower IFTRACE(D_TPINPUT) 145836401Ssklower tptrace(TPPTmisc, "tp_input DISCARD m", m,0,0,0); 145936401Ssklower ENDTRACE 146036401Ssklower m_freem(m); 146136401Ssklower IncStat(ts_recv_drop); 146236401Ssklower return (ProtoHook)0; 146336401Ssklower 146436401Ssklower respond: 146536401Ssklower IFDEBUG(D_ERROR_EMIT) 146636401Ssklower printf("RESPOND: error 0x%x, errloc 0x%x\n", error, errloc); 146736401Ssklower ENDDEBUG 146836401Ssklower IFTRACE(D_TPINPUT) 146936401Ssklower tptrace(TPPTmisc, "tp_input RESPOND m error sref", m,error,sref,0); 147036401Ssklower ENDTRACE 147136401Ssklower if( sref == 0 ) 147236401Ssklower goto discard; 1473*37469Ssklower (void) tp_error_emit(error, (u_long)sref, (struct sockaddr_iso *)faddr, 1474*37469Ssklower (struct sockaddr_iso *)laddr, m, (int)errloc, tpcb, 1475*37469Ssklower (int)cons_channel, dgout_routine); 147636401Ssklower IFDEBUG(D_ERROR_EMIT) 147736401Ssklower printf("tp_input after error_emit\n"); 147836401Ssklower ENDDEBUG 147936401Ssklower 148036401Ssklower #ifdef lint 148136401Ssklower printf("",sref,opt); 148236401Ssklower #endif lint 148336401Ssklower IncStat(ts_recv_drop); 148436401Ssklower return (ProtoHook)0; 148536401Ssklower } 148636401Ssklower 148736401Ssklower 148836401Ssklower /* 148936401Ssklower * NAME: tp_headersize() 149036401Ssklower * 149136401Ssklower * CALLED FROM: 149236401Ssklower * tp_emit() and tp_sbsend() 149336401Ssklower * TP needs to know the header size so it can figure out how 149436401Ssklower * much data to put in each tpdu. 149536401Ssklower * 149636401Ssklower * FUNCTION, ARGUMENTS, and RETURN VALUE: 149736401Ssklower * For a given connection, represented by (tpcb), and 149836401Ssklower * tpdu type (dutype), return the size of a tp header. 149936401Ssklower * 150036401Ssklower * RETURNS: the expected size of the heade in bytesr 150136401Ssklower * 150236401Ssklower * SIDE EFFECTS: 150336401Ssklower * 150436401Ssklower * NOTES: It would be nice if it got the network header size as well. 150536401Ssklower */ 150636401Ssklower int 150736401Ssklower tp_headersize(dutype, tpcb) 150836401Ssklower int dutype; 150936401Ssklower struct tp_pcb *tpcb; 151036401Ssklower { 151136401Ssklower register int size = 0; 151236401Ssklower 151336401Ssklower IFTRACE(D_CONN) 151436401Ssklower tptrace(TPPTmisc, "tp_headersize dutype class xtd_format", 151536401Ssklower dutype, tpcb->tp_class, tpcb->tp_xtd_format, 0); 151636401Ssklower ENDTRACE 151736401Ssklower if( !( (tpcb->tp_class == TP_CLASS_0) || 151836401Ssklower (tpcb->tp_class == TP_CLASS_4) || 151936401Ssklower (dutype == DR_TPDU_type) || 152036401Ssklower (dutype == CR_TPDU_type) )) { 152136401Ssklower printf("tp_headersize:dutype 0x%x, class 0x%x", 152236401Ssklower dutype, tpcb->tp_class); 152336401Ssklower /* TODO: identify this and GET RID OF IT */ 152436401Ssklower } 152536401Ssklower ASSERT( (tpcb->tp_class == TP_CLASS_0) || 152636401Ssklower (tpcb->tp_class == TP_CLASS_4) || 152736401Ssklower (dutype == DR_TPDU_type) || 152836401Ssklower (dutype == CR_TPDU_type) ); 152936401Ssklower 153036401Ssklower if( tpcb->tp_class == TP_CLASS_0 ) { 153136401Ssklower size = tpdu_info[ dutype ] [TP_LEN_CLASS_0_INDEX]; 153236401Ssklower } else { 153336401Ssklower size = tpdu_info[ dutype ] [tpcb->tp_xtd_format]; 153436401Ssklower } 153536401Ssklower return size; 153636401Ssklower /* caller must get network level header size separately */ 153736401Ssklower } 1538