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*48749Ssklower * @(#)tp_input.c 7.16 (Berkeley) 04/26/91 * 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 "param.h" 6044422Ssklower #include "systm.h" 6136401Ssklower #include "mbuf.h" 6236401Ssklower #include "socket.h" 6336401Ssklower #include "socketvar.h" 6436401Ssklower #include "domain.h" 6536401Ssklower #include "protosw.h" 6636401Ssklower #include "errno.h" 6736401Ssklower #include "time.h" 6836401Ssklower #include "kernel.h" 6936401Ssklower #include "types.h" 7045900Ssklower #include "iso.h" 7137469Ssklower #include "iso_errno.h" 7245900Ssklower #include "iso_pcb.h" 7337469Ssklower #include "tp_param.h" 7437469Ssklower #include "tp_timer.h" 7537469Ssklower #include "tp_stat.h" 7637469Ssklower #include "tp_pcb.h" 7737469Ssklower #include "argo_debug.h" 7837469Ssklower #include "tp_trace.h" 7937469Ssklower #include "tp_tpdu.h" 8036401Ssklower 8145900Ssklower #include "../net/if.h" 8245900Ssklower #ifdef TRUE 8345900Ssklower #undef FALSE 8445900Ssklower #undef TRUE 8545900Ssklower #endif 8645900Ssklower #include "../netccitt/x25.h" 8745900Ssklower #include "../netccitt/pk.h" 8845900Ssklower #include "../netccitt/pk_var.h" 8945900Ssklower 9036401Ssklower int iso_check_csum(), tp_driver(), tp_headersize(), tp_error_emit(); 9136401Ssklower 9237469Ssklower /* 9337469Ssklower #ifdef lint 9437469Ssklower #undef ATTR 9537469Ssklower #define ATTR(X)ev_number 9637469Ssklower #endif lint 9737469Ssklower */ 9836401Ssklower 9936401Ssklower struct mbuf * 10036401Ssklower tp_inputprep(m) 10137469Ssklower register struct mbuf *m; 10236401Ssklower { 10337469Ssklower int hdrlen; 10436401Ssklower 10536401Ssklower IFDEBUG(D_TPINPUT) 10637469Ssklower printf("tp_inputprep: m 0x%x\n", m) ; 10736401Ssklower ENDDEBUG 10836401Ssklower 10936401Ssklower while( m->m_len < 1 ) { 11036401Ssklower if( (m = m_free(m)) == MNULL ) { 11136401Ssklower return (struct mbuf *)0; 11236401Ssklower } 11336401Ssklower } 11437469Ssklower if(((int)m->m_data) & 0x3) { 11537469Ssklower /* If we are not 4-byte aligned, we have to be 11637469Ssklower * above the beginning of the mbuf, and it is ok just 11737469Ssklower * to slide it back. 11837469Ssklower */ 11937469Ssklower caddr_t ocp = m->m_data; 12036401Ssklower 12137469Ssklower m->m_data = (caddr_t)(((int)m->m_data) & ~0x3); 12237469Ssklower ovbcopy(ocp, m->m_data, (unsigned)m->m_len); 12336401Ssklower } 12436401Ssklower CHANGE_MTYPE(m, TPMT_DATA); 12536401Ssklower 12637469Ssklower /* we KNOW that there is at least 1 byte in this mbuf 12737469Ssklower and that it is hdr->tpdu_li XXXXXXX! */ 12836401Ssklower 12937469Ssklower hdrlen = 1 + *mtod( m, u_char *); 13036401Ssklower 13136401Ssklower /* 13236401Ssklower * now pull up the whole tp header 13336401Ssklower */ 13437469Ssklower if ( m->m_len < hdrlen) { 13537469Ssklower if ((m = m_pullup(m, hdrlen)) == MNULL ) { 13636401Ssklower IncStat(ts_recv_drop); 13736401Ssklower return (struct mbuf *)0; 13836401Ssklower } 13936401Ssklower } 14036401Ssklower IFDEBUG(D_INPUT) 14136401Ssklower printf( 14236401Ssklower " at end: m 0x%x hdr->tpdu_li 0x%x m_len 0x%x\n",m, 14337469Ssklower hdrlen, m->m_len); 14436401Ssklower ENDDEBUG 14536401Ssklower return m; 14636401Ssklower } 14736401Ssklower 14836401Ssklower /* begin groan 14936401Ssklower * -- this array and the following macros allow you to step through the 15036401Ssklower * parameters of the variable part of a header 15136401Ssklower * note that if for any reason the values of the **_TPDU macros (in tp_events.h) 15236401Ssklower * should change, this array has to be rearranged 15336401Ssklower */ 15436401Ssklower 15536401Ssklower #define TP_LEN_CLASS_0_INDEX 2 15636401Ssklower #define TP_MAX_DATA_INDEX 3 15736401Ssklower 15836401Ssklower static u_char tpdu_info[][4] = 15936401Ssklower { 16036401Ssklower /* length max data len */ 16136401Ssklower /* reg fmt xtd fmt class 0 */ 16236401Ssklower /* UNUSED 0x0 */ 0x0 , 0x0, 0x0, 0x0, 16336401Ssklower /* XPD_TPDU_type 0x1 */ 0x5, 0x8, 0x0, TP_MAX_XPD_DATA, 16436401Ssklower /* XAK_TPDU_type 0x2 */ 0x5 , 0x8, 0x0, 0x0, 16536401Ssklower /* GR_TPDU_type 0x3 */ 0x0 , 0x0, 0x0, 0x0, 16636401Ssklower /* UNUSED 0x4 */ 0x0 , 0x0, 0x0, 0x0, 16736401Ssklower /* UNUSED 0x5 */ 0x0 , 0x0, 0x0, 0x0, 16836401Ssklower /* AK_TPDU_type 0x6 */ 0x5, 0xa, 0x0, 0x0, 16936401Ssklower /* ER_TPDU_type 0x7 */ 0x5, 0x5, 0x0, 0x0, 17036401Ssklower /* DR_TPDU_type 0x8 */ 0x7, 0x7, 0x7, TP_MAX_DR_DATA, 17136401Ssklower /* UNUSED 0x9 */ 0x0 , 0x0, 0x0, 0x0, 17236401Ssklower /* UNUSED 0xa */ 0x0 , 0x0, 0x0, 0x0, 17336401Ssklower /* UNUSED 0xb */ 0x0 , 0x0, 0x0, 0x0, 17436401Ssklower /* DC_TPDU_type 0xc */ 0x6, 0x6, 0x0, 0x0, 17536401Ssklower /* CC_TPDU_type 0xd */ 0x7, 0x7, 0x7, TP_MAX_CC_DATA, 17636401Ssklower /* CR_TPDU_type 0xe */ 0x7, 0x7, 0x7, TP_MAX_CR_DATA, 17736401Ssklower /* DT_TPDU_type 0xf */ 0x5, 0x8, 0x3, 0x0, 17836401Ssklower }; 17936401Ssklower 18042944Ssklower #define CHECK(Phrase, Erval, Stat, Whattodo, Loc)\ 18143334Ssklower if (Phrase) {error = (Erval); errlen = (int)(Loc); IncStat(Stat); tpibrk();\ 18242944Ssklower goto Whattodo; } 18342944Ssklower 18443334Ssklower tpibrk() {} 18543334Ssklower 18636401Ssklower /* 18736401Ssklower * WHENEVER YOU USE THE FOLLOWING MACRO, 18836401Ssklower * BE SURE THE TPDUTYPE IS A LEGIT VALUE FIRST! 18936401Ssklower */ 19036401Ssklower 19142944Ssklower #define WHILE_OPTIONS(P, hdr, format)\ 19242944Ssklower { register caddr_t P = tpdu_info[(hdr)->tpdu_type][(format)] + (caddr_t)hdr;\ 19342944Ssklower caddr_t PLIM = 1 + hdr->tpdu_li + (caddr_t)hdr;\ 19442944Ssklower for (;; P += 2 + ((struct tp_vbp *)P)->tpv_len) {\ 19542944Ssklower CHECK((P > PLIM), E_TP_LENGTH_INVAL, ts_inv_length,\ 19642944Ssklower respond, P - (caddr_t)hdr);\ 19742944Ssklower if (P == PLIM) break; 19836401Ssklower 19942944Ssklower #define END_WHILE_OPTIONS(P) } } 20036401Ssklower 20136401Ssklower /* end groan */ 20236401Ssklower 20336401Ssklower /* 20436401Ssklower * NAME: tp_newsocket() 20536401Ssklower * 20636401Ssklower * CALLED FROM: 20736401Ssklower * tp_input() on incoming CR, when a socket w/ the called suffix 20836401Ssklower * is awaiting a connection request 20936401Ssklower * 21036401Ssklower * FUNCTION and ARGUMENTS: 21136401Ssklower * Create a new socket structure, attach to it a new transport pcb, 21236401Ssklower * using a copy of the net level pcb for the parent socket. 21336401Ssklower * (so) is the parent socket. 21436401Ssklower * (fname) is the foreign address (all that's used is the nsap portion) 21536401Ssklower * 21636401Ssklower * RETURN VALUE: 21736401Ssklower * a new socket structure, being this end of the newly formed connection. 21836401Ssklower * 21936401Ssklower * SIDE EFFECTS: 22036401Ssklower * Sets a few things in the tpcb and net level pcb 22136401Ssklower * 22236401Ssklower * NOTES: 22336401Ssklower */ 22436401Ssklower static struct socket * 22536401Ssklower tp_newsocket(so, fname, cons_channel, class_to_use, netservice) 22636401Ssklower struct socket *so; 22736401Ssklower struct sockaddr *fname; 22836401Ssklower u_int cons_channel; 22936401Ssklower u_char class_to_use; 23036401Ssklower u_int netservice; 23136401Ssklower { 23236401Ssklower register struct tp_pcb *tpcb = sototpcb(so); /* old tpcb, needed below */ 23345900Ssklower register struct tp_pcb *newtpcb; 23436401Ssklower 23536401Ssklower /* 23636401Ssklower * sonewconn() gets a new socket structure, 23736401Ssklower * a new lower layer pcb and a new tpcb, 23836401Ssklower * but the pcbs are unnamed (not bound) 23936401Ssklower */ 24036401Ssklower IFTRACE(D_NEWSOCK) 24138841Ssklower tptraceTPCB(TPPTmisc, "newsock: listg_so, _tpcb, so_head", 24239196Ssklower so, tpcb, so->so_head, 0); 24336401Ssklower ENDTRACE 24436401Ssklower 24540636Skarels if ((so = sonewconn(so, SS_ISCONFIRMING)) == (struct socket *)0) 24636401Ssklower return so; 24736401Ssklower IFTRACE(D_NEWSOCK) 24838841Ssklower tptraceTPCB(TPPTmisc, "newsock: after newconn so, so_head", 24938841Ssklower so, so->so_head, 0, 0); 25036401Ssklower ENDTRACE 25136401Ssklower 25236401Ssklower IFDEBUG(D_NEWSOCK) 25337469Ssklower printf("tp_newsocket(channel 0x%x) after sonewconn so 0x%x \n", 25437469Ssklower cons_channel, so); 25537469Ssklower dump_addr(fname); 25636401Ssklower { 25736401Ssklower struct socket *t, *head ; 25836401Ssklower 25936401Ssklower head = so->so_head; 26036401Ssklower t = so; 26136401Ssklower printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n", 26236401Ssklower t, t->so_head, t->so_q0, t->so_q0len); 26336401Ssklower while( (t=t->so_q0) && t!= so && t!= head) 26436401Ssklower printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n", 26536401Ssklower t, t->so_head, t->so_q0, t->so_q0len); 26636401Ssklower } 26736401Ssklower ENDDEBUG 26836401Ssklower 26936401Ssklower /* 27036401Ssklower * before we clobber the old tpcb ptr, get these items from the parent pcb 27136401Ssklower */ 27236401Ssklower newtpcb = sototpcb(so); 27336401Ssklower newtpcb->_tp_param = tpcb->_tp_param; 27436401Ssklower newtpcb->tp_flags = tpcb->tp_flags; 27536401Ssklower newtpcb->tp_lcredit = tpcb->tp_lcredit; 27636401Ssklower newtpcb->tp_l_tpdusize = tpcb->tp_l_tpdusize; 27736401Ssklower newtpcb->tp_lsuffixlen = tpcb->tp_lsuffixlen; 27836401Ssklower bcopy( tpcb->tp_lsuffix, newtpcb->tp_lsuffix, newtpcb->tp_lsuffixlen); 27937469Ssklower soreserve(so, (u_long)tpcb->tp_winsize, (u_long)tpcb->tp_winsize); 28036401Ssklower 28137469Ssklower if( /* old */ tpcb->tp_ucddata) { 28236401Ssklower /* 28337469Ssklower * These data are the connect- , confirm- or disconnect- data. 28436401Ssklower */ 28536401Ssklower struct mbuf *conndata; 28636401Ssklower 28737469Ssklower conndata = m_copy(tpcb->tp_ucddata, 0, (int)M_COPYALL); 28836401Ssklower IFDEBUG(D_CONN) 28936401Ssklower dump_mbuf(conndata, "conndata after mcopy"); 29036401Ssklower ENDDEBUG 29137469Ssklower newtpcb->tp_ucddata = conndata; 29236401Ssklower } 29336401Ssklower 29436401Ssklower tpcb = newtpcb; 29536401Ssklower tpcb->tp_state = TP_LISTENING; 29636401Ssklower tpcb->tp_class = class_to_use; 29736401Ssklower tpcb->tp_netservice = netservice; 29836401Ssklower 29936401Ssklower 30036401Ssklower ASSERT( fname != 0 ) ; /* just checking */ 30136401Ssklower if ( fname ) { 30236401Ssklower /* 30336401Ssklower * tp_route_to takes its address argument in the form of an mbuf. 30436401Ssklower */ 30536401Ssklower struct mbuf *m; 30636401Ssklower int err; 30736401Ssklower 30836401Ssklower MGET(m, M_DONTWAIT, MT_SONAME); /* mbuf type used is confusing */ 30936401Ssklower if (m) { 31036401Ssklower /* 31136401Ssklower * this seems a bit grotesque, but tp_route_to expects 31236401Ssklower * an mbuf * instead of simply a sockaddr; it calls the ll 31336401Ssklower * pcb_connect, which expects the name/addr in an mbuf as well. 31436401Ssklower * sigh. 31536401Ssklower */ 31637469Ssklower bcopy((caddr_t)fname, mtod(m, caddr_t), fname->sa_len); 31737469Ssklower m->m_len = fname->sa_len; 31836401Ssklower 31936401Ssklower /* grot : have to say the kernel can override params in 32036401Ssklower * the passive open case 32136401Ssklower */ 32236401Ssklower tpcb->tp_dont_change_params = 0; 32336401Ssklower err = tp_route_to( m, tpcb, cons_channel); 32436401Ssklower m_free(m); 32536401Ssklower 32636401Ssklower if (!err) 32736401Ssklower goto ok; 32836401Ssklower } 32936401Ssklower IFDEBUG(D_CONN) 33036401Ssklower printf("tp_route_to FAILED! detaching tpcb 0x%x, so 0x%x\n", 33136401Ssklower tpcb, so); 33236401Ssklower ENDDEBUG 33336401Ssklower (void) tp_detach(tpcb); 33436401Ssklower return 0; 33536401Ssklower } 33636401Ssklower ok: 33736401Ssklower IFDEBUG(D_TPINPUT) 33836401Ssklower printf("tp_newsocket returning so 0x%x, sototpcb(so) 0x%x\n", 33936401Ssklower so, sototpcb(so)); 34036401Ssklower ENDDEBUG 34136401Ssklower return so; 34236401Ssklower } 34336401Ssklower 34445900Ssklower #ifndef TPCONS 34536401Ssklower tpcons_output() 34636401Ssklower { 34736401Ssklower return(0); 34836401Ssklower } 34936401Ssklower #endif !CONS 35036401Ssklower 35136401Ssklower /* 35236401Ssklower * NAME: tp_input() 35336401Ssklower * 35436401Ssklower * CALLED FROM: 35536401Ssklower * net layer input routine 35636401Ssklower * 35736401Ssklower * FUNCTION and ARGUMENTS: 35836401Ssklower * Process an incoming TPDU (m), finding the associated tpcb if there 35936401Ssklower * is one. Create the appropriate type of event and call the driver. 36036401Ssklower * (faddr) and (laddr) are the foreign and local addresses. 36136401Ssklower * 36236401Ssklower * When tp_input() is called we KNOW that the ENTIRE TP HEADER 36336401Ssklower * has been m_pullup-ed. 36436401Ssklower * 36536401Ssklower * RETURN VALUE: Nada 36636401Ssklower * 36736401Ssklower * SIDE EFFECTS: 36836401Ssklower * When using COSNS it may affect the state of the net-level pcb 36936401Ssklower * 37036401Ssklower * NOTE: 37136401Ssklower * The initial value of acktime is 2 so that we will never 37236401Ssklower * have a 0 value for tp_peer_acktime. It gets used in the 37336401Ssklower * computation of the retransmission timer value, and so it 37436401Ssklower * mustn't be zero. 37536401Ssklower * 2 seems like a reasonable minimum. 37636401Ssklower */ 37736401Ssklower ProtoHook 37839929Ssklower tp_input(m, faddr, laddr, cons_channel, dgout_routine, ce_bit) 37936401Ssklower register struct mbuf *m; 38036401Ssklower struct sockaddr *faddr, *laddr; /* NSAP addresses */ 38136401Ssklower u_int cons_channel; 38236401Ssklower int (*dgout_routine)(); 38339929Ssklower int ce_bit; 38436401Ssklower 38536401Ssklower { 38636401Ssklower register struct tp_pcb *tpcb = (struct tp_pcb *)0; 38744947Ssklower register struct tpdu *hdr; 38836401Ssklower struct socket *so; 38936401Ssklower struct tp_event e; 39042944Ssklower int error = 0; 39136401Ssklower unsigned dutype; 39242944Ssklower u_short dref, sref = 0, acktime = 2, subseq = 0; /*VAX*/ 39342944Ssklower u_char preferred_class = 0, class_to_use = 0; 39442944Ssklower u_char opt, dusize = TP_DFL_TPDUSIZE, addlopt = 0, version; 39536401Ssklower #ifdef TP_PERF_MEAS 39638841Ssklower u_char perf_meas; 39736401Ssklower #endif TP_PERF_MEAS 39844422Ssklower u_char fsufxlen = 0, lsufxlen = 0, intercepted = 0; 39942944Ssklower caddr_t fsufxloc = 0, lsufxloc = 0; 40042944Ssklower int tpdu_len = 0; 40142944Ssklower u_int takes_data = FALSE; 40242944Ssklower u_int fcc_present = FALSE; 40342944Ssklower int errlen = 0; 40436401Ssklower struct tp_conn_param tpp; 40536401Ssklower int tpcons_output(); 40636401Ssklower 40738841Ssklower again: 40844947Ssklower hdr = mtod(m, struct tpdu *); 40936401Ssklower #ifdef TP_PERF_MEAS 41038841Ssklower GET_CUR_TIME( &e.e_time ); perf_meas = 0; 41136401Ssklower #endif TP_PERF_MEAS 41236401Ssklower 41336401Ssklower IFDEBUG(D_TPINPUT) 41436401Ssklower printf("tp_input(0x%x, ... 0x%x)\n", m, cons_channel); 41536401Ssklower ENDDEBUG 41636401Ssklower 41736401Ssklower 41836401Ssklower /* 41936401Ssklower * get the actual tpdu length - necessary for monitoring 42036401Ssklower * and for checksumming 42136401Ssklower * 42236401Ssklower * Also, maybe measure the mbuf chain lengths and sizes. 42336401Ssklower */ 42436401Ssklower 42536401Ssklower { register struct mbuf *n=m; 42636401Ssklower # ifdef ARGO_DEBUG 42736401Ssklower int chain_length = 0; 42836401Ssklower # endif ARGO_DEBUG 42936401Ssklower 43036401Ssklower for(;;) { 43136401Ssklower tpdu_len += n->m_len; 43236401Ssklower IFDEBUG(D_MBUF_MEAS) 43337469Ssklower if( n->m_flags & M_EXT) { 43436401Ssklower IncStat(ts_mb_cluster); 43536401Ssklower } else { 43636401Ssklower IncStat(ts_mb_small); 43736401Ssklower } 43836401Ssklower chain_length ++; 43936401Ssklower ENDDEBUG 44036401Ssklower if (n->m_next == MNULL ) { 44136401Ssklower break; 44236401Ssklower } 44336401Ssklower n = n->m_next; 44436401Ssklower } 44536401Ssklower IFDEBUG(D_MBUF_MEAS) 44636401Ssklower if(chain_length > 16) 44736401Ssklower chain_length = 0; /* zero used for anything > 16 */ 44836401Ssklower tp_stat.ts_mb_len_distr[chain_length] ++; 44936401Ssklower ENDDEBUG 45036401Ssklower } 45136401Ssklower IFTRACE(D_TPINPUT) 45236401Ssklower tptraceTPCB(TPPTtpduin, hdr->tpdu_type, hdr, hdr->tpdu_li+1, tpdu_len, 45336401Ssklower 0); 45436401Ssklower ENDTRACE 45536401Ssklower 45636401Ssklower dref = ntohs((short)hdr->tpdu_dref); 45736401Ssklower sref = ntohs((short)hdr->tpdu_sref); 45836401Ssklower dutype = (int)hdr->tpdu_type; 45936401Ssklower 46036401Ssklower IFDEBUG(D_TPINPUT) 46136401Ssklower printf("input: dutype 0x%x cons_channel 0x%x dref 0x%x\n", dutype, 46236401Ssklower cons_channel, dref); 46336401Ssklower printf("input: dref 0x%x sref 0x%x\n", dref, sref); 46436401Ssklower ENDDEBUG 46536401Ssklower IFTRACE(D_TPINPUT) 46636401Ssklower tptrace(TPPTmisc, "channel dutype dref ", 46736401Ssklower cons_channel, dutype, dref, 0); 46836401Ssklower ENDTRACE 46936401Ssklower 47036401Ssklower 47136401Ssklower #ifdef ARGO_DEBUG 47236401Ssklower if( (dutype < TP_MIN_TPDUTYPE) || (dutype > TP_MAX_TPDUTYPE)) { 47336401Ssklower printf("BAD dutype! 0x%x, channel 0x%x dref 0x%x\n", 47436401Ssklower dutype, cons_channel, dref); 47536401Ssklower dump_buf (m, sizeof( struct mbuf )); 47636401Ssklower 47736401Ssklower IncStat(ts_inv_dutype); 47836401Ssklower goto discard; 47936401Ssklower } 48036401Ssklower #endif ARGO_DEBUG 48136401Ssklower 48236401Ssklower CHECK( (dutype < TP_MIN_TPDUTYPE || dutype > TP_MAX_TPDUTYPE), 48336401Ssklower E_TP_INV_TPDU, ts_inv_dutype, respond, 48436401Ssklower 2 ); 48536401Ssklower /* unfortunately we can't take the address of the tpdu_type field, 48636401Ssklower * since it's a bit field - so we just use the constant offset 2 48736401Ssklower */ 48836401Ssklower 48936401Ssklower /* Now this isn't very neat but since you locate a pcb one way 49036401Ssklower * at the beginning of connection establishment, and by 49136401Ssklower * the dref for each tpdu after that, we have to treat CRs differently 49236401Ssklower */ 49336401Ssklower if ( dutype == CR_TPDU_type ) { 49436401Ssklower u_char alt_classes = 0; 49536401Ssklower 49637469Ssklower preferred_class = 1 << hdr->tpdu_CRclass; 49736401Ssklower opt = hdr->tpdu_CRoptions; 49836401Ssklower 49936401Ssklower WHILE_OPTIONS(P, hdr, 1 ) /* { */ 50036401Ssklower 50136401Ssklower switch( vbptr(P)->tpv_code ) { 50236401Ssklower 50336401Ssklower case TPP_tpdu_size: 50436401Ssklower vb_getval(P, u_char, dusize); 50536401Ssklower IFDEBUG(D_TPINPUT) 50636401Ssklower printf("CR dusize 0x%x\n", dusize); 50736401Ssklower ENDDEBUG 50842944Ssklower /* COS tests: NBS IA (Dec. 1987) Sec. 4.5.2.1 */ 50942944Ssklower if (dusize < TP_MIN_TPDUSIZE || dusize > TP_MAX_TPDUSIZE) 51042944Ssklower dusize = TP_DFL_TPDUSIZE; 51136401Ssklower break; 51236401Ssklower case TPP_addl_opt: 51336401Ssklower vb_getval(P, u_char, addlopt); 51436401Ssklower break; 51536401Ssklower case TPP_calling_sufx: 51636401Ssklower /* could use vb_getval, but we want to save the loc & len 51736401Ssklower * for later use 51836401Ssklower */ 51936401Ssklower fsufxloc = (caddr_t) &vbptr(P)->tpv_val; 52036401Ssklower fsufxlen = vbptr(P)->tpv_len; 52136401Ssklower IFDEBUG(D_TPINPUT) 52236401Ssklower printf("CR fsufx:"); 52336401Ssklower { register int j; 52436401Ssklower for(j=0; j<fsufxlen; j++ ) { 52536401Ssklower printf(" 0x%x. ", *((caddr_t)(fsufxloc+j)) ); 52636401Ssklower } 52736401Ssklower printf("\n"); 52836401Ssklower } 52936401Ssklower ENDDEBUG 53036401Ssklower break; 53136401Ssklower case TPP_called_sufx: 53236401Ssklower /* could use vb_getval, but we want to save the loc & len 53336401Ssklower * for later use 53436401Ssklower */ 53536401Ssklower lsufxloc = (caddr_t) &vbptr(P)->tpv_val; 53636401Ssklower lsufxlen = vbptr(P)->tpv_len; 53736401Ssklower IFDEBUG(D_TPINPUT) 53836401Ssklower printf("CR lsufx:"); 53936401Ssklower { register int j; 54036401Ssklower for(j=0; j<lsufxlen; j++ ) { 54137469Ssklower printf(" 0x%x. ", *((u_char *)(lsufxloc+j)) ); 54236401Ssklower } 54336401Ssklower printf("\n"); 54436401Ssklower } 54536401Ssklower ENDDEBUG 54636401Ssklower break; 54736401Ssklower 54836401Ssklower #ifdef TP_PERF_MEAS 54936401Ssklower case TPP_perf_meas: 55036401Ssklower vb_getval(P, u_char, perf_meas); 55136401Ssklower break; 55236401Ssklower #endif TP_PERF_MEAS 55336401Ssklower 55436401Ssklower case TPP_vers: 55536401Ssklower /* not in class 0; 1 octet; in CR_TPDU only */ 55642944Ssklower /* COS tests says if version wrong, use default version!?XXX */ 55736401Ssklower CHECK( (vbval(P, u_char) != TP_VERSION ), 55842491Ssklower E_TP_INV_PVAL, ts_inv_pval, setversion, 55942944Ssklower (1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) ); 56042491Ssklower setversion: 56142491Ssklower version = vbval(P, u_char); 56236401Ssklower break; 56336401Ssklower case TPP_acktime: 56436401Ssklower vb_getval(P, u_short, acktime); 56536401Ssklower acktime = ntohs(acktime); 56636401Ssklower acktime = acktime/500; /* convert to slowtimo ticks */ 56736401Ssklower if((short)acktime <=0 ) 56836401Ssklower acktime = 2; /* don't allow a bad peer to screw us up */ 56936401Ssklower IFDEBUG(D_TPINPUT) 57036401Ssklower printf("CR acktime 0x%x\n", acktime); 57136401Ssklower ENDDEBUG 57236401Ssklower break; 57336401Ssklower 57436401Ssklower case TPP_alt_class: 57536401Ssklower { 57636401Ssklower u_char *aclass = 0; 57736401Ssklower register int i; 57842944Ssklower static u_char bad_alt_classes[5] = 57942944Ssklower { ~0, ~3, ~5, ~0xf, ~0x1f}; 58036401Ssklower 58142944Ssklower aclass = 58242944Ssklower (u_char *) &(((struct tp_vbp *)P)->tpv_val); 58336401Ssklower for (i = ((struct tp_vbp *)P)->tpv_len; i>0; i--) { 58442944Ssklower alt_classes |= (1<<((*aclass++)>>4)); 58536401Ssklower } 58642944Ssklower CHECK( (bad_alt_classes[hdr->tpdu_CRclass] & alt_classes), 58742944Ssklower E_TP_INV_PVAL, ts_inv_aclass, respond, 58842944Ssklower ((caddr_t)aclass) - (caddr_t)hdr); 58936401Ssklower IFDEBUG(D_TPINPUT) 59036401Ssklower printf("alt_classes 0x%x\n", alt_classes); 59136401Ssklower ENDDEBUG 59236401Ssklower } 59336401Ssklower break; 59436401Ssklower 59536401Ssklower case TPP_security: 59636401Ssklower case TPP_residER: 59736401Ssklower case TPP_priority: 59836401Ssklower case TPP_transdelay: 59936401Ssklower case TPP_throughput: 60036401Ssklower case TPP_addl_info: 60136401Ssklower case TPP_subseq: 60244947Ssklower default: 60336401Ssklower IFDEBUG(D_TPINPUT) 60436401Ssklower printf("param ignored CR_TPDU code= 0x%x\n", 60536401Ssklower vbptr(P)->tpv_code); 60636401Ssklower ENDDEBUG 60736401Ssklower IncStat(ts_param_ignored); 60836401Ssklower break; 60936401Ssklower 61036401Ssklower case TPP_checksum: 61136401Ssklower IFDEBUG(D_TPINPUT) 61236401Ssklower printf("CR before cksum\n"); 61336401Ssklower ENDDEBUG 61436401Ssklower 61536401Ssklower CHECK( iso_check_csum(m, tpdu_len), 61636401Ssklower E_TP_INV_PVAL, ts_bad_csum, discard, 0) 61736401Ssklower 61836401Ssklower IFDEBUG(D_TPINPUT) 61936401Ssklower printf("CR before cksum\n"); 62036401Ssklower ENDDEBUG 62136401Ssklower break; 62236401Ssklower } 62336401Ssklower 62436401Ssklower /* } */ END_WHILE_OPTIONS(P) 62536401Ssklower 62644422Ssklower if (lsufxlen == 0) { 62736401Ssklower /* can't look for a tpcb w/o any called sufx */ 62836401Ssklower error = E_TP_LENGTH_INVAL; 62936401Ssklower IncStat(ts_inv_sufx); 63036401Ssklower goto respond; 63136401Ssklower } else { 63244422Ssklower register struct tp_pcb *t; 63336401Ssklower 63444601Ssklower for (t = tp_intercepts; t ; t = t->tp_nextlisten) { 63544422Ssklower if (laddr->sa_family != t->tp_nlproto->nlp_afamily) 63636401Ssklower continue; 63744601Ssklower if ((*t->tp_nlproto->nlp_cmpnetaddr)( 63844422Ssklower t->tp_npcb, laddr, TP_LOCAL)) { 63944422Ssklower intercepted = 1; 64044422Ssklower goto check_duplicate_cr; 64136401Ssklower } 64236401Ssklower } 64344601Ssklower for (t = tp_listeners; t ; t = t->tp_nextlisten) 64444601Ssklower if (bcmp(lsufxloc, t->tp_lsuffix, lsufxlen) == 0 && 64544601Ssklower laddr->sa_family == t->tp_nlproto->nlp_afamily) 64644601Ssklower break; 64744422Ssklower CHECK(t == 0, E_TP_NO_SESSION, ts_inv_sufx, respond, 64836401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 64936401Ssklower /* _tpduf is the fixed part; add 2 to get the dref bits of 65036401Ssklower * the fixed part (can't take the address of a bit field) 65136401Ssklower */ 65244601Ssklower IFDEBUG(D_TPINPUT) 65344601Ssklower printf("checking if dup CR\n"); 65444601Ssklower ENDDEBUG 65544422Ssklower check_duplicate_cr: 65644422Ssklower tpcb = t; 65744422Ssklower for (t = tpcb->tp_next; t != tpcb; t = t->tp_next) { 65844422Ssklower if (sref != t->tp_fref) 65944422Ssklower continue; 66044422Ssklower if ((*tpcb->tp_nlproto->nlp_cmpnetaddr)( 66144422Ssklower t->tp_npcb, faddr, TP_FOREIGN)) { 66244422Ssklower IFDEBUG(D_TPINPUT) 66344422Ssklower printf("duplicate CR discarded\n"); 66444422Ssklower ENDDEBUG 66544422Ssklower goto discard; 66644422Ssklower } 66744422Ssklower } 66844422Ssklower IFTRACE(D_TPINPUT) 66944422Ssklower tptrace(TPPTmisc, "tp_input: tpcb *lsufxloc tpstate", 67044422Ssklower tpcb, *lsufxloc, tpcb->tp_state, 0); 67144422Ssklower ENDTRACE 67236401Ssklower } 67336401Ssklower 67436401Ssklower /* 67536401Ssklower * WE HAVE A TPCB 67636401Ssklower * already know that the classes in the CR match at least 67736401Ssklower * one class implemented, but we don't know yet if they 67836401Ssklower * include any classes permitted by this server. 67936401Ssklower */ 68036401Ssklower 68136401Ssklower IFDEBUG(D_TPINPUT) 68236401Ssklower printf("HAVE A TPCB 1: 0x%x\n", tpcb); 68336401Ssklower ENDDEBUG 68436401Ssklower IFDEBUG(D_CONN) 68536401Ssklower printf( 68636401Ssklower "CR: bef CHKS: flags 0x%x class_to_use 0x%x alt 0x%x opt 0x%x tp_class 0x%x\n", 68736401Ssklower tpcb->tp_flags, class_to_use, alt_classes, opt, tpcb->tp_class); 68836401Ssklower ENDDEBUG 68936401Ssklower /* tpcb->tp_class doesn't include any classes not implemented */ 69036401Ssklower class_to_use = (preferred_class & tpcb->tp_class); 69136401Ssklower if( (class_to_use = preferred_class & tpcb->tp_class) == 0 ) 69236401Ssklower class_to_use = alt_classes & tpcb->tp_class; 69336401Ssklower 69436401Ssklower class_to_use = 1 << tp_mask_to_num(class_to_use); 69536401Ssklower 69636401Ssklower { 69736401Ssklower tpp = tpcb->_tp_param; 69836401Ssklower tpp.p_class = class_to_use; 69936401Ssklower tpp.p_tpdusize = dusize; 70036401Ssklower tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT; 70136401Ssklower tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD; 70236401Ssklower tpp.p_use_checksum = (tpp.p_class == TP_CLASS_0)?0: 70336401Ssklower (addlopt & TPAO_NO_CSUM) == 0; 70442491Ssklower tpp.p_version = version; 70536401Ssklower #ifdef notdef 70636401Ssklower tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC; 70736401Ssklower tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD; 70836401Ssklower tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC; 70936401Ssklower #endif notdef 71036401Ssklower 71136401Ssklower CHECK( 71236401Ssklower tp_consistency(tpcb, 0 /* not force or strict */, &tpp) != 0, 71336401Ssklower E_TP_NEGOT_FAILED, ts_negotfailed, respond, 71436401Ssklower (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 71536401Ssklower /* ^ more or less the location of class */ 71636401Ssklower ) 71736401Ssklower } 71836401Ssklower IFTRACE(D_CONN) 71936401Ssklower tptrace(TPPTmisc, 72036401Ssklower "after 1 consist class_to_use class, out, tpconsout", 72136401Ssklower class_to_use, 72236401Ssklower tpcb->tp_class, dgout_routine, tpcons_output 72336401Ssklower ); 72436401Ssklower ENDTRACE 72536401Ssklower CHECK( 72636401Ssklower ((class_to_use == TP_CLASS_0)&&(dgout_routine != tpcons_output)), 72736401Ssklower E_TP_NEGOT_FAILED, ts_negotfailed, respond, 72836401Ssklower (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 72936401Ssklower /* ^ more or less the location of class */ 73036401Ssklower ) 73136401Ssklower IFDEBUG(D_CONN) 73236401Ssklower printf("CR: after CRCCCHECKS: tpcb 0x%x, flags 0x%x\n", 73336401Ssklower tpcb, tpcb->tp_flags); 73436401Ssklower ENDDEBUG 73536401Ssklower takes_data = TRUE; 73636401Ssklower e.ATTR(CR_TPDU).e_cdt = hdr->tpdu_CRcdt; 73736401Ssklower e.ev_number = CR_TPDU; 73836401Ssklower 73936401Ssklower so = tpcb->tp_sock; 74036401Ssklower if (so->so_options & SO_ACCEPTCONN) { 74144422Ssklower struct tp_pcb *parent_tpcb = tpcb; 74236401Ssklower /* 74336401Ssklower * Create a socket, tpcb, ll pcb, etc. 74436401Ssklower * for this newborn connection, and fill in all the values. 74536401Ssklower */ 74636401Ssklower IFDEBUG(D_CONN) 74736401Ssklower printf("abt to call tp_newsocket(0x%x, 0x%x, 0x%x, 0x%x)\n", 74836401Ssklower so, laddr, faddr, cons_channel); 74936401Ssklower ENDDEBUG 75036401Ssklower if( (so = 75136401Ssklower tp_newsocket(so, faddr, cons_channel, 75236401Ssklower class_to_use, 75337469Ssklower ((tpcb->tp_netservice == IN_CLNS) ? IN_CLNS : 75437469Ssklower (dgout_routine == tpcons_output)?ISO_CONS:ISO_CLNS)) 75536401Ssklower ) == (struct socket *)0 ) { 75636401Ssklower /* note - even if netservice is IN_CLNS, as far as 75736401Ssklower * the tp entity is concerned, the only differences 75837469Ssklower * are CO vs CL 75936401Ssklower */ 76036401Ssklower IFDEBUG(D_CONN) 76136401Ssklower printf("tp_newsocket returns 0\n"); 76236401Ssklower ENDDEBUG 76336401Ssklower goto discard; 76436401Ssklower } 76536401Ssklower tpcb = sototpcb(so); 76644601Ssklower insque(tpcb, parent_tpcb); 76736401Ssklower 76836401Ssklower /* 76937469Ssklower * Stash the addresses in the net level pcb 77036401Ssklower * kind of like a pcbconnect() but don't need 77136401Ssklower * or want all those checks. 77236401Ssklower */ 77336401Ssklower (tpcb->tp_nlproto->nlp_putnetaddr)(so->so_pcb, faddr, TP_FOREIGN); 77436401Ssklower (tpcb->tp_nlproto->nlp_putnetaddr)(so->so_pcb, laddr, TP_LOCAL); 77536401Ssklower 77637469Ssklower /* stash the f suffix in the new tpcb */ 77738841Ssklower bcopy(fsufxloc, tpcb->tp_fsuffix, fsufxlen); 77844422Ssklower /* l suffix is already there, unless this is an intercept case */ 77944422Ssklower if (intercepted) 78044422Ssklower bcopy(lsufxloc, tpcb->tp_lsuffix, lsufxlen); 78137469Ssklower (tpcb->tp_nlproto->nlp_putsufx) 78237469Ssklower (so->so_pcb, fsufxloc, fsufxlen, TP_FOREIGN); 78338841Ssklower (tpcb->tp_nlproto->nlp_putsufx) 78438841Ssklower (so->so_pcb, lsufxloc, lsufxlen, TP_LOCAL); 78536401Ssklower #ifdef TP_PERF_MEAS 78636401Ssklower if( tpcb->tp_perf_on = perf_meas ) { /* assignment */ 78736401Ssklower /* ok, let's create an mbuf for stashing the 78836401Ssklower * statistics if one doesn't already exist 78936401Ssklower */ 79036401Ssklower (void) tp_setup_perf(tpcb); 79136401Ssklower } 79236401Ssklower #endif TP_PERF_MEAS 79336401Ssklower tpcb->tp_fref = sref; 79436401Ssklower 79536401Ssklower /* We've already checked for consistency with the options 79636401Ssklower * set in tpp, but we couldn't set them earlier because 79736401Ssklower * we didn't want to change options in the LISTENING tpcb. 79836401Ssklower * Now we set the options in the new socket's tpcb. 79936401Ssklower */ 80036401Ssklower (void) tp_consistency( tpcb, TP_FORCE, &tpp); 80136401Ssklower 80236401Ssklower if(!tpcb->tp_use_checksum) 80336401Ssklower IncStat(ts_csum_off); 80436401Ssklower if(tpcb->tp_xpd_service) 80536401Ssklower IncStat(ts_use_txpd); 80636401Ssklower if(tpcb->tp_xtd_format) 80736401Ssklower IncStat(ts_xtd_fmt); 80836401Ssklower 80936401Ssklower /* 81036401Ssklower * Get the maximum transmission unit from the lower layer(s) 81136401Ssklower * so we can negotiate a reasonable max TPDU size. 81236401Ssklower */ 81336401Ssklower (tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb, 81436401Ssklower &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0); 81536401Ssklower tpcb->tp_peer_acktime = acktime; 81636401Ssklower 81736401Ssklower /* 81836401Ssklower * The following kludge is used to test retransmissions and 81936401Ssklower * timeout during connection establishment. 82036401Ssklower */ 82136401Ssklower IFDEBUG(D_ZDREF) 82236401Ssklower IncStat(ts_zdebug); 82337469Ssklower /*tpcb->tp_fref = 0;*/ 82436401Ssklower ENDDEBUG 82536401Ssklower } 82636401Ssklower IncStat(ts_CR_rcvd); 82739929Ssklower if (!tpcb->tp_cebit_off) { 82839929Ssklower tpcb->tp_win_recv = tp_start_win << 8; 82939929Ssklower tpcb->tp_cong_sample.cs_size = 0; 83039929Ssklower LOCAL_CREDIT(tpcb); 83139929Ssklower CONG_INIT_SAMPLE(tpcb); 83239929Ssklower CONG_UPDATE_SAMPLE(tpcb, ce_bit); 83339929Ssklower } 83439929Ssklower tpcb->tp_ackrcvd = 0; 83536401Ssklower } else if ( dutype == ER_TPDU_type ) { 83636401Ssklower /* 83736401Ssklower * ER TPDUs have to be recognized separately 83836401Ssklower * because they don't necessarily have a tpcb 83936401Ssklower * with them and we don't want err out looking for such 84036401Ssklower * a beast. 84136401Ssklower * We could put a bunch of little kludges in the 84236401Ssklower * next section of code so it would avoid references to tpcb 84336401Ssklower * if dutype == ER_TPDU_type but we don't want code for ERs to 84436401Ssklower * mess up code for data transfer. 84536401Ssklower */ 84636401Ssklower IncStat(ts_ER_rcvd); 84736401Ssklower e.ev_number = ER_TPDU; 84836401Ssklower e.ATTR(ER_TPDU).e_reason = (u_char)hdr->tpdu_ERreason; 849*48749Ssklower takes_data = FALSE; 85036401Ssklower } else { 85136401Ssklower /* tpdu type is CC, XPD, XAK, GR, AK, DR, DC, or DT */ 85236401Ssklower 85336401Ssklower /* In the next 4 checks, 85436401Ssklower * _tpduf is the fixed part; add 2 to get the dref bits of 85536401Ssklower * the fixed part (can't take the address of a bit field) 85636401Ssklower */ 85745900Ssklower #ifdef old_history 85836401Ssklower if(cons_channel) { 85945900Ssklower #ifdef NARGOXTWENTYFIVE 86036401Ssklower extern struct tp_pcb *cons_chan_to_tpcb(); 86136401Ssklower 86236401Ssklower tpcb = cons_chan_to_tpcb( cons_channel ); 86336401Ssklower /* Problem: We may have a legit 86436401Ssklower * error situation yet we may or may not have 86536401Ssklower * a correspondence between the tpcb and the vc, 86636401Ssklower * e.g., TP4cr--> <no dice, respond w/ DR on vc> 86736401Ssklower * <--- DR 86836401Ssklower * Now it's up to TP to look at the tpdu and do one of: 86936401Ssklower * confirm(dgm)(cr), confirm(circuit)(cr), reject(cr), or 87036401Ssklower * nothing, if the circuit is already open (any other tpdu). 87136401Ssklower * Sigh. 87236401Ssklower */ 87336401Ssklower 87436401Ssklower /* I don't know about this error value */ 87536401Ssklower CHECK( (tpcb == (struct tp_pcb *)0) , 87636401Ssklower E_TP_NO_CR_ON_NC, ts_inv_dref, respond, 87736401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 87836401Ssklower #else 87936401Ssklower printf("tp_input(): X25 NOT CONFIGURED!!\n"); 88045900Ssklower #endif 88145900Ssklower } else 88245900Ssklower /* we've now made the error reporting thing check for 88345900Ssklower multiple channels and not close out if more than 88445900Ssklower one in use */ 88545900Ssklower #endif old_history 88645900Ssklower { 88736401Ssklower 88836401Ssklower CHECK( ((int)dref <= 0 || dref >= N_TPREF) , 88942944Ssklower E_TP_MISM_REFS,ts_inv_dref, nonx_dref, 89036401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 89136401Ssklower CHECK( ((tpcb = tp_ref[dref].tpr_pcb ) == (struct tp_pcb *) 0 ), 89242944Ssklower E_TP_MISM_REFS,ts_inv_dref, nonx_dref, 89336401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 89436401Ssklower CHECK( (tpcb->tp_refp->tpr_state == REF_FREE), 89542944Ssklower E_TP_MISM_REFS,ts_inv_dref, nonx_dref, 89636401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 89736401Ssklower } 89836401Ssklower 89936401Ssklower IFDEBUG(D_TPINPUT) 90036401Ssklower printf("HAVE A TPCB 2: 0x%x\n", tpcb); 90136401Ssklower ENDDEBUG 90236401Ssklower 90336401Ssklower /* causes a DR to be sent for CC; ER for all else */ 90436401Ssklower CHECK( (tpcb->tp_refp->tpr_state == REF_FROZEN), 90536401Ssklower (dutype == CC_TPDU_type?E_TP_NO_SESSION:E_TP_MISM_REFS), 90636401Ssklower ts_inv_dref, respond, 90736401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 90836401Ssklower 90936401Ssklower IFDEBUG(D_TPINPUT) 91036401Ssklower printf("state of dref %d ok, tpcb 0x%x\n", dref,tpcb); 91136401Ssklower ENDDEBUG 91236401Ssklower /* 91336401Ssklower * At this point the state of the dref could be 91436401Ssklower * FROZEN: tpr_pcb == NULL, has ( reference only) timers 91536401Ssklower * for example, DC may arrive after the close() has detached 91636401Ssklower * the tpcb (e.g., if user turned off SO_LISTEN option) 91736401Ssklower * OPENING : a tpcb exists but no timers yet 91836401Ssklower * OPEN : tpcb exists & timers are outstanding 91936401Ssklower */ 92036401Ssklower 92139929Ssklower if (!tpcb->tp_cebit_off) 92239929Ssklower CONG_UPDATE_SAMPLE(tpcb, ce_bit); 92339929Ssklower 92436401Ssklower dusize = tpcb->tp_tpdusize; 92536401Ssklower 92636401Ssklower dutype = hdr->tpdu_type << 8; /* for the switch below */ 92736401Ssklower 92836401Ssklower WHILE_OPTIONS(P, hdr, tpcb->tp_xtd_format) /* { */ 92936401Ssklower 93037469Ssklower #define caseof(x,y) case (((x)<<8)+(y)) 93136401Ssklower switch( dutype | vbptr(P)->tpv_code ) { 93236401Ssklower 93336401Ssklower caseof( CC_TPDU_type, TPP_addl_opt ): 93436401Ssklower /* not in class 0; 1 octet */ 93536401Ssklower vb_getval(P, u_char, addlopt); 93636401Ssklower break; 93736401Ssklower caseof( CC_TPDU_type, TPP_tpdu_size ): 93842944Ssklower { 93942944Ssklower u_char odusize = dusize; 94036401Ssklower vb_getval(P, u_char, dusize); 94142944Ssklower CHECK( (dusize < TP_MIN_TPDUSIZE || 94242944Ssklower dusize > TP_MAX_TPDUSIZE || dusize > odusize), 94342944Ssklower E_TP_INV_PVAL, ts_inv_pval, respond, 94442944Ssklower (1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) ) 94536401Ssklower IFDEBUG(D_TPINPUT) 94636401Ssklower printf("CC dusize 0x%x\n", dusize); 94736401Ssklower ENDDEBUG 94842944Ssklower } 94936401Ssklower break; 95036401Ssklower caseof( CC_TPDU_type, TPP_calling_sufx): 95136401Ssklower IFDEBUG(D_TPINPUT) 95236401Ssklower printf("CC calling (local) sufxlen 0x%x\n", lsufxlen); 95336401Ssklower ENDDEBUG 95436401Ssklower lsufxloc = (caddr_t) &vbptr(P)->tpv_val; 95536401Ssklower lsufxlen = vbptr(P)->tpv_len; 95636401Ssklower break; 95736401Ssklower caseof( CC_TPDU_type, TPP_acktime ): 95836401Ssklower /* class 4 only, 2 octets */ 95936401Ssklower vb_getval(P, u_short, acktime); 96044947Ssklower acktime = ntohs(acktime); 96136401Ssklower acktime = acktime/500; /* convert to slowtimo ticks */ 96236401Ssklower if( (short)acktime <=0 ) 96336401Ssklower acktime = 2; 96436401Ssklower break; 96536401Ssklower caseof( CC_TPDU_type, TPP_called_sufx): 96636401Ssklower fsufxloc = (caddr_t) &vbptr(P)->tpv_val; 96736401Ssklower fsufxlen = vbptr(P)->tpv_len; 96836401Ssklower IFDEBUG(D_TPINPUT) 96936401Ssklower printf("CC called (foreign) sufx len %d\n", fsufxlen); 97036401Ssklower ENDDEBUG 97136401Ssklower break; 97236401Ssklower 97336401Ssklower caseof( CC_TPDU_type, TPP_checksum): 97436401Ssklower caseof( DR_TPDU_type, TPP_checksum): 97536401Ssklower caseof( DT_TPDU_type, TPP_checksum): 97636401Ssklower caseof( XPD_TPDU_type, TPP_checksum): 97736401Ssklower if( tpcb->tp_use_checksum ) { 97836401Ssklower CHECK( iso_check_csum(m, tpdu_len), 97936401Ssklower E_TP_INV_PVAL, ts_bad_csum, discard, 0) 98036401Ssklower } 98136401Ssklower break; 98236401Ssklower 98336401Ssklower /* this is different from the above because in the context 98436401Ssklower * of concat/ sep tpdu_len might not be the same as hdr len 98536401Ssklower */ 98636401Ssklower caseof( AK_TPDU_type, TPP_checksum): 98736401Ssklower caseof( XAK_TPDU_type, TPP_checksum): 98836401Ssklower caseof( DC_TPDU_type, TPP_checksum): 98936401Ssklower if( tpcb->tp_use_checksum ) { 99037469Ssklower CHECK( iso_check_csum(m, (int)hdr->tpdu_li + 1), 99136401Ssklower E_TP_INV_PVAL, ts_bad_csum, discard, 0) 99236401Ssklower } 99336401Ssklower break; 99436401Ssklower #ifdef notdef 99536401Ssklower caseof( DR_TPDU_type, TPP_addl_info ): 99636401Ssklower /* ignore - its length and meaning are 99736401Ssklower * user defined and there's no way 99836401Ssklower * to pass this info to the user anyway 99936401Ssklower */ 100036401Ssklower break; 100136401Ssklower #endif notdef 100236401Ssklower 100336401Ssklower caseof( AK_TPDU_type, TPP_subseq ): 100436401Ssklower /* used after reduction of window */ 100536401Ssklower vb_getval(P, u_short, subseq); 100636401Ssklower subseq = ntohs(subseq); 100736401Ssklower IFDEBUG(D_ACKRECV) 100836401Ssklower printf("AK Subsequence # 0x%x\n", subseq); 100936401Ssklower ENDDEBUG 101036401Ssklower break; 101136401Ssklower 101236401Ssklower caseof( AK_TPDU_type, TPP_flow_cntl_conf ): 101336401Ssklower { 101436401Ssklower u_int ylwe; 101536401Ssklower u_short ysubseq, ycredit; 101636401Ssklower 101736401Ssklower fcc_present = TRUE; 101836401Ssklower vb_getval(P, u_int, ylwe); 101936401Ssklower vb_getval(P, u_short, ysubseq); 102036401Ssklower vb_getval(P, u_short, ycredit); 102136401Ssklower ylwe = ntohl(ylwe); 102236401Ssklower ysubseq = ntohs(ysubseq); 102336401Ssklower ycredit = ntohs(ycredit); 102436401Ssklower IFDEBUG(D_ACKRECV) 102536401Ssklower printf("AK FCC lwe 0x%x, subseq 0x%x, cdt 0x%x\n", 102636401Ssklower ylwe, ysubseq, ycredit); 102736401Ssklower ENDDEBUG 102836401Ssklower } 102936401Ssklower break; 103036401Ssklower 103136401Ssklower default: 103236401Ssklower IFDEBUG(D_TPINPUT) 103336401Ssklower printf("param ignored dutype 0x%x, code 0x%x\n", 103436401Ssklower dutype, vbptr(P)->tpv_code); 103536401Ssklower ENDDEBUG 103636401Ssklower IFTRACE(D_TPINPUT) 103736401Ssklower tptrace(TPPTmisc, "param ignored dutype code ", 103836401Ssklower dutype, vbptr(P)->tpv_code ,0,0); 103936401Ssklower ENDTRACE 104036401Ssklower IncStat(ts_param_ignored); 104136401Ssklower break; 104236401Ssklower #undef caseof 104336401Ssklower } 104436401Ssklower /* } */ END_WHILE_OPTIONS(P) 104536401Ssklower 104636401Ssklower /* NOTE: the variable dutype has been shifted left! */ 104736401Ssklower 104836401Ssklower switch( hdr->tpdu_type ) { 104936401Ssklower case CC_TPDU_type: 105036401Ssklower /* If CC comes back with an unacceptable class 105136401Ssklower * respond with a DR or ER 105236401Ssklower */ 105336401Ssklower 105436401Ssklower opt = hdr->tpdu_CCoptions; /* 1 byte */ 105536401Ssklower 105636401Ssklower { 105736401Ssklower tpp = tpcb->_tp_param; 105836401Ssklower tpp.p_class = (1<<hdr->tpdu_CCclass); 105936401Ssklower tpp.p_tpdusize = dusize; 106036401Ssklower tpp.p_dont_change_params = 0; 106136401Ssklower tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT; 106236401Ssklower tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD; 106336401Ssklower tpp.p_use_checksum = (addlopt & TPAO_NO_CSUM) == 0; 106436401Ssklower #ifdef notdef 106536401Ssklower tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC; 106636401Ssklower tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD; 106736401Ssklower tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC; 106836401Ssklower #endif notdef 106936401Ssklower 107036401Ssklower CHECK( 107136401Ssklower tp_consistency(tpcb, TP_FORCE, &tpp) != 0, 107236401Ssklower E_TP_NEGOT_FAILED, ts_negotfailed, respond, 107336401Ssklower (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 107436401Ssklower /* ^ more or less the location of class */ 107536401Ssklower ) 107636401Ssklower IFTRACE(D_CONN) 107736401Ssklower tptrace(TPPTmisc, 107836401Ssklower "after 1 consist class, out, tpconsout", 107936401Ssklower tpcb->tp_class, dgout_routine, tpcons_output, 0 108036401Ssklower ); 108136401Ssklower ENDTRACE 108236401Ssklower CHECK( 108336401Ssklower ((class_to_use == TP_CLASS_0)&& 108436401Ssklower (dgout_routine != tpcons_output)), 108536401Ssklower E_TP_NEGOT_FAILED, ts_negotfailed, respond, 108636401Ssklower (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 108736401Ssklower /* ^ more or less the location of class */ 108836401Ssklower ) 108945900Ssklower #ifdef TPCONS 109045900Ssklower if (tpcb->tp_netservice == ISO_CONS && 109145900Ssklower class_to_use == TP_CLASS_0) { 109245900Ssklower struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb; 109345900Ssklower struct pklcd *lcp = (struct pklcd *)isop->isop_chan; 109445900Ssklower lcp->lcd_flags &= ~X25_DG_CIRCUIT; 109545900Ssklower } 109645900Ssklower #endif 109736401Ssklower } 109836401Ssklower if( ! tpcb->tp_use_checksum) 109936401Ssklower IncStat(ts_csum_off); 110036401Ssklower if(tpcb->tp_xpd_service) 110136401Ssklower IncStat(ts_use_txpd); 110236401Ssklower if(tpcb->tp_xtd_format) 110336401Ssklower IncStat(ts_xtd_fmt); 110436401Ssklower 110536401Ssklower IFTRACE(D_CONN) 110636401Ssklower tptrace(TPPTmisc, "after CC class flags dusize CCclass", 110736401Ssklower tpcb->tp_class, tpcb->tp_flags, tpcb->tp_tpdusize, 110836401Ssklower hdr->tpdu_CCclass); 110936401Ssklower ENDTRACE 111036401Ssklower 111136401Ssklower /* 111236401Ssklower * Get the maximum transmission unit from the lower layer(s) 111336401Ssklower * so we can decide how large a TPDU size to negotiate. 111436401Ssklower * It would be nice if the arguments to this 111536401Ssklower * were more reasonable. 111636401Ssklower */ 111736401Ssklower (tpcb->tp_nlproto->nlp_mtu)(tpcb->tp_sock, tpcb->tp_sock->so_pcb, 111836401Ssklower &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0); 111936401Ssklower 112036401Ssklower 112136401Ssklower /* if called or calling suffices appeared on the CC, 112236401Ssklower * they'd better jive with what's in the pcb 112336401Ssklower */ 112436401Ssklower if( fsufxlen ) { 112536401Ssklower CHECK( ((tpcb->tp_fsuffixlen != fsufxlen) || 112636401Ssklower bcmp(fsufxloc, tpcb->tp_fsuffix, fsufxlen)), 112736401Ssklower E_TP_INV_PVAL,ts_inv_sufx, respond, 112836401Ssklower (1+fsufxloc - (caddr_t)hdr)) 112936401Ssklower } 113036401Ssklower if( lsufxlen ) { 113136401Ssklower CHECK( ((tpcb->tp_lsuffixlen != lsufxlen) || 113236401Ssklower bcmp(lsufxloc, tpcb->tp_lsuffix, lsufxlen)), 113336401Ssklower E_TP_INV_PVAL,ts_inv_sufx, respond, 113436401Ssklower (1+lsufxloc - (caddr_t)hdr)) 113536401Ssklower } 113636401Ssklower 113736401Ssklower e.ATTR(CC_TPDU).e_sref = sref; 113836401Ssklower e.ATTR(CC_TPDU).e_cdt = hdr->tpdu_CCcdt; 113936401Ssklower takes_data = TRUE; 114036401Ssklower e.ev_number = CC_TPDU; 114136401Ssklower IncStat(ts_CC_rcvd); 114236401Ssklower break; 114336401Ssklower 114436401Ssklower case DC_TPDU_type: 114536401Ssklower if (sref != tpcb->tp_fref) 114636401Ssklower printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n", 114736401Ssklower sref, tpcb->tp_fref); 114836401Ssklower 114936401Ssklower CHECK( (sref != tpcb->tp_fref), 115042944Ssklower E_TP_MISM_REFS, ts_inv_sufx, discard, 115136401Ssklower (1 + (caddr_t)&hdr->tpdu_DCsref - (caddr_t)hdr)) 115242944Ssklower 115336401Ssklower e.ev_number = DC_TPDU; 115436401Ssklower IncStat(ts_DC_rcvd); 115536401Ssklower break; 115636401Ssklower 115736401Ssklower case DR_TPDU_type: 115836401Ssklower IFTRACE(D_TPINPUT) 115936401Ssklower tptrace(TPPTmisc, "DR recvd", hdr->tpdu_DRreason, 0, 0, 0); 116036401Ssklower ENDTRACE 116142944Ssklower if (sref != tpcb->tp_fref) { 116236401Ssklower printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n", 116336401Ssklower sref, tpcb->tp_fref); 116442944Ssklower } 116536401Ssklower 116642944Ssklower CHECK( (sref != 0 && sref != tpcb->tp_fref && 116742944Ssklower tpcb->tp_state != TP_CRSENT), 116842944Ssklower (TP_ERROR_SNDC | E_TP_MISM_REFS),ts_inv_sufx, respond, 116936401Ssklower (1 + (caddr_t)&hdr->tpdu_DRsref - (caddr_t)hdr)) 117036401Ssklower 117136401Ssklower e.ATTR(DR_TPDU).e_reason = hdr->tpdu_DRreason; 117236401Ssklower e.ATTR(DR_TPDU).e_sref = (u_short)sref; 117336401Ssklower takes_data = TRUE; 117436401Ssklower e.ev_number = DR_TPDU; 117536401Ssklower IncStat(ts_DR_rcvd); 117636401Ssklower break; 117736401Ssklower 117836401Ssklower case ER_TPDU_type: 117936401Ssklower IFTRACE(D_TPINPUT) 118036401Ssklower tptrace(TPPTmisc, "ER recvd", hdr->tpdu_ERreason,0,0,0); 118136401Ssklower ENDTRACE 118236401Ssklower e.ev_number = ER_TPDU; 118336401Ssklower e.ATTR(ER_TPDU).e_reason = hdr->tpdu_ERreason; 118436401Ssklower IncStat(ts_ER_rcvd); 118536401Ssklower break; 118636401Ssklower 118736401Ssklower case AK_TPDU_type: 118836401Ssklower 118936401Ssklower e.ATTR(AK_TPDU).e_subseq = subseq; 119036401Ssklower e.ATTR(AK_TPDU).e_fcc_present = fcc_present; 119136401Ssklower 119236401Ssklower if (tpcb->tp_xtd_format) { 119336401Ssklower #ifdef BYTE_ORDER 119436401Ssklower union seq_type seqeotX; 119536401Ssklower 119636401Ssklower seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 119736401Ssklower e.ATTR(AK_TPDU).e_seq = seqeotX.s_seq; 119836401Ssklower e.ATTR(AK_TPDU).e_cdt = ntohs(hdr->tpdu_AKcdtX); 119936401Ssklower #else 120036401Ssklower e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdtX; 120136401Ssklower e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseqX; 120236401Ssklower #endif BYTE_ORDER 120336401Ssklower } else { 120436401Ssklower e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdt; 120536401Ssklower e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseq; 120636401Ssklower } 120736401Ssklower IFTRACE(D_TPINPUT) 120836401Ssklower tptrace(TPPTmisc, "AK recvd seq cdt subseq fcc_pres", 120936401Ssklower e.ATTR(AK_TPDU).e_seq, e.ATTR(AK_TPDU).e_cdt, 121036401Ssklower subseq, fcc_present); 121136401Ssklower ENDTRACE 121236401Ssklower 121336401Ssklower e.ev_number = AK_TPDU; 121436401Ssklower IncStat(ts_AK_rcvd); 121536401Ssklower IncPStat(tpcb, tps_AK_rcvd); 121636401Ssklower break; 121736401Ssklower 121836401Ssklower case XAK_TPDU_type: 121936401Ssklower if (tpcb->tp_xtd_format) { 122036401Ssklower #ifdef BYTE_ORDER 122136401Ssklower union seq_type seqeotX; 122236401Ssklower 122336401Ssklower seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 122436401Ssklower e.ATTR(XAK_TPDU).e_seq = seqeotX.s_seq; 122536401Ssklower #else 122636401Ssklower e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseqX; 122736401Ssklower #endif BYTE_ORDER 122836401Ssklower } else { 122936401Ssklower e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseq; 123036401Ssklower } 123136401Ssklower e.ev_number = XAK_TPDU; 123236401Ssklower IncStat(ts_XAK_rcvd); 123336401Ssklower IncPStat(tpcb, tps_XAK_rcvd); 123436401Ssklower break; 123536401Ssklower 123636401Ssklower case XPD_TPDU_type: 123736401Ssklower if (tpcb->tp_xtd_format) { 123836401Ssklower #ifdef BYTE_ORDER 123936401Ssklower union seq_type seqeotX; 124036401Ssklower 124136401Ssklower seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 124236401Ssklower e.ATTR(XPD_TPDU).e_seq = seqeotX.s_seq; 124336401Ssklower #else 124436401Ssklower e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseqX; 124536401Ssklower #endif BYTE_ORDER 124636401Ssklower } else { 124736401Ssklower e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseq; 124836401Ssklower } 124936401Ssklower takes_data = TRUE; 125036401Ssklower e.ev_number = XPD_TPDU; 125136401Ssklower IncStat(ts_XPD_rcvd); 125236401Ssklower IncPStat(tpcb, tps_XPD_rcvd); 125336401Ssklower break; 125436401Ssklower 125536401Ssklower case DT_TPDU_type: 125636401Ssklower { /* the y option will cause occasional packets to be dropped. 125736401Ssklower * A little crude but it works. 125836401Ssklower */ 125936401Ssklower 126036401Ssklower IFDEBUG(D_DROP) 126136401Ssklower if(time.tv_usec & 0x4 && hdr->tpdu_DTseq & 0x1) { 126236401Ssklower IncStat(ts_ydebug); 126336401Ssklower goto discard; 126436401Ssklower } 126536401Ssklower ENDDEBUG 126636401Ssklower } 126736401Ssklower if (tpcb->tp_class == TP_CLASS_0) { 126836401Ssklower e.ATTR(DT_TPDU).e_seq = 0; /* actually don't care */ 126936401Ssklower e.ATTR(DT_TPDU).e_eot = (((struct tp0du *)hdr)->tp0du_eot); 127036401Ssklower } else if (tpcb->tp_xtd_format) { 127136401Ssklower #ifdef BYTE_ORDER 127236401Ssklower union seq_type seqeotX; 127336401Ssklower 127436401Ssklower seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 127536401Ssklower e.ATTR(DT_TPDU).e_seq = seqeotX.s_seq; 127636401Ssklower e.ATTR(DT_TPDU).e_eot = seqeotX.s_eot; 127736401Ssklower #else 127836401Ssklower e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseqX; 127936401Ssklower e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeotX; 128036401Ssklower #endif BYTE_ORDER 128136401Ssklower } else { 128236401Ssklower e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseq; 128336401Ssklower e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeot; 128436401Ssklower } 128536401Ssklower if(e.ATTR(DT_TPDU).e_eot) 128636401Ssklower IncStat(ts_eot_input); 128736401Ssklower takes_data = TRUE; 128836401Ssklower e.ev_number = DT_TPDU; 128936401Ssklower IncStat(ts_DT_rcvd); 129036401Ssklower IncPStat(tpcb, tps_DT_rcvd); 129136401Ssklower break; 129236401Ssklower 129336401Ssklower case GR_TPDU_type: 129436401Ssklower tp_indicate(T_DISCONNECT, tpcb, ECONNABORTED); 129536401Ssklower /* drop through */ 129636401Ssklower default: 129736401Ssklower /* this should NEVER happen because there is a 129836401Ssklower * check for dutype well above here 129936401Ssklower */ 130036401Ssklower error = E_TP_INV_TPDU; /* causes an ER */ 130136401Ssklower IFDEBUG(D_TPINPUT) 130236401Ssklower printf("INVALID dutype 0x%x\n", hdr->tpdu_type); 130336401Ssklower ENDDEBUG 130436401Ssklower IncStat(ts_inv_dutype); 130536401Ssklower goto respond; 130636401Ssklower } 130736401Ssklower } 130836401Ssklower /* peel off the tp header; 130936401Ssklower * remember that the du_li doesn't count itself. 131036401Ssklower * This may leave us w/ an empty mbuf at the front of a chain. 131136401Ssklower * We can't just throw away the empty mbuf because hdr still points 131236401Ssklower * into the mbuf's data area and we're still using hdr (the tpdu header) 131336401Ssklower */ 131436401Ssklower m->m_len -= ((int)hdr->tpdu_li + 1); 131537469Ssklower m->m_data += ((int)hdr->tpdu_li + 1); 131636401Ssklower 131737469Ssklower if (takes_data) { 131837469Ssklower int max = tpdu_info[ hdr->tpdu_type ] [TP_MAX_DATA_INDEX]; 131937469Ssklower int datalen = tpdu_len - hdr->tpdu_li - 1, mbtype = MT_DATA; 1320*48749Ssklower struct { 1321*48749Ssklower struct tp_disc_reason dr; 1322*48749Ssklower struct cmsghdr x_hdr; 1323*48749Ssklower } x; 1324*48749Ssklower #define c_hdr x.x_hdr 1325*48749Ssklower register struct mbuf *n; 132636401Ssklower 132737469Ssklower CHECK( (max && datalen > max), E_TP_LENGTH_INVAL, 132837469Ssklower ts_inv_length, respond, (max + hdr->tpdu_li + 1) ); 132936401Ssklower switch( hdr->tpdu_type ) { 133037469Ssklower 133136401Ssklower case CR_TPDU_type: 133237469Ssklower c_hdr.cmsg_type = TPOPT_CONN_DATA; 133337469Ssklower goto make_control_msg; 133437469Ssklower 133536401Ssklower case CC_TPDU_type: 133637469Ssklower c_hdr.cmsg_type = TPOPT_CFRM_DATA; 133737469Ssklower goto make_control_msg; 133837469Ssklower 133936401Ssklower case DR_TPDU_type: 1340*48749Ssklower x.dr.dr_hdr.cmsg_len = sizeof(x) - sizeof(c_hdr); 1341*48749Ssklower x.dr.dr_hdr.cmsg_type = TPOPT_DISC_REASON; 1342*48749Ssklower x.dr.dr_hdr.cmsg_level = SOL_TRANSPORT; 1343*48749Ssklower x.dr.dr_reason = hdr->tpdu_DRreason; 134437469Ssklower c_hdr.cmsg_type = TPOPT_DISC_DATA; 134537469Ssklower make_control_msg: 1346*48749Ssklower datalen += sizeof(c_hdr); 1347*48749Ssklower c_hdr.cmsg_len = datalen; 134837469Ssklower c_hdr.cmsg_level = SOL_TRANSPORT; 134937469Ssklower mbtype = MT_CONTROL; 135043334Ssklower MGET(n, M_DONTWAIT, MT_DATA); 1351*48749Ssklower if (n == 0) 1352*48749Ssklower {m_freem(m); m = 0; datalen = 0; goto invoke; } 1353*48749Ssklower if (hdr->tpdu_type == DR_TPDU_type) { 1354*48749Ssklower datalen += sizeof(x) - sizeof(c_hdr); 1355*48749Ssklower bcopy((caddr_t)&x, mtod(n, caddr_t), n->m_len = sizeof(x)); 1356*48749Ssklower } else 1357*48749Ssklower bcopy((caddr_t)&c_hdr, mtod(n, caddr_t), 1358*48749Ssklower n->m_len = sizeof(c_hdr)); 1359*48749Ssklower n->m_next = m; 1360*48749Ssklower m = n; 136137469Ssklower /* FALLTHROUGH */ 136237469Ssklower 136336401Ssklower case XPD_TPDU_type: 136437469Ssklower if (mbtype != MT_CONTROL) 136537469Ssklower mbtype = MT_OOBDATA; 136637469Ssklower m->m_flags |= M_EOR; 136737469Ssklower /* FALLTHROUGH */ 136837469Ssklower 136936401Ssklower case DT_TPDU_type: 137037469Ssklower for (n = m; n; n = n->m_next) { 137137469Ssklower MCHTYPE(n, mbtype); 137237469Ssklower } 137343334Ssklower invoke: 137437469Ssklower e.ATTR(DT_TPDU).e_datalen = datalen; 137536401Ssklower e.ATTR(DT_TPDU).e_data = m; 137636401Ssklower break; 137736401Ssklower 137836401Ssklower default: 137936401Ssklower printf( 138036401Ssklower "ERROR in tp_input! hdr->tpdu_type 0x%x takes_data 0x%x m 0x%x\n", 138136401Ssklower hdr->tpdu_type, takes_data, m); 138236401Ssklower break; 138336401Ssklower } 138436401Ssklower /* prevent m_freem() after tp_driver() from throwing it all away */ 138536401Ssklower m = MNULL; 138636401Ssklower } 138736401Ssklower 138836401Ssklower IncStat(ts_tpdu_rcvd); 138936401Ssklower 139036401Ssklower IFDEBUG(D_TPINPUT) 139136401Ssklower printf( "tp_input: before driver, state 0x%x event 0x%x m 0x%x", 139236401Ssklower tpcb->tp_state, e.ev_number, m ); 139336401Ssklower printf(" e.e_data 0x%x\n", e.ATTR(DT_TPDU).e_data); 139436401Ssklower printf("takes_data 0x%x m_len 0x%x, tpdu_len 0x%x\n", 139536401Ssklower takes_data, (m==MNULL)?0:m->m_len, tpdu_len); 139636401Ssklower ENDDEBUG 139736401Ssklower 139836401Ssklower error = tp_driver(tpcb, &e); 139936401Ssklower 140036401Ssklower ASSERT(tpcb != (struct tp_pcb *)0); 140136401Ssklower ASSERT(tpcb->tp_sock != (struct socket *)0); 140236401Ssklower if( tpcb->tp_sock->so_error == 0 ) 140336401Ssklower tpcb->tp_sock->so_error = error; 140436401Ssklower 140536401Ssklower /* Kludge to keep the state tables under control (adding 140636401Ssklower * data on connect & disconnect & freeing the mbuf containing 140736401Ssklower * the data would have exploded the tables and made a big mess ). 140836401Ssklower */ 140936401Ssklower switch(e.ev_number) { 141036401Ssklower case CC_TPDU: 141136401Ssklower case DR_TPDU: 141236401Ssklower case CR_TPDU: 141336401Ssklower m = e.ATTR(CC_TPDU).e_data; /* same field for all three dutypes */ 141436401Ssklower IFDEBUG(D_TPINPUT) 141536401Ssklower printf("after driver, restoring m to 0x%x, takes_data 0x%x\n", 141636401Ssklower m, takes_data); 141736401Ssklower ENDDEBUG 141836401Ssklower break; 141936401Ssklower default: 142036401Ssklower break; 142136401Ssklower } 142236401Ssklower /* Concatenated sequences are terminated by any tpdu that 142336401Ssklower * carries data: CR, CC, DT, XPD, DR. 142436401Ssklower * All other tpdu types may be concatenated: AK, XAK, DC, ER. 142536401Ssklower */ 142636401Ssklower 142736401Ssklower separate: 142836401Ssklower if ( takes_data == 0 ) { 142936401Ssklower ASSERT( m != MNULL ); 143036401Ssklower /* 143136401Ssklower * we already peeled off the prev. tp header so 143236401Ssklower * we can just pull up some more and repeat 143336401Ssklower */ 143436401Ssklower 143537469Ssklower if( m = tp_inputprep(m) ) { 143636401Ssklower IFDEBUG(D_TPINPUT) 143736401Ssklower hdr = mtod(m, struct tpdu *); 143836401Ssklower printf("tp_input @ separate: hdr 0x%x size %d m 0x%x\n", 143936401Ssklower hdr, (int) hdr->tpdu_li + 1, m); 144036401Ssklower dump_mbuf(m, "tp_input after driver, at separate"); 144136401Ssklower ENDDEBUG 144236401Ssklower 144336401Ssklower IncStat(ts_concat_rcvd); 144436401Ssklower goto again; 144536401Ssklower } 144636401Ssklower } 144736401Ssklower if ( m != MNULL ) { 144836401Ssklower IFDEBUG(D_TPINPUT) 144936401Ssklower printf("tp_input : m_freem(0x%x)\n", m); 145036401Ssklower ENDDEBUG 145136401Ssklower m_freem(m); 145236401Ssklower IFDEBUG(D_TPINPUT) 145336401Ssklower printf("tp_input : after m_freem 0x%x\n", m); 145436401Ssklower ENDDEBUG 145536401Ssklower } 145636401Ssklower return (ProtoHook) tpcb; 145736401Ssklower 145836401Ssklower discard: 145936401Ssklower /* class 4: drop the tpdu */ 146036401Ssklower /* class 2,0: Should drop the net connection, if you can figure out 146136401Ssklower * to which connection it applies 146236401Ssklower */ 146336401Ssklower IFDEBUG(D_TPINPUT) 146436401Ssklower printf("tp_input DISCARD\n"); 146536401Ssklower ENDDEBUG 146636401Ssklower IFTRACE(D_TPINPUT) 146736401Ssklower tptrace(TPPTmisc, "tp_input DISCARD m", m,0,0,0); 146836401Ssklower ENDTRACE 146936401Ssklower m_freem(m); 147036401Ssklower IncStat(ts_recv_drop); 147136401Ssklower return (ProtoHook)0; 147236401Ssklower 147342944Ssklower nonx_dref: 147442944Ssklower switch (dutype) { 147542944Ssklower default: 147642944Ssklower goto discard; 147742944Ssklower case CC_TPDU_type: 147842944Ssklower /* error = E_TP_MISM_REFS; */ 147942944Ssklower break; 148042944Ssklower case DR_TPDU_type: 148142944Ssklower error |= TP_ERROR_SNDC; 148242944Ssklower } 148336401Ssklower respond: 148443334Ssklower IFDEBUG(D_TPINPUT) 148542944Ssklower printf("RESPOND: error 0x%x, errlen 0x%x\n", error, errlen); 148636401Ssklower ENDDEBUG 148736401Ssklower IFTRACE(D_TPINPUT) 148842944Ssklower tptrace(TPPTmisc, "tp_input RESPOND m error sref", m, error, sref, 0); 148936401Ssklower ENDTRACE 149042944Ssklower if (sref == 0) 149136401Ssklower goto discard; 149237469Ssklower (void) tp_error_emit(error, (u_long)sref, (struct sockaddr_iso *)faddr, 149342944Ssklower (struct sockaddr_iso *)laddr, m, errlen, tpcb, 149437469Ssklower (int)cons_channel, dgout_routine); 149536401Ssklower IFDEBUG(D_ERROR_EMIT) 149636401Ssklower printf("tp_input after error_emit\n"); 149736401Ssklower ENDDEBUG 149836401Ssklower 149936401Ssklower #ifdef lint 150036401Ssklower printf("",sref,opt); 150136401Ssklower #endif lint 150236401Ssklower IncStat(ts_recv_drop); 150336401Ssklower return (ProtoHook)0; 150436401Ssklower } 150536401Ssklower 150636401Ssklower 150736401Ssklower /* 150836401Ssklower * NAME: tp_headersize() 150936401Ssklower * 151036401Ssklower * CALLED FROM: 151136401Ssklower * tp_emit() and tp_sbsend() 151236401Ssklower * TP needs to know the header size so it can figure out how 151336401Ssklower * much data to put in each tpdu. 151436401Ssklower * 151536401Ssklower * FUNCTION, ARGUMENTS, and RETURN VALUE: 151636401Ssklower * For a given connection, represented by (tpcb), and 151736401Ssklower * tpdu type (dutype), return the size of a tp header. 151836401Ssklower * 151936401Ssklower * RETURNS: the expected size of the heade in bytesr 152036401Ssklower * 152136401Ssklower * SIDE EFFECTS: 152236401Ssklower * 152336401Ssklower * NOTES: It would be nice if it got the network header size as well. 152436401Ssklower */ 152536401Ssklower int 152636401Ssklower tp_headersize(dutype, tpcb) 152736401Ssklower int dutype; 152836401Ssklower struct tp_pcb *tpcb; 152936401Ssklower { 153036401Ssklower register int size = 0; 153136401Ssklower 153236401Ssklower IFTRACE(D_CONN) 153336401Ssklower tptrace(TPPTmisc, "tp_headersize dutype class xtd_format", 153436401Ssklower dutype, tpcb->tp_class, tpcb->tp_xtd_format, 0); 153536401Ssklower ENDTRACE 153636401Ssklower if( !( (tpcb->tp_class == TP_CLASS_0) || 153736401Ssklower (tpcb->tp_class == TP_CLASS_4) || 153836401Ssklower (dutype == DR_TPDU_type) || 153936401Ssklower (dutype == CR_TPDU_type) )) { 154036401Ssklower printf("tp_headersize:dutype 0x%x, class 0x%x", 154136401Ssklower dutype, tpcb->tp_class); 154236401Ssklower /* TODO: identify this and GET RID OF IT */ 154336401Ssklower } 154436401Ssklower ASSERT( (tpcb->tp_class == TP_CLASS_0) || 154536401Ssklower (tpcb->tp_class == TP_CLASS_4) || 154636401Ssklower (dutype == DR_TPDU_type) || 154736401Ssklower (dutype == CR_TPDU_type) ); 154836401Ssklower 154936401Ssklower if( tpcb->tp_class == TP_CLASS_0 ) { 155036401Ssklower size = tpdu_info[ dutype ] [TP_LEN_CLASS_0_INDEX]; 155136401Ssklower } else { 155236401Ssklower size = tpdu_info[ dutype ] [tpcb->tp_xtd_format]; 155336401Ssklower } 155436401Ssklower return size; 155536401Ssklower /* caller must get network level header size separately */ 155636401Ssklower } 1557