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 $ 32*44601Ssklower * @(#)tp_input.c 7.13 (Berkeley) 06/29/90 * 3336401Ssklower * 3436401Ssklower * tp_input() gets an mbuf chain from ip. Actually, not directly 3536401Ssklower * from ip, because ip calls a net-level routine that strips off 3636401Ssklower * the net header and then calls tp_input(), passing the proper type 3736401Ssklower * of addresses for the address family in use (how it figures out 3836401Ssklower * which AF is not yet determined. 3936401Ssklower * 4036401Ssklower * Decomposing the tpdu is some of the most laughable code. The variable-length 4136401Ssklower * parameters and the problem of non-aligned memory references 4236401Ssklower * necessitates such abominations as the macros WHILE_OPTIONS (q.v. below) 4336401Ssklower * to loop through the header and decompose it. 4436401Ssklower * 4536401Ssklower * The routine tp_newsocket() is called when a CR comes in for a listening 4636401Ssklower * socket. tp_input calls sonewconn() and tp_newsocket() to set up the 4736401Ssklower * "child" socket. Most tpcb values are copied from the parent tpcb into 4836401Ssklower * the child. 4936401Ssklower * 5036401Ssklower * Also in here is tp_headersize() (grot) which tells the expected size 5136401Ssklower * of a tp header, to be used by other layers. It's in here because it 5236401Ssklower * uses the static structure tpdu_info. 5336401Ssklower */ 5436401Ssklower 5536401Ssklower #ifndef lint 5636401Ssklower static char *rcsid = "$Header: tp_input.c,v 5.6 88/11/18 17:27:38 nhall Exp $"; 5736401Ssklower #endif lint 5836401Ssklower 5936401Ssklower #include "argoxtwentyfive.h" 6036401Ssklower #include "param.h" 6144422Ssklower #include "systm.h" 6236401Ssklower #include "mbuf.h" 6336401Ssklower #include "socket.h" 6436401Ssklower #include "socketvar.h" 6536401Ssklower #include "domain.h" 6636401Ssklower #include "protosw.h" 6736401Ssklower #include "errno.h" 6836401Ssklower #include "time.h" 6936401Ssklower #include "kernel.h" 7036401Ssklower #include "types.h" 7137469Ssklower #include "iso_errno.h" 7237469Ssklower #include "tp_param.h" 7337469Ssklower #include "tp_timer.h" 7437469Ssklower #include "tp_stat.h" 7537469Ssklower #include "tp_pcb.h" 7637469Ssklower #include "argo_debug.h" 7737469Ssklower #include "tp_trace.h" 7837469Ssklower #include "tp_tpdu.h" 7937469Ssklower #include "iso.h" 8037469Ssklower #include "cons.h" 8136401Ssklower 8236401Ssklower int iso_check_csum(), tp_driver(), tp_headersize(), tp_error_emit(); 8336401Ssklower 8437469Ssklower /* 8537469Ssklower #ifdef lint 8637469Ssklower #undef ATTR 8737469Ssklower #define ATTR(X)ev_number 8837469Ssklower #endif lint 8937469Ssklower */ 9036401Ssklower 9136401Ssklower struct mbuf * 9236401Ssklower tp_inputprep(m) 9337469Ssklower register struct mbuf *m; 9436401Ssklower { 9537469Ssklower int hdrlen; 9636401Ssklower 9736401Ssklower IFDEBUG(D_TPINPUT) 9837469Ssklower printf("tp_inputprep: m 0x%x\n", m) ; 9936401Ssklower ENDDEBUG 10036401Ssklower 10136401Ssklower while( m->m_len < 1 ) { 10236401Ssklower if( (m = m_free(m)) == MNULL ) { 10336401Ssklower return (struct mbuf *)0; 10436401Ssklower } 10536401Ssklower } 10637469Ssklower if(((int)m->m_data) & 0x3) { 10737469Ssklower /* If we are not 4-byte aligned, we have to be 10837469Ssklower * above the beginning of the mbuf, and it is ok just 10937469Ssklower * to slide it back. 11037469Ssklower */ 11137469Ssklower caddr_t ocp = m->m_data; 11236401Ssklower 11337469Ssklower m->m_data = (caddr_t)(((int)m->m_data) & ~0x3); 11437469Ssklower ovbcopy(ocp, m->m_data, (unsigned)m->m_len); 11536401Ssklower } 11636401Ssklower CHANGE_MTYPE(m, TPMT_DATA); 11736401Ssklower 11837469Ssklower /* we KNOW that there is at least 1 byte in this mbuf 11937469Ssklower and that it is hdr->tpdu_li XXXXXXX! */ 12036401Ssklower 12137469Ssklower hdrlen = 1 + *mtod( m, u_char *); 12236401Ssklower 12336401Ssklower /* 12436401Ssklower * now pull up the whole tp header 12536401Ssklower */ 12637469Ssklower if ( m->m_len < hdrlen) { 12737469Ssklower if ((m = m_pullup(m, hdrlen)) == MNULL ) { 12836401Ssklower IncStat(ts_recv_drop); 12936401Ssklower return (struct mbuf *)0; 13036401Ssklower } 13136401Ssklower } 13236401Ssklower IFDEBUG(D_INPUT) 13336401Ssklower printf( 13436401Ssklower " at end: m 0x%x hdr->tpdu_li 0x%x m_len 0x%x\n",m, 13537469Ssklower hdrlen, m->m_len); 13636401Ssklower ENDDEBUG 13736401Ssklower return m; 13836401Ssklower } 13936401Ssklower 14036401Ssklower /* begin groan 14136401Ssklower * -- this array and the following macros allow you to step through the 14236401Ssklower * parameters of the variable part of a header 14336401Ssklower * note that if for any reason the values of the **_TPDU macros (in tp_events.h) 14436401Ssklower * should change, this array has to be rearranged 14536401Ssklower */ 14636401Ssklower 14736401Ssklower #define TP_LEN_CLASS_0_INDEX 2 14836401Ssklower #define TP_MAX_DATA_INDEX 3 14936401Ssklower 15036401Ssklower static u_char tpdu_info[][4] = 15136401Ssklower { 15236401Ssklower /* length max data len */ 15336401Ssklower /* reg fmt xtd fmt class 0 */ 15436401Ssklower /* UNUSED 0x0 */ 0x0 , 0x0, 0x0, 0x0, 15536401Ssklower /* XPD_TPDU_type 0x1 */ 0x5, 0x8, 0x0, TP_MAX_XPD_DATA, 15636401Ssklower /* XAK_TPDU_type 0x2 */ 0x5 , 0x8, 0x0, 0x0, 15736401Ssklower /* GR_TPDU_type 0x3 */ 0x0 , 0x0, 0x0, 0x0, 15836401Ssklower /* UNUSED 0x4 */ 0x0 , 0x0, 0x0, 0x0, 15936401Ssklower /* UNUSED 0x5 */ 0x0 , 0x0, 0x0, 0x0, 16036401Ssklower /* AK_TPDU_type 0x6 */ 0x5, 0xa, 0x0, 0x0, 16136401Ssklower /* ER_TPDU_type 0x7 */ 0x5, 0x5, 0x0, 0x0, 16236401Ssklower /* DR_TPDU_type 0x8 */ 0x7, 0x7, 0x7, TP_MAX_DR_DATA, 16336401Ssklower /* UNUSED 0x9 */ 0x0 , 0x0, 0x0, 0x0, 16436401Ssklower /* UNUSED 0xa */ 0x0 , 0x0, 0x0, 0x0, 16536401Ssklower /* UNUSED 0xb */ 0x0 , 0x0, 0x0, 0x0, 16636401Ssklower /* DC_TPDU_type 0xc */ 0x6, 0x6, 0x0, 0x0, 16736401Ssklower /* CC_TPDU_type 0xd */ 0x7, 0x7, 0x7, TP_MAX_CC_DATA, 16836401Ssklower /* CR_TPDU_type 0xe */ 0x7, 0x7, 0x7, TP_MAX_CR_DATA, 16936401Ssklower /* DT_TPDU_type 0xf */ 0x5, 0x8, 0x3, 0x0, 17036401Ssklower }; 17136401Ssklower 17242944Ssklower #define CHECK(Phrase, Erval, Stat, Whattodo, Loc)\ 17343334Ssklower if (Phrase) {error = (Erval); errlen = (int)(Loc); IncStat(Stat); tpibrk();\ 17442944Ssklower goto Whattodo; } 17542944Ssklower 17643334Ssklower tpibrk() {} 17743334Ssklower 17836401Ssklower /* 17936401Ssklower * WHENEVER YOU USE THE FOLLOWING MACRO, 18036401Ssklower * BE SURE THE TPDUTYPE IS A LEGIT VALUE FIRST! 18136401Ssklower */ 18236401Ssklower 18342944Ssklower #define WHILE_OPTIONS(P, hdr, format)\ 18442944Ssklower { register caddr_t P = tpdu_info[(hdr)->tpdu_type][(format)] + (caddr_t)hdr;\ 18542944Ssklower caddr_t PLIM = 1 + hdr->tpdu_li + (caddr_t)hdr;\ 18642944Ssklower for (;; P += 2 + ((struct tp_vbp *)P)->tpv_len) {\ 18742944Ssklower CHECK((P > PLIM), E_TP_LENGTH_INVAL, ts_inv_length,\ 18842944Ssklower respond, P - (caddr_t)hdr);\ 18942944Ssklower if (P == PLIM) break; 19036401Ssklower 19142944Ssklower #define END_WHILE_OPTIONS(P) } } 19236401Ssklower 19336401Ssklower /* end groan */ 19436401Ssklower 19536401Ssklower /* 19636401Ssklower * NAME: tp_newsocket() 19736401Ssklower * 19836401Ssklower * CALLED FROM: 19936401Ssklower * tp_input() on incoming CR, when a socket w/ the called suffix 20036401Ssklower * is awaiting a connection request 20136401Ssklower * 20236401Ssklower * FUNCTION and ARGUMENTS: 20336401Ssklower * Create a new socket structure, attach to it a new transport pcb, 20436401Ssklower * using a copy of the net level pcb for the parent socket. 20536401Ssklower * (so) is the parent socket. 20636401Ssklower * (fname) is the foreign address (all that's used is the nsap portion) 20736401Ssklower * 20836401Ssklower * RETURN VALUE: 20936401Ssklower * a new socket structure, being this end of the newly formed connection. 21036401Ssklower * 21136401Ssklower * SIDE EFFECTS: 21236401Ssklower * Sets a few things in the tpcb and net level pcb 21336401Ssklower * 21436401Ssklower * NOTES: 21536401Ssklower */ 21636401Ssklower static struct socket * 21736401Ssklower tp_newsocket(so, fname, cons_channel, class_to_use, netservice) 21836401Ssklower struct socket *so; 21936401Ssklower struct sockaddr *fname; 22036401Ssklower u_int cons_channel; 22136401Ssklower u_char class_to_use; 22236401Ssklower u_int netservice; 22336401Ssklower { 22436401Ssklower register struct tp_pcb *tpcb = sototpcb(so); /* old tpcb, needed below */ 22536401Ssklower struct tp_pcb * newtpcb; 22636401Ssklower 22736401Ssklower /* 22836401Ssklower * sonewconn() gets a new socket structure, 22936401Ssklower * a new lower layer pcb and a new tpcb, 23036401Ssklower * but the pcbs are unnamed (not bound) 23136401Ssklower */ 23236401Ssklower IFTRACE(D_NEWSOCK) 23338841Ssklower tptraceTPCB(TPPTmisc, "newsock: listg_so, _tpcb, so_head", 23439196Ssklower so, tpcb, so->so_head, 0); 23536401Ssklower ENDTRACE 23636401Ssklower 23740636Skarels if ((so = sonewconn(so, SS_ISCONFIRMING)) == (struct socket *)0) 23836401Ssklower return so; 23936401Ssklower IFTRACE(D_NEWSOCK) 24038841Ssklower tptraceTPCB(TPPTmisc, "newsock: after newconn so, so_head", 24138841Ssklower so, so->so_head, 0, 0); 24236401Ssklower ENDTRACE 24336401Ssklower 24436401Ssklower IFDEBUG(D_NEWSOCK) 24537469Ssklower printf("tp_newsocket(channel 0x%x) after sonewconn so 0x%x \n", 24637469Ssklower cons_channel, so); 24737469Ssklower dump_addr(fname); 24836401Ssklower { 24936401Ssklower struct socket *t, *head ; 25036401Ssklower 25136401Ssklower head = so->so_head; 25236401Ssklower t = so; 25336401Ssklower printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n", 25436401Ssklower t, t->so_head, t->so_q0, t->so_q0len); 25536401Ssklower while( (t=t->so_q0) && t!= so && t!= head) 25636401Ssklower printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n", 25736401Ssklower t, t->so_head, t->so_q0, t->so_q0len); 25836401Ssklower } 25936401Ssklower ENDDEBUG 26036401Ssklower 26136401Ssklower /* 26236401Ssklower * before we clobber the old tpcb ptr, get these items from the parent pcb 26336401Ssklower */ 26436401Ssklower newtpcb = sototpcb(so); 26536401Ssklower newtpcb->_tp_param = tpcb->_tp_param; 26636401Ssklower newtpcb->tp_flags = tpcb->tp_flags; 26736401Ssklower newtpcb->tp_lcredit = tpcb->tp_lcredit; 26836401Ssklower newtpcb->tp_l_tpdusize = tpcb->tp_l_tpdusize; 26936401Ssklower newtpcb->tp_lsuffixlen = tpcb->tp_lsuffixlen; 27036401Ssklower bcopy( tpcb->tp_lsuffix, newtpcb->tp_lsuffix, newtpcb->tp_lsuffixlen); 27137469Ssklower soreserve(so, (u_long)tpcb->tp_winsize, (u_long)tpcb->tp_winsize); 27236401Ssklower 27337469Ssklower if( /* old */ tpcb->tp_ucddata) { 27436401Ssklower /* 27537469Ssklower * These data are the connect- , confirm- or disconnect- data. 27636401Ssklower */ 27736401Ssklower struct mbuf *conndata; 27836401Ssklower 27937469Ssklower conndata = m_copy(tpcb->tp_ucddata, 0, (int)M_COPYALL); 28036401Ssklower IFDEBUG(D_CONN) 28136401Ssklower dump_mbuf(conndata, "conndata after mcopy"); 28236401Ssklower ENDDEBUG 28337469Ssklower newtpcb->tp_ucddata = conndata; 28436401Ssklower } 28536401Ssklower 28636401Ssklower tpcb = newtpcb; 28736401Ssklower tpcb->tp_state = TP_LISTENING; 28836401Ssklower tpcb->tp_class = class_to_use; 28936401Ssklower tpcb->tp_netservice = netservice; 29036401Ssklower 29136401Ssklower 29236401Ssklower ASSERT( fname != 0 ) ; /* just checking */ 29336401Ssklower if ( fname ) { 29436401Ssklower /* 29536401Ssklower * tp_route_to takes its address argument in the form of an mbuf. 29636401Ssklower */ 29736401Ssklower struct mbuf *m; 29836401Ssklower int err; 29936401Ssklower 30036401Ssklower MGET(m, M_DONTWAIT, MT_SONAME); /* mbuf type used is confusing */ 30136401Ssklower if (m) { 30236401Ssklower /* 30336401Ssklower * this seems a bit grotesque, but tp_route_to expects 30436401Ssklower * an mbuf * instead of simply a sockaddr; it calls the ll 30536401Ssklower * pcb_connect, which expects the name/addr in an mbuf as well. 30636401Ssklower * sigh. 30736401Ssklower */ 30837469Ssklower bcopy((caddr_t)fname, mtod(m, caddr_t), fname->sa_len); 30937469Ssklower m->m_len = fname->sa_len; 31036401Ssklower 31136401Ssklower /* grot : have to say the kernel can override params in 31236401Ssklower * the passive open case 31336401Ssklower */ 31436401Ssklower tpcb->tp_dont_change_params = 0; 31536401Ssklower err = tp_route_to( m, tpcb, cons_channel); 31636401Ssklower m_free(m); 31736401Ssklower 31836401Ssklower if (!err) 31936401Ssklower goto ok; 32036401Ssklower } 32136401Ssklower IFDEBUG(D_CONN) 32236401Ssklower printf("tp_route_to FAILED! detaching tpcb 0x%x, so 0x%x\n", 32336401Ssklower tpcb, so); 32436401Ssklower ENDDEBUG 32536401Ssklower (void) tp_detach(tpcb); 32636401Ssklower return 0; 32736401Ssklower } 32836401Ssklower ok: 32936401Ssklower IFDEBUG(D_TPINPUT) 33036401Ssklower printf("tp_newsocket returning so 0x%x, sototpcb(so) 0x%x\n", 33136401Ssklower so, sototpcb(so)); 33236401Ssklower ENDDEBUG 33336401Ssklower return so; 33436401Ssklower } 33536401Ssklower 33636401Ssklower #ifndef CONS 33736401Ssklower tpcons_output() 33836401Ssklower { 33936401Ssklower return(0); 34036401Ssklower } 34136401Ssklower #endif !CONS 34236401Ssklower 34336401Ssklower /* 34436401Ssklower * NAME: tp_input() 34536401Ssklower * 34636401Ssklower * CALLED FROM: 34736401Ssklower * net layer input routine 34836401Ssklower * 34936401Ssklower * FUNCTION and ARGUMENTS: 35036401Ssklower * Process an incoming TPDU (m), finding the associated tpcb if there 35136401Ssklower * is one. Create the appropriate type of event and call the driver. 35236401Ssklower * (faddr) and (laddr) are the foreign and local addresses. 35336401Ssklower * 35436401Ssklower * When tp_input() is called we KNOW that the ENTIRE TP HEADER 35536401Ssklower * has been m_pullup-ed. 35636401Ssklower * 35736401Ssklower * RETURN VALUE: Nada 35836401Ssklower * 35936401Ssklower * SIDE EFFECTS: 36036401Ssklower * When using COSNS it may affect the state of the net-level pcb 36136401Ssklower * 36236401Ssklower * NOTE: 36336401Ssklower * The initial value of acktime is 2 so that we will never 36436401Ssklower * have a 0 value for tp_peer_acktime. It gets used in the 36536401Ssklower * computation of the retransmission timer value, and so it 36636401Ssklower * mustn't be zero. 36736401Ssklower * 2 seems like a reasonable minimum. 36836401Ssklower */ 36936401Ssklower ProtoHook 37039929Ssklower tp_input(m, faddr, laddr, cons_channel, dgout_routine, ce_bit) 37136401Ssklower register struct mbuf *m; 37236401Ssklower struct sockaddr *faddr, *laddr; /* NSAP addresses */ 37336401Ssklower u_int cons_channel; 37436401Ssklower int (*dgout_routine)(); 37539929Ssklower int ce_bit; 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; 38242944Ssklower int error = 0; 38336401Ssklower unsigned dutype; 38442944Ssklower u_short dref, sref = 0, acktime = 2, subseq = 0; /*VAX*/ 38542944Ssklower u_char preferred_class = 0, class_to_use = 0; 38642944Ssklower u_char opt, dusize = TP_DFL_TPDUSIZE, addlopt = 0, version; 38736401Ssklower #ifdef TP_PERF_MEAS 38838841Ssklower u_char perf_meas; 38936401Ssklower #endif TP_PERF_MEAS 39044422Ssklower u_char fsufxlen = 0, lsufxlen = 0, intercepted = 0; 39142944Ssklower caddr_t fsufxloc = 0, lsufxloc = 0; 39242944Ssklower int tpdu_len = 0; 39342944Ssklower u_int takes_data = FALSE; 39442944Ssklower u_int fcc_present = FALSE; 39542944Ssklower int errlen = 0; 39636401Ssklower struct tp_conn_param tpp; 39736401Ssklower int tpcons_output(); 39836401Ssklower 39938841Ssklower again: 40036401Ssklower #ifdef TP_PERF_MEAS 40138841Ssklower GET_CUR_TIME( &e.e_time ); perf_meas = 0; 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 40936401Ssklower /* 41036401Ssklower * get the actual tpdu length - necessary for monitoring 41136401Ssklower * and for checksumming 41236401Ssklower * 41336401Ssklower * Also, maybe measure the mbuf chain lengths and sizes. 41436401Ssklower */ 41536401Ssklower 41636401Ssklower { register struct mbuf *n=m; 41736401Ssklower # ifdef ARGO_DEBUG 41836401Ssklower int chain_length = 0; 41936401Ssklower # endif ARGO_DEBUG 42036401Ssklower 42136401Ssklower for(;;) { 42236401Ssklower tpdu_len += n->m_len; 42336401Ssklower IFDEBUG(D_MBUF_MEAS) 42437469Ssklower if( n->m_flags & M_EXT) { 42536401Ssklower IncStat(ts_mb_cluster); 42636401Ssklower } else { 42736401Ssklower IncStat(ts_mb_small); 42836401Ssklower } 42936401Ssklower chain_length ++; 43036401Ssklower ENDDEBUG 43136401Ssklower if (n->m_next == MNULL ) { 43236401Ssklower break; 43336401Ssklower } 43436401Ssklower n = n->m_next; 43536401Ssklower } 43636401Ssklower IFDEBUG(D_MBUF_MEAS) 43736401Ssklower if(chain_length > 16) 43836401Ssklower chain_length = 0; /* zero used for anything > 16 */ 43936401Ssklower tp_stat.ts_mb_len_distr[chain_length] ++; 44036401Ssklower ENDDEBUG 44136401Ssklower } 44236401Ssklower IFTRACE(D_TPINPUT) 44336401Ssklower tptraceTPCB(TPPTtpduin, hdr->tpdu_type, hdr, hdr->tpdu_li+1, tpdu_len, 44436401Ssklower 0); 44536401Ssklower ENDTRACE 44636401Ssklower 44736401Ssklower dref = ntohs((short)hdr->tpdu_dref); 44836401Ssklower sref = ntohs((short)hdr->tpdu_sref); 44936401Ssklower dutype = (int)hdr->tpdu_type; 45036401Ssklower 45136401Ssklower IFDEBUG(D_TPINPUT) 45236401Ssklower printf("input: dutype 0x%x cons_channel 0x%x dref 0x%x\n", dutype, 45336401Ssklower cons_channel, dref); 45436401Ssklower printf("input: dref 0x%x sref 0x%x\n", dref, sref); 45536401Ssklower ENDDEBUG 45636401Ssklower IFTRACE(D_TPINPUT) 45736401Ssklower tptrace(TPPTmisc, "channel dutype dref ", 45836401Ssklower cons_channel, dutype, dref, 0); 45936401Ssklower ENDTRACE 46036401Ssklower 46136401Ssklower 46236401Ssklower #ifdef ARGO_DEBUG 46336401Ssklower if( (dutype < TP_MIN_TPDUTYPE) || (dutype > TP_MAX_TPDUTYPE)) { 46436401Ssklower printf("BAD dutype! 0x%x, channel 0x%x dref 0x%x\n", 46536401Ssklower dutype, cons_channel, dref); 46636401Ssklower dump_buf (m, sizeof( struct mbuf )); 46736401Ssklower 46836401Ssklower IncStat(ts_inv_dutype); 46936401Ssklower goto discard; 47036401Ssklower } 47136401Ssklower #endif ARGO_DEBUG 47236401Ssklower 47336401Ssklower CHECK( (dutype < TP_MIN_TPDUTYPE || dutype > TP_MAX_TPDUTYPE), 47436401Ssklower E_TP_INV_TPDU, ts_inv_dutype, respond, 47536401Ssklower 2 ); 47636401Ssklower /* unfortunately we can't take the address of the tpdu_type field, 47736401Ssklower * since it's a bit field - so we just use the constant offset 2 47836401Ssklower */ 47936401Ssklower 48036401Ssklower /* Now this isn't very neat but since you locate a pcb one way 48136401Ssklower * at the beginning of connection establishment, and by 48236401Ssklower * the dref for each tpdu after that, we have to treat CRs differently 48336401Ssklower */ 48436401Ssklower if ( dutype == CR_TPDU_type ) { 48536401Ssklower u_char alt_classes = 0; 48636401Ssklower 48737469Ssklower preferred_class = 1 << hdr->tpdu_CRclass; 48836401Ssklower opt = hdr->tpdu_CRoptions; 48936401Ssklower 49036401Ssklower WHILE_OPTIONS(P, hdr, 1 ) /* { */ 49136401Ssklower 49236401Ssklower switch( vbptr(P)->tpv_code ) { 49336401Ssklower 49436401Ssklower case TPP_tpdu_size: 49536401Ssklower vb_getval(P, u_char, dusize); 49636401Ssklower IFDEBUG(D_TPINPUT) 49736401Ssklower printf("CR dusize 0x%x\n", dusize); 49836401Ssklower ENDDEBUG 49942944Ssklower /* COS tests: NBS IA (Dec. 1987) Sec. 4.5.2.1 */ 50042944Ssklower if (dusize < TP_MIN_TPDUSIZE || dusize > TP_MAX_TPDUSIZE) 50142944Ssklower dusize = TP_DFL_TPDUSIZE; 50236401Ssklower break; 50336401Ssklower case TPP_addl_opt: 50436401Ssklower vb_getval(P, u_char, addlopt); 50536401Ssklower break; 50636401Ssklower case TPP_calling_sufx: 50736401Ssklower /* could use vb_getval, but we want to save the loc & len 50836401Ssklower * for later use 50936401Ssklower */ 51036401Ssklower fsufxloc = (caddr_t) &vbptr(P)->tpv_val; 51136401Ssklower fsufxlen = vbptr(P)->tpv_len; 51236401Ssklower IFDEBUG(D_TPINPUT) 51336401Ssklower printf("CR fsufx:"); 51436401Ssklower { register int j; 51536401Ssklower for(j=0; j<fsufxlen; j++ ) { 51636401Ssklower printf(" 0x%x. ", *((caddr_t)(fsufxloc+j)) ); 51736401Ssklower } 51836401Ssklower printf("\n"); 51936401Ssklower } 52036401Ssklower ENDDEBUG 52136401Ssklower break; 52236401Ssklower case TPP_called_sufx: 52336401Ssklower /* could use vb_getval, but we want to save the loc & len 52436401Ssklower * for later use 52536401Ssklower */ 52636401Ssklower lsufxloc = (caddr_t) &vbptr(P)->tpv_val; 52736401Ssklower lsufxlen = vbptr(P)->tpv_len; 52836401Ssklower IFDEBUG(D_TPINPUT) 52936401Ssklower printf("CR lsufx:"); 53036401Ssklower { register int j; 53136401Ssklower for(j=0; j<lsufxlen; j++ ) { 53237469Ssklower printf(" 0x%x. ", *((u_char *)(lsufxloc+j)) ); 53336401Ssklower } 53436401Ssklower printf("\n"); 53536401Ssklower } 53636401Ssklower ENDDEBUG 53736401Ssklower break; 53836401Ssklower 53936401Ssklower #ifdef TP_PERF_MEAS 54036401Ssklower case TPP_perf_meas: 54136401Ssklower vb_getval(P, u_char, perf_meas); 54236401Ssklower break; 54336401Ssklower #endif TP_PERF_MEAS 54436401Ssklower 54536401Ssklower case TPP_vers: 54636401Ssklower /* not in class 0; 1 octet; in CR_TPDU only */ 54742944Ssklower /* COS tests says if version wrong, use default version!?XXX */ 54836401Ssklower CHECK( (vbval(P, u_char) != TP_VERSION ), 54942491Ssklower E_TP_INV_PVAL, ts_inv_pval, setversion, 55042944Ssklower (1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) ); 55142491Ssklower setversion: 55242491Ssklower version = vbval(P, u_char); 55336401Ssklower break; 55436401Ssklower case TPP_acktime: 55536401Ssklower vb_getval(P, u_short, acktime); 55636401Ssklower acktime = ntohs(acktime); 55736401Ssklower acktime = acktime/500; /* convert to slowtimo ticks */ 55836401Ssklower if((short)acktime <=0 ) 55936401Ssklower acktime = 2; /* don't allow a bad peer to screw us up */ 56036401Ssklower IFDEBUG(D_TPINPUT) 56136401Ssklower printf("CR acktime 0x%x\n", acktime); 56236401Ssklower ENDDEBUG 56336401Ssklower break; 56436401Ssklower 56536401Ssklower case TPP_alt_class: 56636401Ssklower { 56736401Ssklower u_char *aclass = 0; 56836401Ssklower register int i; 56942944Ssklower static u_char bad_alt_classes[5] = 57042944Ssklower { ~0, ~3, ~5, ~0xf, ~0x1f}; 57136401Ssklower 57242944Ssklower aclass = 57342944Ssklower (u_char *) &(((struct tp_vbp *)P)->tpv_val); 57436401Ssklower for (i = ((struct tp_vbp *)P)->tpv_len; i>0; i--) { 57542944Ssklower alt_classes |= (1<<((*aclass++)>>4)); 57636401Ssklower } 57742944Ssklower CHECK( (bad_alt_classes[hdr->tpdu_CRclass] & alt_classes), 57842944Ssklower E_TP_INV_PVAL, ts_inv_aclass, respond, 57942944Ssklower ((caddr_t)aclass) - (caddr_t)hdr); 58036401Ssklower IFDEBUG(D_TPINPUT) 58136401Ssklower printf("alt_classes 0x%x\n", alt_classes); 58236401Ssklower ENDDEBUG 58336401Ssklower } 58436401Ssklower break; 58536401Ssklower 58636401Ssklower case TPP_security: 58736401Ssklower case TPP_residER: 58836401Ssklower case TPP_priority: 58936401Ssklower case TPP_transdelay: 59036401Ssklower case TPP_throughput: 59136401Ssklower case TPP_addl_info: 59236401Ssklower case TPP_subseq: 59336401Ssklower IFDEBUG(D_TPINPUT) 59436401Ssklower printf("param ignored CR_TPDU code= 0x%x\n", 59536401Ssklower vbptr(P)->tpv_code); 59636401Ssklower ENDDEBUG 59736401Ssklower IncStat(ts_param_ignored); 59836401Ssklower break; 59936401Ssklower 60036401Ssklower case TPP_checksum: 60136401Ssklower IFDEBUG(D_TPINPUT) 60236401Ssklower printf("CR before cksum\n"); 60336401Ssklower ENDDEBUG 60436401Ssklower 60536401Ssklower CHECK( iso_check_csum(m, tpdu_len), 60636401Ssklower E_TP_INV_PVAL, ts_bad_csum, discard, 0) 60736401Ssklower 60836401Ssklower IFDEBUG(D_TPINPUT) 60936401Ssklower printf("CR before cksum\n"); 61036401Ssklower ENDDEBUG 61136401Ssklower break; 61236401Ssklower 61336401Ssklower default: 61436401Ssklower IncStat(ts_inv_pcode); 61536401Ssklower error = E_TP_INV_PCODE; 61636401Ssklower goto discard; 61736401Ssklower 61836401Ssklower } 61936401Ssklower 62036401Ssklower /* } */ END_WHILE_OPTIONS(P) 62136401Ssklower 62244422Ssklower if (lsufxlen == 0) { 62336401Ssklower /* can't look for a tpcb w/o any called sufx */ 62436401Ssklower error = E_TP_LENGTH_INVAL; 62536401Ssklower IncStat(ts_inv_sufx); 62636401Ssklower goto respond; 62736401Ssklower } else { 62844422Ssklower register struct tp_pcb *t; 62936401Ssklower 630*44601Ssklower for (t = tp_intercepts; t ; t = t->tp_nextlisten) { 63144422Ssklower if (laddr->sa_family != t->tp_nlproto->nlp_afamily) 63236401Ssklower continue; 633*44601Ssklower if ((*t->tp_nlproto->nlp_cmpnetaddr)( 63444422Ssklower t->tp_npcb, laddr, TP_LOCAL)) { 63544422Ssklower intercepted = 1; 63644422Ssklower goto check_duplicate_cr; 63736401Ssklower } 63836401Ssklower } 639*44601Ssklower for (t = tp_listeners; t ; t = t->tp_nextlisten) 640*44601Ssklower if (bcmp(lsufxloc, t->tp_lsuffix, lsufxlen) == 0 && 641*44601Ssklower laddr->sa_family == t->tp_nlproto->nlp_afamily) 642*44601Ssklower break; 64344422Ssklower CHECK(t == 0, E_TP_NO_SESSION, ts_inv_sufx, respond, 64436401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 64536401Ssklower /* _tpduf is the fixed part; add 2 to get the dref bits of 64636401Ssklower * the fixed part (can't take the address of a bit field) 64736401Ssklower */ 648*44601Ssklower IFDEBUG(D_TPINPUT) 649*44601Ssklower printf("checking if dup CR\n"); 650*44601Ssklower ENDDEBUG 65144422Ssklower check_duplicate_cr: 65244422Ssklower tpcb = t; 65344422Ssklower for (t = tpcb->tp_next; t != tpcb; t = t->tp_next) { 65444422Ssklower if (sref != t->tp_fref) 65544422Ssklower continue; 65644422Ssklower if ((*tpcb->tp_nlproto->nlp_cmpnetaddr)( 65744422Ssklower t->tp_npcb, faddr, TP_FOREIGN)) { 65844422Ssklower IFDEBUG(D_TPINPUT) 65944422Ssklower printf("duplicate CR discarded\n"); 66044422Ssklower ENDDEBUG 66144422Ssklower goto discard; 66244422Ssklower } 66344422Ssklower } 66444422Ssklower IFTRACE(D_TPINPUT) 66544422Ssklower tptrace(TPPTmisc, "tp_input: tpcb *lsufxloc tpstate", 66644422Ssklower tpcb, *lsufxloc, tpcb->tp_state, 0); 66744422Ssklower ENDTRACE 66836401Ssklower } 66936401Ssklower 67036401Ssklower /* 67136401Ssklower * WE HAVE A TPCB 67236401Ssklower * already know that the classes in the CR match at least 67336401Ssklower * one class implemented, but we don't know yet if they 67436401Ssklower * include any classes permitted by this server. 67536401Ssklower */ 67636401Ssklower 67736401Ssklower IFDEBUG(D_TPINPUT) 67836401Ssklower printf("HAVE A TPCB 1: 0x%x\n", tpcb); 67936401Ssklower ENDDEBUG 68036401Ssklower IFDEBUG(D_CONN) 68136401Ssklower printf( 68236401Ssklower "CR: bef CHKS: flags 0x%x class_to_use 0x%x alt 0x%x opt 0x%x tp_class 0x%x\n", 68336401Ssklower tpcb->tp_flags, class_to_use, alt_classes, opt, tpcb->tp_class); 68436401Ssklower ENDDEBUG 68536401Ssklower /* tpcb->tp_class doesn't include any classes not implemented */ 68636401Ssklower class_to_use = (preferred_class & tpcb->tp_class); 68736401Ssklower if( (class_to_use = preferred_class & tpcb->tp_class) == 0 ) 68836401Ssklower class_to_use = alt_classes & tpcb->tp_class; 68936401Ssklower 69036401Ssklower class_to_use = 1 << tp_mask_to_num(class_to_use); 69136401Ssklower 69236401Ssklower { 69336401Ssklower tpp = tpcb->_tp_param; 69436401Ssklower tpp.p_class = class_to_use; 69536401Ssklower tpp.p_tpdusize = dusize; 69636401Ssklower tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT; 69736401Ssklower tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD; 69836401Ssklower tpp.p_use_checksum = (tpp.p_class == TP_CLASS_0)?0: 69936401Ssklower (addlopt & TPAO_NO_CSUM) == 0; 70042491Ssklower tpp.p_version = version; 70136401Ssklower #ifdef notdef 70236401Ssklower tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC; 70336401Ssklower tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD; 70436401Ssklower tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC; 70536401Ssklower #endif notdef 70636401Ssklower 70736401Ssklower CHECK( 70836401Ssklower tp_consistency(tpcb, 0 /* not force or strict */, &tpp) != 0, 70936401Ssklower E_TP_NEGOT_FAILED, ts_negotfailed, respond, 71036401Ssklower (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 71136401Ssklower /* ^ more or less the location of class */ 71236401Ssklower ) 71336401Ssklower } 71436401Ssklower IFTRACE(D_CONN) 71536401Ssklower tptrace(TPPTmisc, 71636401Ssklower "after 1 consist class_to_use class, out, tpconsout", 71736401Ssklower class_to_use, 71836401Ssklower tpcb->tp_class, dgout_routine, tpcons_output 71936401Ssklower ); 72036401Ssklower ENDTRACE 72136401Ssklower CHECK( 72236401Ssklower ((class_to_use == TP_CLASS_0)&&(dgout_routine != tpcons_output)), 72336401Ssklower E_TP_NEGOT_FAILED, ts_negotfailed, respond, 72436401Ssklower (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 72536401Ssklower /* ^ more or less the location of class */ 72636401Ssklower ) 72736401Ssklower IFDEBUG(D_CONN) 72836401Ssklower printf("CR: after CRCCCHECKS: tpcb 0x%x, flags 0x%x\n", 72936401Ssklower tpcb, tpcb->tp_flags); 73036401Ssklower ENDDEBUG 73136401Ssklower takes_data = TRUE; 73236401Ssklower e.ATTR(CR_TPDU).e_cdt = hdr->tpdu_CRcdt; 73336401Ssklower e.ev_number = CR_TPDU; 73436401Ssklower 73536401Ssklower so = tpcb->tp_sock; 73636401Ssklower if (so->so_options & SO_ACCEPTCONN) { 73744422Ssklower struct tp_pcb *parent_tpcb = tpcb; 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, 74937469Ssklower ((tpcb->tp_netservice == IN_CLNS) ? IN_CLNS : 75037469Ssklower (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 75437469Ssklower * 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); 762*44601Ssklower insque(tpcb, parent_tpcb); 76336401Ssklower 76436401Ssklower /* 76537469Ssklower * Stash the addresses in the net level pcb 76636401Ssklower * kind of like a pcbconnect() but don't need 76736401Ssklower * or want all those checks. 76836401Ssklower */ 76936401Ssklower (tpcb->tp_nlproto->nlp_putnetaddr)(so->so_pcb, faddr, TP_FOREIGN); 77036401Ssklower (tpcb->tp_nlproto->nlp_putnetaddr)(so->so_pcb, laddr, TP_LOCAL); 77136401Ssklower 77237469Ssklower /* stash the f suffix in the new tpcb */ 77338841Ssklower bcopy(fsufxloc, tpcb->tp_fsuffix, fsufxlen); 77444422Ssklower /* l suffix is already there, unless this is an intercept case */ 77544422Ssklower if (intercepted) 77644422Ssklower bcopy(lsufxloc, tpcb->tp_lsuffix, lsufxlen); 77737469Ssklower (tpcb->tp_nlproto->nlp_putsufx) 77837469Ssklower (so->so_pcb, fsufxloc, fsufxlen, TP_FOREIGN); 77938841Ssklower (tpcb->tp_nlproto->nlp_putsufx) 78038841Ssklower (so->so_pcb, lsufxloc, lsufxlen, TP_LOCAL); 78136401Ssklower #ifdef TP_PERF_MEAS 78236401Ssklower if( tpcb->tp_perf_on = perf_meas ) { /* assignment */ 78336401Ssklower /* ok, let's create an mbuf for stashing the 78436401Ssklower * statistics if one doesn't already exist 78536401Ssklower */ 78636401Ssklower (void) tp_setup_perf(tpcb); 78736401Ssklower } 78836401Ssklower #endif TP_PERF_MEAS 78936401Ssklower tpcb->tp_fref = sref; 79036401Ssklower 79136401Ssklower /* We've already checked for consistency with the options 79236401Ssklower * set in tpp, but we couldn't set them earlier because 79336401Ssklower * we didn't want to change options in the LISTENING tpcb. 79436401Ssklower * Now we set the options in the new socket's tpcb. 79536401Ssklower */ 79636401Ssklower (void) tp_consistency( tpcb, TP_FORCE, &tpp); 79736401Ssklower 79836401Ssklower if(!tpcb->tp_use_checksum) 79936401Ssklower IncStat(ts_csum_off); 80036401Ssklower if(tpcb->tp_xpd_service) 80136401Ssklower IncStat(ts_use_txpd); 80236401Ssklower if(tpcb->tp_xtd_format) 80336401Ssklower IncStat(ts_xtd_fmt); 80436401Ssklower 80536401Ssklower /* 80636401Ssklower * Get the maximum transmission unit from the lower layer(s) 80736401Ssklower * so we can negotiate a reasonable max TPDU size. 80836401Ssklower */ 80936401Ssklower (tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb, 81036401Ssklower &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0); 81136401Ssklower tpcb->tp_peer_acktime = acktime; 81236401Ssklower 81336401Ssklower /* 81436401Ssklower * The following kludge is used to test retransmissions and 81536401Ssklower * timeout during connection establishment. 81636401Ssklower */ 81736401Ssklower IFDEBUG(D_ZDREF) 81836401Ssklower IncStat(ts_zdebug); 81937469Ssklower /*tpcb->tp_fref = 0;*/ 82036401Ssklower ENDDEBUG 82136401Ssklower } 82236401Ssklower IncStat(ts_CR_rcvd); 82339929Ssklower if (!tpcb->tp_cebit_off) { 82439929Ssklower tpcb->tp_win_recv = tp_start_win << 8; 82539929Ssklower tpcb->tp_cong_sample.cs_size = 0; 82639929Ssklower LOCAL_CREDIT(tpcb); 82739929Ssklower CONG_INIT_SAMPLE(tpcb); 82839929Ssklower CONG_UPDATE_SAMPLE(tpcb, ce_bit); 82939929Ssklower } 83039929Ssklower tpcb->tp_ackrcvd = 0; 83136401Ssklower } else if ( dutype == ER_TPDU_type ) { 83236401Ssklower /* 83336401Ssklower * ER TPDUs have to be recognized separately 83436401Ssklower * because they don't necessarily have a tpcb 83536401Ssklower * with them and we don't want err out looking for such 83636401Ssklower * a beast. 83736401Ssklower * We could put a bunch of little kludges in the 83836401Ssklower * next section of code so it would avoid references to tpcb 83936401Ssklower * if dutype == ER_TPDU_type but we don't want code for ERs to 84036401Ssklower * mess up code for data transfer. 84136401Ssklower */ 84236401Ssklower IncStat(ts_ER_rcvd); 84336401Ssklower e.ev_number = ER_TPDU; 84436401Ssklower e.ATTR(ER_TPDU).e_reason = (u_char)hdr->tpdu_ERreason; 84536401Ssklower takes_data = 1; 84636401Ssklower } else { 84736401Ssklower /* tpdu type is CC, XPD, XAK, GR, AK, DR, DC, or DT */ 84836401Ssklower 84936401Ssklower /* In the next 4 checks, 85036401Ssklower * _tpduf is the fixed part; add 2 to get the dref bits of 85136401Ssklower * the fixed part (can't take the address of a bit field) 85236401Ssklower */ 85336401Ssklower if(cons_channel) { 85436401Ssklower #if NARGOXTWENTYFIVE > 0 85536401Ssklower extern struct tp_pcb *cons_chan_to_tpcb(); 85636401Ssklower 85736401Ssklower tpcb = cons_chan_to_tpcb( cons_channel ); 85836401Ssklower /* Problem: We may have a legit 85936401Ssklower * error situation yet we may or may not have 86036401Ssklower * a correspondence between the tpcb and the vc, 86136401Ssklower * e.g., TP4cr--> <no dice, respond w/ DR on vc> 86236401Ssklower * <--- DR 86336401Ssklower * Now it's up to TP to look at the tpdu and do one of: 86436401Ssklower * confirm(dgm)(cr), confirm(circuit)(cr), reject(cr), or 86536401Ssklower * nothing, if the circuit is already open (any other tpdu). 86636401Ssklower * Sigh. 86736401Ssklower */ 86836401Ssklower 86936401Ssklower /* I don't know about this error value */ 87036401Ssklower CHECK( (tpcb == (struct tp_pcb *)0) , 87136401Ssklower E_TP_NO_CR_ON_NC, ts_inv_dref, respond, 87236401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 87336401Ssklower #else 87436401Ssklower printf("tp_input(): X25 NOT CONFIGURED!!\n"); 87536401Ssklower #endif NARGOXTWENTYFIVE > 0 87636401Ssklower 87736401Ssklower } else { 87836401Ssklower 87936401Ssklower CHECK( ((int)dref <= 0 || dref >= N_TPREF) , 88042944Ssklower E_TP_MISM_REFS,ts_inv_dref, nonx_dref, 88136401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 88236401Ssklower CHECK( ((tpcb = tp_ref[dref].tpr_pcb ) == (struct tp_pcb *) 0 ), 88342944Ssklower E_TP_MISM_REFS,ts_inv_dref, nonx_dref, 88436401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 88536401Ssklower CHECK( (tpcb->tp_refp->tpr_state == REF_FREE), 88642944Ssklower E_TP_MISM_REFS,ts_inv_dref, nonx_dref, 88736401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 88836401Ssklower } 88936401Ssklower 89036401Ssklower IFDEBUG(D_TPINPUT) 89136401Ssklower printf("HAVE A TPCB 2: 0x%x\n", tpcb); 89236401Ssklower ENDDEBUG 89336401Ssklower 89436401Ssklower /* causes a DR to be sent for CC; ER for all else */ 89536401Ssklower CHECK( (tpcb->tp_refp->tpr_state == REF_FROZEN), 89636401Ssklower (dutype == CC_TPDU_type?E_TP_NO_SESSION:E_TP_MISM_REFS), 89736401Ssklower ts_inv_dref, respond, 89836401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 89936401Ssklower 90036401Ssklower IFDEBUG(D_TPINPUT) 90136401Ssklower printf("state of dref %d ok, tpcb 0x%x\n", dref,tpcb); 90236401Ssklower ENDDEBUG 90336401Ssklower /* 90436401Ssklower * At this point the state of the dref could be 90536401Ssklower * FROZEN: tpr_pcb == NULL, has ( reference only) timers 90636401Ssklower * for example, DC may arrive after the close() has detached 90736401Ssklower * the tpcb (e.g., if user turned off SO_LISTEN option) 90836401Ssklower * OPENING : a tpcb exists but no timers yet 90936401Ssklower * OPEN : tpcb exists & timers are outstanding 91036401Ssklower */ 91136401Ssklower 91239929Ssklower if (!tpcb->tp_cebit_off) 91339929Ssklower CONG_UPDATE_SAMPLE(tpcb, ce_bit); 91439929Ssklower 91536401Ssklower dusize = tpcb->tp_tpdusize; 91636401Ssklower 91736401Ssklower dutype = hdr->tpdu_type << 8; /* for the switch below */ 91836401Ssklower 91936401Ssklower WHILE_OPTIONS(P, hdr, tpcb->tp_xtd_format) /* { */ 92036401Ssklower 92137469Ssklower #define caseof(x,y) case (((x)<<8)+(y)) 92236401Ssklower switch( dutype | vbptr(P)->tpv_code ) { 92336401Ssklower 92436401Ssklower caseof( CC_TPDU_type, TPP_addl_opt ): 92536401Ssklower /* not in class 0; 1 octet */ 92636401Ssklower vb_getval(P, u_char, addlopt); 92736401Ssklower break; 92836401Ssklower caseof( CC_TPDU_type, TPP_tpdu_size ): 92942944Ssklower { 93042944Ssklower u_char odusize = dusize; 93136401Ssklower vb_getval(P, u_char, dusize); 93242944Ssklower CHECK( (dusize < TP_MIN_TPDUSIZE || 93342944Ssklower dusize > TP_MAX_TPDUSIZE || dusize > odusize), 93442944Ssklower E_TP_INV_PVAL, ts_inv_pval, respond, 93542944Ssklower (1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) ) 93636401Ssklower IFDEBUG(D_TPINPUT) 93736401Ssklower printf("CC dusize 0x%x\n", dusize); 93836401Ssklower ENDDEBUG 93942944Ssklower } 94036401Ssklower break; 94136401Ssklower caseof( CC_TPDU_type, TPP_calling_sufx): 94236401Ssklower IFDEBUG(D_TPINPUT) 94336401Ssklower printf("CC calling (local) sufxlen 0x%x\n", lsufxlen); 94436401Ssklower ENDDEBUG 94536401Ssklower lsufxloc = (caddr_t) &vbptr(P)->tpv_val; 94636401Ssklower lsufxlen = vbptr(P)->tpv_len; 94736401Ssklower break; 94836401Ssklower caseof( CC_TPDU_type, TPP_acktime ): 94936401Ssklower /* class 4 only, 2 octets */ 95036401Ssklower vb_getval(P, u_short, acktime); 95136401Ssklower acktime = acktime/500; /* convert to slowtimo ticks */ 95236401Ssklower if( (short)acktime <=0 ) 95336401Ssklower acktime = 2; 95436401Ssklower break; 95536401Ssklower caseof( CC_TPDU_type, TPP_called_sufx): 95636401Ssklower fsufxloc = (caddr_t) &vbptr(P)->tpv_val; 95736401Ssklower fsufxlen = vbptr(P)->tpv_len; 95836401Ssklower IFDEBUG(D_TPINPUT) 95936401Ssklower printf("CC called (foreign) sufx len %d\n", fsufxlen); 96036401Ssklower ENDDEBUG 96136401Ssklower break; 96236401Ssklower 96336401Ssklower caseof( CC_TPDU_type, TPP_checksum): 96436401Ssklower caseof( DR_TPDU_type, TPP_checksum): 96536401Ssklower caseof( DT_TPDU_type, TPP_checksum): 96636401Ssklower caseof( XPD_TPDU_type, TPP_checksum): 96736401Ssklower if( tpcb->tp_use_checksum ) { 96836401Ssklower CHECK( iso_check_csum(m, tpdu_len), 96936401Ssklower E_TP_INV_PVAL, ts_bad_csum, discard, 0) 97036401Ssklower } 97136401Ssklower break; 97236401Ssklower 97336401Ssklower /* this is different from the above because in the context 97436401Ssklower * of concat/ sep tpdu_len might not be the same as hdr len 97536401Ssklower */ 97636401Ssklower caseof( AK_TPDU_type, TPP_checksum): 97736401Ssklower caseof( XAK_TPDU_type, TPP_checksum): 97836401Ssklower caseof( DC_TPDU_type, TPP_checksum): 97936401Ssklower if( tpcb->tp_use_checksum ) { 98037469Ssklower CHECK( iso_check_csum(m, (int)hdr->tpdu_li + 1), 98136401Ssklower E_TP_INV_PVAL, ts_bad_csum, discard, 0) 98236401Ssklower } 98336401Ssklower break; 98436401Ssklower #ifdef notdef 98536401Ssklower caseof( DR_TPDU_type, TPP_addl_info ): 98636401Ssklower /* ignore - its length and meaning are 98736401Ssklower * user defined and there's no way 98836401Ssklower * to pass this info to the user anyway 98936401Ssklower */ 99036401Ssklower break; 99136401Ssklower #endif notdef 99236401Ssklower 99336401Ssklower caseof( AK_TPDU_type, TPP_subseq ): 99436401Ssklower /* used after reduction of window */ 99536401Ssklower vb_getval(P, u_short, subseq); 99636401Ssklower subseq = ntohs(subseq); 99736401Ssklower IFDEBUG(D_ACKRECV) 99836401Ssklower printf("AK Subsequence # 0x%x\n", subseq); 99936401Ssklower ENDDEBUG 100036401Ssklower break; 100136401Ssklower 100236401Ssklower caseof( AK_TPDU_type, TPP_flow_cntl_conf ): 100336401Ssklower { 100436401Ssklower u_int ylwe; 100536401Ssklower u_short ysubseq, ycredit; 100636401Ssklower 100736401Ssklower fcc_present = TRUE; 100836401Ssklower vb_getval(P, u_int, ylwe); 100936401Ssklower vb_getval(P, u_short, ysubseq); 101036401Ssklower vb_getval(P, u_short, ycredit); 101136401Ssklower ylwe = ntohl(ylwe); 101236401Ssklower ysubseq = ntohs(ysubseq); 101336401Ssklower ycredit = ntohs(ycredit); 101436401Ssklower IFDEBUG(D_ACKRECV) 101536401Ssklower printf("AK FCC lwe 0x%x, subseq 0x%x, cdt 0x%x\n", 101636401Ssklower ylwe, ysubseq, ycredit); 101736401Ssklower ENDDEBUG 101836401Ssklower } 101936401Ssklower break; 102036401Ssklower 102136401Ssklower default: 102236401Ssklower IFDEBUG(D_TPINPUT) 102336401Ssklower printf("param ignored dutype 0x%x, code 0x%x\n", 102436401Ssklower dutype, vbptr(P)->tpv_code); 102536401Ssklower ENDDEBUG 102636401Ssklower IFTRACE(D_TPINPUT) 102736401Ssklower tptrace(TPPTmisc, "param ignored dutype code ", 102836401Ssklower dutype, vbptr(P)->tpv_code ,0,0); 102936401Ssklower ENDTRACE 103036401Ssklower IncStat(ts_param_ignored); 103136401Ssklower break; 103236401Ssklower #undef caseof 103336401Ssklower } 103436401Ssklower /* } */ END_WHILE_OPTIONS(P) 103536401Ssklower 103636401Ssklower /* NOTE: the variable dutype has been shifted left! */ 103736401Ssklower 103836401Ssklower switch( hdr->tpdu_type ) { 103936401Ssklower case CC_TPDU_type: 104036401Ssklower /* If CC comes back with an unacceptable class 104136401Ssklower * respond with a DR or ER 104236401Ssklower */ 104336401Ssklower 104436401Ssklower opt = hdr->tpdu_CCoptions; /* 1 byte */ 104536401Ssklower 104636401Ssklower { 104736401Ssklower tpp = tpcb->_tp_param; 104836401Ssklower tpp.p_class = (1<<hdr->tpdu_CCclass); 104936401Ssklower tpp.p_tpdusize = dusize; 105036401Ssklower tpp.p_dont_change_params = 0; 105136401Ssklower tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT; 105236401Ssklower tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD; 105336401Ssklower tpp.p_use_checksum = (addlopt & TPAO_NO_CSUM) == 0; 105436401Ssklower #ifdef notdef 105536401Ssklower tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC; 105636401Ssklower tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD; 105736401Ssklower tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC; 105836401Ssklower #endif notdef 105936401Ssklower 106036401Ssklower CHECK( 106136401Ssklower tp_consistency(tpcb, TP_FORCE, &tpp) != 0, 106236401Ssklower E_TP_NEGOT_FAILED, ts_negotfailed, respond, 106336401Ssklower (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 106436401Ssklower /* ^ more or less the location of class */ 106536401Ssklower ) 106636401Ssklower IFTRACE(D_CONN) 106736401Ssklower tptrace(TPPTmisc, 106836401Ssklower "after 1 consist class, out, tpconsout", 106936401Ssklower tpcb->tp_class, dgout_routine, tpcons_output, 0 107036401Ssklower ); 107136401Ssklower ENDTRACE 107236401Ssklower CHECK( 107336401Ssklower ((class_to_use == TP_CLASS_0)&& 107436401Ssklower (dgout_routine != tpcons_output)), 107536401Ssklower E_TP_NEGOT_FAILED, ts_negotfailed, respond, 107636401Ssklower (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 107736401Ssklower /* ^ more or less the location of class */ 107836401Ssklower ) 107936401Ssklower } 108036401Ssklower if( ! tpcb->tp_use_checksum) 108136401Ssklower IncStat(ts_csum_off); 108236401Ssklower if(tpcb->tp_xpd_service) 108336401Ssklower IncStat(ts_use_txpd); 108436401Ssklower if(tpcb->tp_xtd_format) 108536401Ssklower IncStat(ts_xtd_fmt); 108636401Ssklower 108736401Ssklower IFTRACE(D_CONN) 108836401Ssklower tptrace(TPPTmisc, "after CC class flags dusize CCclass", 108936401Ssklower tpcb->tp_class, tpcb->tp_flags, tpcb->tp_tpdusize, 109036401Ssklower hdr->tpdu_CCclass); 109136401Ssklower ENDTRACE 109236401Ssklower 109336401Ssklower /* 109436401Ssklower * Get the maximum transmission unit from the lower layer(s) 109536401Ssklower * so we can decide how large a TPDU size to negotiate. 109636401Ssklower * It would be nice if the arguments to this 109736401Ssklower * were more reasonable. 109836401Ssklower */ 109936401Ssklower (tpcb->tp_nlproto->nlp_mtu)(tpcb->tp_sock, tpcb->tp_sock->so_pcb, 110036401Ssklower &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0); 110136401Ssklower 110236401Ssklower #ifdef CONS 110336401Ssklower /* Could be that this CC came in on a NEW vc, in which case 110436401Ssklower * we have to confirm it. 110536401Ssklower */ 110636401Ssklower if( cons_channel ) 110736401Ssklower cons_netcmd( CONN_CONFIRM, tpcb->tp_npcb, cons_channel, 110836401Ssklower tpcb->tp_class == TP_CLASS_4); 110936401Ssklower #endif CONS 111036401Ssklower 111136401Ssklower tpcb->tp_peer_acktime = acktime; 111236401Ssklower 111336401Ssklower /* if called or calling suffices appeared on the CC, 111436401Ssklower * they'd better jive with what's in the pcb 111536401Ssklower */ 111636401Ssklower if( fsufxlen ) { 111736401Ssklower CHECK( ((tpcb->tp_fsuffixlen != fsufxlen) || 111836401Ssklower bcmp(fsufxloc, tpcb->tp_fsuffix, fsufxlen)), 111936401Ssklower E_TP_INV_PVAL,ts_inv_sufx, respond, 112036401Ssklower (1+fsufxloc - (caddr_t)hdr)) 112136401Ssklower } 112236401Ssklower if( lsufxlen ) { 112336401Ssklower CHECK( ((tpcb->tp_lsuffixlen != lsufxlen) || 112436401Ssklower bcmp(lsufxloc, tpcb->tp_lsuffix, lsufxlen)), 112536401Ssklower E_TP_INV_PVAL,ts_inv_sufx, respond, 112636401Ssklower (1+lsufxloc - (caddr_t)hdr)) 112736401Ssklower } 112836401Ssklower 112936401Ssklower e.ATTR(CC_TPDU).e_sref = sref; 113036401Ssklower e.ATTR(CC_TPDU).e_cdt = hdr->tpdu_CCcdt; 113136401Ssklower takes_data = TRUE; 113236401Ssklower e.ev_number = CC_TPDU; 113336401Ssklower IncStat(ts_CC_rcvd); 113436401Ssklower break; 113536401Ssklower 113636401Ssklower case DC_TPDU_type: 113736401Ssklower if (sref != tpcb->tp_fref) 113836401Ssklower printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n", 113936401Ssklower sref, tpcb->tp_fref); 114036401Ssklower 114136401Ssklower CHECK( (sref != tpcb->tp_fref), 114242944Ssklower E_TP_MISM_REFS, ts_inv_sufx, discard, 114336401Ssklower (1 + (caddr_t)&hdr->tpdu_DCsref - (caddr_t)hdr)) 114442944Ssklower 114536401Ssklower e.ev_number = DC_TPDU; 114636401Ssklower IncStat(ts_DC_rcvd); 114736401Ssklower break; 114836401Ssklower 114936401Ssklower case DR_TPDU_type: 115036401Ssklower IFTRACE(D_TPINPUT) 115136401Ssklower tptrace(TPPTmisc, "DR recvd", hdr->tpdu_DRreason, 0, 0, 0); 115236401Ssklower ENDTRACE 115342944Ssklower if (sref != tpcb->tp_fref) { 115436401Ssklower printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n", 115536401Ssklower sref, tpcb->tp_fref); 115642944Ssklower } 115736401Ssklower 115842944Ssklower CHECK( (sref != 0 && sref != tpcb->tp_fref && 115942944Ssklower tpcb->tp_state != TP_CRSENT), 116042944Ssklower (TP_ERROR_SNDC | E_TP_MISM_REFS),ts_inv_sufx, respond, 116136401Ssklower (1 + (caddr_t)&hdr->tpdu_DRsref - (caddr_t)hdr)) 116236401Ssklower 116336401Ssklower e.ATTR(DR_TPDU).e_reason = hdr->tpdu_DRreason; 116436401Ssklower e.ATTR(DR_TPDU).e_sref = (u_short)sref; 116536401Ssklower takes_data = TRUE; 116636401Ssklower e.ev_number = DR_TPDU; 116736401Ssklower IncStat(ts_DR_rcvd); 116836401Ssklower break; 116936401Ssklower 117036401Ssklower case ER_TPDU_type: 117136401Ssklower IFTRACE(D_TPINPUT) 117236401Ssklower tptrace(TPPTmisc, "ER recvd", hdr->tpdu_ERreason,0,0,0); 117336401Ssklower ENDTRACE 117436401Ssklower e.ev_number = ER_TPDU; 117536401Ssklower e.ATTR(ER_TPDU).e_reason = hdr->tpdu_ERreason; 117636401Ssklower IncStat(ts_ER_rcvd); 117736401Ssklower break; 117836401Ssklower 117936401Ssklower case AK_TPDU_type: 118036401Ssklower 118136401Ssklower e.ATTR(AK_TPDU).e_subseq = subseq; 118236401Ssklower e.ATTR(AK_TPDU).e_fcc_present = fcc_present; 118336401Ssklower 118436401Ssklower if (tpcb->tp_xtd_format) { 118536401Ssklower #ifdef BYTE_ORDER 118636401Ssklower union seq_type seqeotX; 118736401Ssklower 118836401Ssklower seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 118936401Ssklower e.ATTR(AK_TPDU).e_seq = seqeotX.s_seq; 119036401Ssklower e.ATTR(AK_TPDU).e_cdt = ntohs(hdr->tpdu_AKcdtX); 119136401Ssklower #else 119236401Ssklower e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdtX; 119336401Ssklower e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseqX; 119436401Ssklower #endif BYTE_ORDER 119536401Ssklower } else { 119636401Ssklower e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdt; 119736401Ssklower e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseq; 119836401Ssklower } 119936401Ssklower IFTRACE(D_TPINPUT) 120036401Ssklower tptrace(TPPTmisc, "AK recvd seq cdt subseq fcc_pres", 120136401Ssklower e.ATTR(AK_TPDU).e_seq, e.ATTR(AK_TPDU).e_cdt, 120236401Ssklower subseq, fcc_present); 120336401Ssklower ENDTRACE 120436401Ssklower 120536401Ssklower e.ev_number = AK_TPDU; 120636401Ssklower IncStat(ts_AK_rcvd); 120736401Ssklower IncPStat(tpcb, tps_AK_rcvd); 120836401Ssklower break; 120936401Ssklower 121036401Ssklower case XAK_TPDU_type: 121136401Ssklower if (tpcb->tp_xtd_format) { 121236401Ssklower #ifdef BYTE_ORDER 121336401Ssklower union seq_type seqeotX; 121436401Ssklower 121536401Ssklower seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 121636401Ssklower e.ATTR(XAK_TPDU).e_seq = seqeotX.s_seq; 121736401Ssklower #else 121836401Ssklower e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseqX; 121936401Ssklower #endif BYTE_ORDER 122036401Ssklower } else { 122136401Ssklower e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseq; 122236401Ssklower } 122336401Ssklower e.ev_number = XAK_TPDU; 122436401Ssklower IncStat(ts_XAK_rcvd); 122536401Ssklower IncPStat(tpcb, tps_XAK_rcvd); 122636401Ssklower break; 122736401Ssklower 122836401Ssklower case XPD_TPDU_type: 122936401Ssklower if (tpcb->tp_xtd_format) { 123036401Ssklower #ifdef BYTE_ORDER 123136401Ssklower union seq_type seqeotX; 123236401Ssklower 123336401Ssklower seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 123436401Ssklower e.ATTR(XPD_TPDU).e_seq = seqeotX.s_seq; 123536401Ssklower #else 123636401Ssklower e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseqX; 123736401Ssklower #endif BYTE_ORDER 123836401Ssklower } else { 123936401Ssklower e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseq; 124036401Ssklower } 124136401Ssklower takes_data = TRUE; 124236401Ssklower e.ev_number = XPD_TPDU; 124336401Ssklower IncStat(ts_XPD_rcvd); 124436401Ssklower IncPStat(tpcb, tps_XPD_rcvd); 124536401Ssklower break; 124636401Ssklower 124736401Ssklower case DT_TPDU_type: 124836401Ssklower { /* the y option will cause occasional packets to be dropped. 124936401Ssklower * A little crude but it works. 125036401Ssklower */ 125136401Ssklower 125236401Ssklower IFDEBUG(D_DROP) 125336401Ssklower if(time.tv_usec & 0x4 && hdr->tpdu_DTseq & 0x1) { 125436401Ssklower IncStat(ts_ydebug); 125536401Ssklower goto discard; 125636401Ssklower } 125736401Ssklower ENDDEBUG 125836401Ssklower } 125936401Ssklower if (tpcb->tp_class == TP_CLASS_0) { 126036401Ssklower e.ATTR(DT_TPDU).e_seq = 0; /* actually don't care */ 126136401Ssklower e.ATTR(DT_TPDU).e_eot = (((struct tp0du *)hdr)->tp0du_eot); 126236401Ssklower } else if (tpcb->tp_xtd_format) { 126336401Ssklower #ifdef BYTE_ORDER 126436401Ssklower union seq_type seqeotX; 126536401Ssklower 126636401Ssklower seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 126736401Ssklower e.ATTR(DT_TPDU).e_seq = seqeotX.s_seq; 126836401Ssklower e.ATTR(DT_TPDU).e_eot = seqeotX.s_eot; 126936401Ssklower #else 127036401Ssklower e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseqX; 127136401Ssklower e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeotX; 127236401Ssklower #endif BYTE_ORDER 127336401Ssklower } else { 127436401Ssklower e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseq; 127536401Ssklower e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeot; 127636401Ssklower } 127736401Ssklower if(e.ATTR(DT_TPDU).e_eot) 127836401Ssklower IncStat(ts_eot_input); 127936401Ssklower takes_data = TRUE; 128036401Ssklower e.ev_number = DT_TPDU; 128136401Ssklower IncStat(ts_DT_rcvd); 128236401Ssklower IncPStat(tpcb, tps_DT_rcvd); 128336401Ssklower break; 128436401Ssklower 128536401Ssklower case GR_TPDU_type: 128636401Ssklower tp_indicate(T_DISCONNECT, tpcb, ECONNABORTED); 128736401Ssklower /* drop through */ 128836401Ssklower default: 128936401Ssklower /* this should NEVER happen because there is a 129036401Ssklower * check for dutype well above here 129136401Ssklower */ 129236401Ssklower error = E_TP_INV_TPDU; /* causes an ER */ 129336401Ssklower IFDEBUG(D_TPINPUT) 129436401Ssklower printf("INVALID dutype 0x%x\n", hdr->tpdu_type); 129536401Ssklower ENDDEBUG 129636401Ssklower IncStat(ts_inv_dutype); 129736401Ssklower goto respond; 129836401Ssklower } 129936401Ssklower } 130036401Ssklower /* peel off the tp header; 130136401Ssklower * remember that the du_li doesn't count itself. 130236401Ssklower * This may leave us w/ an empty mbuf at the front of a chain. 130336401Ssklower * We can't just throw away the empty mbuf because hdr still points 130436401Ssklower * into the mbuf's data area and we're still using hdr (the tpdu header) 130536401Ssklower */ 130636401Ssklower m->m_len -= ((int)hdr->tpdu_li + 1); 130737469Ssklower m->m_data += ((int)hdr->tpdu_li + 1); 130836401Ssklower 130937469Ssklower if (takes_data) { 131037469Ssklower int max = tpdu_info[ hdr->tpdu_type ] [TP_MAX_DATA_INDEX]; 131137469Ssklower int datalen = tpdu_len - hdr->tpdu_li - 1, mbtype = MT_DATA; 131242468Ssklower struct cmsghdr c_hdr; 131337469Ssklower struct mbuf *n; 131436401Ssklower 131537469Ssklower CHECK( (max && datalen > max), E_TP_LENGTH_INVAL, 131637469Ssklower ts_inv_length, respond, (max + hdr->tpdu_li + 1) ); 131736401Ssklower switch( hdr->tpdu_type ) { 131837469Ssklower 131936401Ssklower case CR_TPDU_type: 132037469Ssklower c_hdr.cmsg_type = TPOPT_CONN_DATA; 132137469Ssklower goto make_control_msg; 132237469Ssklower 132336401Ssklower case CC_TPDU_type: 132437469Ssklower c_hdr.cmsg_type = TPOPT_CFRM_DATA; 132537469Ssklower goto make_control_msg; 132637469Ssklower 132736401Ssklower case DR_TPDU_type: 132837469Ssklower c_hdr.cmsg_type = TPOPT_DISC_DATA; 132937469Ssklower make_control_msg: 133037469Ssklower c_hdr.cmsg_level = SOL_TRANSPORT; 133137469Ssklower mbtype = MT_CONTROL; 133243334Ssklower MGET(n, M_DONTWAIT, MT_DATA); 133343334Ssklower if (n) { 133443334Ssklower datalen += sizeof(c_hdr); 133543334Ssklower n->m_len = sizeof(c_hdr); 133643334Ssklower c_hdr.cmsg_len = datalen; 133743334Ssklower *mtod(n, struct cmsghdr *) = c_hdr; 133843334Ssklower n->m_next = m; 133943334Ssklower m = n; 134043334Ssklower } else {m_freem(m); m = 0; goto invoke;} 134137469Ssklower /* FALLTHROUGH */ 134237469Ssklower 134336401Ssklower case XPD_TPDU_type: 134437469Ssklower if (mbtype != MT_CONTROL) 134537469Ssklower mbtype = MT_OOBDATA; 134637469Ssklower m->m_flags |= M_EOR; 134737469Ssklower /* FALLTHROUGH */ 134837469Ssklower 134936401Ssklower case DT_TPDU_type: 135037469Ssklower for (n = m; n; n = n->m_next) { 135137469Ssklower MCHTYPE(n, mbtype); 135237469Ssklower } 135343334Ssklower invoke: 135437469Ssklower e.ATTR(DT_TPDU).e_datalen = datalen; 135536401Ssklower e.ATTR(DT_TPDU).e_data = m; 135636401Ssklower break; 135736401Ssklower 135836401Ssklower default: 135936401Ssklower printf( 136036401Ssklower "ERROR in tp_input! hdr->tpdu_type 0x%x takes_data 0x%x m 0x%x\n", 136136401Ssklower hdr->tpdu_type, takes_data, m); 136236401Ssklower break; 136336401Ssklower } 136436401Ssklower /* prevent m_freem() after tp_driver() from throwing it all away */ 136536401Ssklower m = MNULL; 136636401Ssklower } 136736401Ssklower 136836401Ssklower IncStat(ts_tpdu_rcvd); 136936401Ssklower 137036401Ssklower IFDEBUG(D_TPINPUT) 137136401Ssklower printf( "tp_input: before driver, state 0x%x event 0x%x m 0x%x", 137236401Ssklower tpcb->tp_state, e.ev_number, m ); 137336401Ssklower printf(" e.e_data 0x%x\n", e.ATTR(DT_TPDU).e_data); 137436401Ssklower printf("takes_data 0x%x m_len 0x%x, tpdu_len 0x%x\n", 137536401Ssklower takes_data, (m==MNULL)?0:m->m_len, tpdu_len); 137636401Ssklower ENDDEBUG 137736401Ssklower 137836401Ssklower error = tp_driver(tpcb, &e); 137936401Ssklower 138036401Ssklower ASSERT(tpcb != (struct tp_pcb *)0); 138136401Ssklower ASSERT(tpcb->tp_sock != (struct socket *)0); 138236401Ssklower if( tpcb->tp_sock->so_error == 0 ) 138336401Ssklower tpcb->tp_sock->so_error = error; 138436401Ssklower 138536401Ssklower /* Kludge to keep the state tables under control (adding 138636401Ssklower * data on connect & disconnect & freeing the mbuf containing 138736401Ssklower * the data would have exploded the tables and made a big mess ). 138836401Ssklower */ 138936401Ssklower switch(e.ev_number) { 139036401Ssklower case CC_TPDU: 139136401Ssklower case DR_TPDU: 139236401Ssklower case CR_TPDU: 139336401Ssklower m = e.ATTR(CC_TPDU).e_data; /* same field for all three dutypes */ 139436401Ssklower IFDEBUG(D_TPINPUT) 139536401Ssklower printf("after driver, restoring m to 0x%x, takes_data 0x%x\n", 139636401Ssklower m, takes_data); 139736401Ssklower ENDDEBUG 139836401Ssklower break; 139936401Ssklower default: 140036401Ssklower break; 140136401Ssklower } 140236401Ssklower /* Concatenated sequences are terminated by any tpdu that 140336401Ssklower * carries data: CR, CC, DT, XPD, DR. 140436401Ssklower * All other tpdu types may be concatenated: AK, XAK, DC, ER. 140536401Ssklower */ 140636401Ssklower 140736401Ssklower separate: 140836401Ssklower if ( takes_data == 0 ) { 140936401Ssklower ASSERT( m != MNULL ); 141036401Ssklower /* 141136401Ssklower * we already peeled off the prev. tp header so 141236401Ssklower * we can just pull up some more and repeat 141336401Ssklower */ 141436401Ssklower 141537469Ssklower if( m = tp_inputprep(m) ) { 141636401Ssklower IFDEBUG(D_TPINPUT) 141736401Ssklower hdr = mtod(m, struct tpdu *); 141836401Ssklower printf("tp_input @ separate: hdr 0x%x size %d m 0x%x\n", 141936401Ssklower hdr, (int) hdr->tpdu_li + 1, m); 142036401Ssklower dump_mbuf(m, "tp_input after driver, at separate"); 142136401Ssklower ENDDEBUG 142236401Ssklower 142336401Ssklower IncStat(ts_concat_rcvd); 142436401Ssklower goto again; 142536401Ssklower } 142636401Ssklower } 142736401Ssklower if ( m != MNULL ) { 142836401Ssklower IFDEBUG(D_TPINPUT) 142936401Ssklower printf("tp_input : m_freem(0x%x)\n", m); 143036401Ssklower ENDDEBUG 143136401Ssklower m_freem(m); 143236401Ssklower IFDEBUG(D_TPINPUT) 143336401Ssklower printf("tp_input : after m_freem 0x%x\n", m); 143436401Ssklower ENDDEBUG 143536401Ssklower } 143636401Ssklower return (ProtoHook) tpcb; 143736401Ssklower 143836401Ssklower discard: 143936401Ssklower /* class 4: drop the tpdu */ 144036401Ssklower /* class 2,0: Should drop the net connection, if you can figure out 144136401Ssklower * to which connection it applies 144236401Ssklower */ 144336401Ssklower IFDEBUG(D_TPINPUT) 144436401Ssklower printf("tp_input DISCARD\n"); 144536401Ssklower ENDDEBUG 144636401Ssklower IFTRACE(D_TPINPUT) 144736401Ssklower tptrace(TPPTmisc, "tp_input DISCARD m", m,0,0,0); 144836401Ssklower ENDTRACE 144936401Ssklower m_freem(m); 145036401Ssklower IncStat(ts_recv_drop); 145136401Ssklower return (ProtoHook)0; 145236401Ssklower 145342944Ssklower nonx_dref: 145442944Ssklower switch (dutype) { 145542944Ssklower default: 145642944Ssklower goto discard; 145742944Ssklower case CC_TPDU_type: 145842944Ssklower /* error = E_TP_MISM_REFS; */ 145942944Ssklower break; 146042944Ssklower case DR_TPDU_type: 146142944Ssklower error |= TP_ERROR_SNDC; 146242944Ssklower } 146336401Ssklower respond: 146443334Ssklower IFDEBUG(D_TPINPUT) 146542944Ssklower printf("RESPOND: error 0x%x, errlen 0x%x\n", error, errlen); 146636401Ssklower ENDDEBUG 146736401Ssklower IFTRACE(D_TPINPUT) 146842944Ssklower tptrace(TPPTmisc, "tp_input RESPOND m error sref", m, error, sref, 0); 146936401Ssklower ENDTRACE 147042944Ssklower if (sref == 0) 147136401Ssklower goto discard; 147237469Ssklower (void) tp_error_emit(error, (u_long)sref, (struct sockaddr_iso *)faddr, 147342944Ssklower (struct sockaddr_iso *)laddr, m, errlen, tpcb, 147437469Ssklower (int)cons_channel, dgout_routine); 147536401Ssklower IFDEBUG(D_ERROR_EMIT) 147636401Ssklower printf("tp_input after error_emit\n"); 147736401Ssklower ENDDEBUG 147836401Ssklower 147936401Ssklower #ifdef lint 148036401Ssklower printf("",sref,opt); 148136401Ssklower #endif lint 148236401Ssklower IncStat(ts_recv_drop); 148336401Ssklower return (ProtoHook)0; 148436401Ssklower } 148536401Ssklower 148636401Ssklower 148736401Ssklower /* 148836401Ssklower * NAME: tp_headersize() 148936401Ssklower * 149036401Ssklower * CALLED FROM: 149136401Ssklower * tp_emit() and tp_sbsend() 149236401Ssklower * TP needs to know the header size so it can figure out how 149336401Ssklower * much data to put in each tpdu. 149436401Ssklower * 149536401Ssklower * FUNCTION, ARGUMENTS, and RETURN VALUE: 149636401Ssklower * For a given connection, represented by (tpcb), and 149736401Ssklower * tpdu type (dutype), return the size of a tp header. 149836401Ssklower * 149936401Ssklower * RETURNS: the expected size of the heade in bytesr 150036401Ssklower * 150136401Ssklower * SIDE EFFECTS: 150236401Ssklower * 150336401Ssklower * NOTES: It would be nice if it got the network header size as well. 150436401Ssklower */ 150536401Ssklower int 150636401Ssklower tp_headersize(dutype, tpcb) 150736401Ssklower int dutype; 150836401Ssklower struct tp_pcb *tpcb; 150936401Ssklower { 151036401Ssklower register int size = 0; 151136401Ssklower 151236401Ssklower IFTRACE(D_CONN) 151336401Ssklower tptrace(TPPTmisc, "tp_headersize dutype class xtd_format", 151436401Ssklower dutype, tpcb->tp_class, tpcb->tp_xtd_format, 0); 151536401Ssklower ENDTRACE 151636401Ssklower if( !( (tpcb->tp_class == TP_CLASS_0) || 151736401Ssklower (tpcb->tp_class == TP_CLASS_4) || 151836401Ssklower (dutype == DR_TPDU_type) || 151936401Ssklower (dutype == CR_TPDU_type) )) { 152036401Ssklower printf("tp_headersize:dutype 0x%x, class 0x%x", 152136401Ssklower dutype, tpcb->tp_class); 152236401Ssklower /* TODO: identify this and GET RID OF IT */ 152336401Ssklower } 152436401Ssklower ASSERT( (tpcb->tp_class == TP_CLASS_0) || 152536401Ssklower (tpcb->tp_class == TP_CLASS_4) || 152636401Ssklower (dutype == DR_TPDU_type) || 152736401Ssklower (dutype == CR_TPDU_type) ); 152836401Ssklower 152936401Ssklower if( tpcb->tp_class == TP_CLASS_0 ) { 153036401Ssklower size = tpdu_info[ dutype ] [TP_LEN_CLASS_0_INDEX]; 153136401Ssklower } else { 153236401Ssklower size = tpdu_info[ dutype ] [tpcb->tp_xtd_format]; 153336401Ssklower } 153436401Ssklower return size; 153536401Ssklower /* caller must get network level header size separately */ 153636401Ssklower } 1537