149268Sbostic /*- 249268Sbostic * Copyright (c) 1991 The Regents of the University of California. 349268Sbostic * All rights reserved. 449268Sbostic * 549268Sbostic * %sccs.include.redist.c% 649268Sbostic * 7*53682Ssklower * @(#)tp_input.c 7.28 (Berkeley) 05/27/92 849268Sbostic */ 949268Sbostic 1036401Ssklower /*********************************************************** 1136401Ssklower Copyright IBM Corporation 1987 1236401Ssklower 1336401Ssklower All Rights Reserved 1436401Ssklower 1536401Ssklower Permission to use, copy, modify, and distribute this software and its 1636401Ssklower documentation for any purpose and without fee is hereby granted, 1736401Ssklower provided that the above copyright notice appear in all copies and that 1836401Ssklower both that copyright notice and this permission notice appear in 1936401Ssklower supporting documentation, and that the name of IBM not be 2036401Ssklower used in advertising or publicity pertaining to distribution of the 2136401Ssklower software without specific, written prior permission. 2236401Ssklower 2336401Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 2436401Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 2536401Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 2636401Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 2736401Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 2836401Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 2936401Ssklower SOFTWARE. 3036401Ssklower 3136401Ssklower ******************************************************************/ 3236401Ssklower 3336401Ssklower /* 3436401Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 3536401Ssklower */ 3636401Ssklower /* 3736401Ssklower * ARGO TP 3836401Ssklower * 3936401Ssklower * $Header: tp_input.c,v 5.6 88/11/18 17:27:38 nhall Exp $ 4036401Ssklower * $Source: /usr/argo/sys/netiso/RCS/tp_input.c,v $ 4136401Ssklower * 4236401Ssklower * tp_input() gets an mbuf chain from ip. Actually, not directly 4336401Ssklower * from ip, because ip calls a net-level routine that strips off 4436401Ssklower * the net header and then calls tp_input(), passing the proper type 4536401Ssklower * of addresses for the address family in use (how it figures out 4650648Ssklower * which AF is not yet determined.) 4736401Ssklower * 4836401Ssklower * Decomposing the tpdu is some of the most laughable code. The variable-length 4936401Ssklower * parameters and the problem of non-aligned memory references 5036401Ssklower * necessitates such abominations as the macros WHILE_OPTIONS (q.v. below) 5136401Ssklower * to loop through the header and decompose it. 5236401Ssklower * 5336401Ssklower * The routine tp_newsocket() is called when a CR comes in for a listening 5436401Ssklower * socket. tp_input calls sonewconn() and tp_newsocket() to set up the 5536401Ssklower * "child" socket. Most tpcb values are copied from the parent tpcb into 5636401Ssklower * the child. 5736401Ssklower * 5836401Ssklower * Also in here is tp_headersize() (grot) which tells the expected size 5936401Ssklower * of a tp header, to be used by other layers. It's in here because it 6036401Ssklower * uses the static structure tpdu_info. 6136401Ssklower */ 6236401Ssklower 6336401Ssklower #include "param.h" 6444422Ssklower #include "systm.h" 6536401Ssklower #include "mbuf.h" 6636401Ssklower #include "socket.h" 6736401Ssklower #include "socketvar.h" 6836401Ssklower #include "domain.h" 6936401Ssklower #include "protosw.h" 7036401Ssklower #include "errno.h" 7136401Ssklower #include "time.h" 7236401Ssklower #include "kernel.h" 7336401Ssklower #include "types.h" 7445900Ssklower #include "iso.h" 7537469Ssklower #include "iso_errno.h" 7645900Ssklower #include "iso_pcb.h" 7737469Ssklower #include "tp_param.h" 7837469Ssklower #include "tp_timer.h" 7937469Ssklower #include "tp_stat.h" 8037469Ssklower #include "tp_pcb.h" 8137469Ssklower #include "argo_debug.h" 8237469Ssklower #include "tp_trace.h" 8337469Ssklower #include "tp_tpdu.h" 8436401Ssklower 8545900Ssklower #include "../net/if.h" 8645900Ssklower #ifdef TRUE 8745900Ssklower #undef FALSE 8845900Ssklower #undef TRUE 8945900Ssklower #endif 9045900Ssklower #include "../netccitt/x25.h" 9145900Ssklower #include "../netccitt/pk.h" 9245900Ssklower #include "../netccitt/pk_var.h" 9345900Ssklower 9436401Ssklower int iso_check_csum(), tp_driver(), tp_headersize(), tp_error_emit(); 9536401Ssklower 9637469Ssklower /* 9737469Ssklower #ifdef lint 9837469Ssklower #undef ATTR 9937469Ssklower #define ATTR(X)ev_number 10037469Ssklower #endif lint 10137469Ssklower */ 10236401Ssklower 10336401Ssklower struct mbuf * 10436401Ssklower tp_inputprep(m) 10537469Ssklower register struct mbuf *m; 10636401Ssklower { 10737469Ssklower int hdrlen; 10836401Ssklower 10936401Ssklower IFDEBUG(D_TPINPUT) 11037469Ssklower printf("tp_inputprep: m 0x%x\n", m) ; 11136401Ssklower ENDDEBUG 11236401Ssklower 11336401Ssklower while( m->m_len < 1 ) { 11436401Ssklower if( (m = m_free(m)) == MNULL ) { 11536401Ssklower return (struct mbuf *)0; 11636401Ssklower } 11736401Ssklower } 11837469Ssklower if(((int)m->m_data) & 0x3) { 11937469Ssklower /* If we are not 4-byte aligned, we have to be 12037469Ssklower * above the beginning of the mbuf, and it is ok just 12137469Ssklower * to slide it back. 12237469Ssklower */ 12337469Ssklower caddr_t ocp = m->m_data; 12436401Ssklower 12537469Ssklower m->m_data = (caddr_t)(((int)m->m_data) & ~0x3); 12652465Smckusick bcopy(ocp, m->m_data, (unsigned)m->m_len); 12736401Ssklower } 12836401Ssklower CHANGE_MTYPE(m, TPMT_DATA); 12936401Ssklower 13037469Ssklower /* we KNOW that there is at least 1 byte in this mbuf 13137469Ssklower and that it is hdr->tpdu_li XXXXXXX! */ 13236401Ssklower 13337469Ssklower hdrlen = 1 + *mtod( m, u_char *); 13436401Ssklower 13536401Ssklower /* 13636401Ssklower * now pull up the whole tp header 13736401Ssklower */ 13837469Ssklower if ( m->m_len < hdrlen) { 13937469Ssklower if ((m = m_pullup(m, hdrlen)) == MNULL ) { 14036401Ssklower IncStat(ts_recv_drop); 14136401Ssklower return (struct mbuf *)0; 14236401Ssklower } 14336401Ssklower } 14436401Ssklower IFDEBUG(D_INPUT) 14536401Ssklower printf( 14636401Ssklower " at end: m 0x%x hdr->tpdu_li 0x%x m_len 0x%x\n",m, 14737469Ssklower hdrlen, m->m_len); 14836401Ssklower ENDDEBUG 14936401Ssklower return m; 15036401Ssklower } 15136401Ssklower 15236401Ssklower /* begin groan 15336401Ssklower * -- this array and the following macros allow you to step through the 15436401Ssklower * parameters of the variable part of a header 15536401Ssklower * note that if for any reason the values of the **_TPDU macros (in tp_events.h) 15636401Ssklower * should change, this array has to be rearranged 15736401Ssklower */ 15836401Ssklower 15936401Ssklower #define TP_LEN_CLASS_0_INDEX 2 16036401Ssklower #define TP_MAX_DATA_INDEX 3 16136401Ssklower 16236401Ssklower static u_char tpdu_info[][4] = 16336401Ssklower { 16436401Ssklower /* length max data len */ 16536401Ssklower /* reg fmt xtd fmt class 0 */ 16636401Ssklower /* UNUSED 0x0 */ 0x0 , 0x0, 0x0, 0x0, 16736401Ssklower /* XPD_TPDU_type 0x1 */ 0x5, 0x8, 0x0, TP_MAX_XPD_DATA, 16836401Ssklower /* XAK_TPDU_type 0x2 */ 0x5 , 0x8, 0x0, 0x0, 16936401Ssklower /* GR_TPDU_type 0x3 */ 0x0 , 0x0, 0x0, 0x0, 17036401Ssklower /* UNUSED 0x4 */ 0x0 , 0x0, 0x0, 0x0, 17136401Ssklower /* UNUSED 0x5 */ 0x0 , 0x0, 0x0, 0x0, 17236401Ssklower /* AK_TPDU_type 0x6 */ 0x5, 0xa, 0x0, 0x0, 17336401Ssklower /* ER_TPDU_type 0x7 */ 0x5, 0x5, 0x0, 0x0, 17436401Ssklower /* DR_TPDU_type 0x8 */ 0x7, 0x7, 0x7, TP_MAX_DR_DATA, 17536401Ssklower /* UNUSED 0x9 */ 0x0 , 0x0, 0x0, 0x0, 17636401Ssklower /* UNUSED 0xa */ 0x0 , 0x0, 0x0, 0x0, 17736401Ssklower /* UNUSED 0xb */ 0x0 , 0x0, 0x0, 0x0, 17836401Ssklower /* DC_TPDU_type 0xc */ 0x6, 0x6, 0x0, 0x0, 17936401Ssklower /* CC_TPDU_type 0xd */ 0x7, 0x7, 0x7, TP_MAX_CC_DATA, 18036401Ssklower /* CR_TPDU_type 0xe */ 0x7, 0x7, 0x7, TP_MAX_CR_DATA, 18136401Ssklower /* DT_TPDU_type 0xf */ 0x5, 0x8, 0x3, 0x0, 18236401Ssklower }; 18336401Ssklower 18442944Ssklower #define CHECK(Phrase, Erval, Stat, Whattodo, Loc)\ 18543334Ssklower if (Phrase) {error = (Erval); errlen = (int)(Loc); IncStat(Stat); tpibrk();\ 18642944Ssklower goto Whattodo; } 18742944Ssklower 18843334Ssklower tpibrk() {} 18943334Ssklower 19036401Ssklower /* 19136401Ssklower * WHENEVER YOU USE THE FOLLOWING MACRO, 19236401Ssklower * BE SURE THE TPDUTYPE IS A LEGIT VALUE FIRST! 19336401Ssklower */ 19436401Ssklower 19542944Ssklower #define WHILE_OPTIONS(P, hdr, format)\ 19642944Ssklower { register caddr_t P = tpdu_info[(hdr)->tpdu_type][(format)] + (caddr_t)hdr;\ 19742944Ssklower caddr_t PLIM = 1 + hdr->tpdu_li + (caddr_t)hdr;\ 19842944Ssklower for (;; P += 2 + ((struct tp_vbp *)P)->tpv_len) {\ 19942944Ssklower CHECK((P > PLIM), E_TP_LENGTH_INVAL, ts_inv_length,\ 20042944Ssklower respond, P - (caddr_t)hdr);\ 20142944Ssklower if (P == PLIM) break; 20236401Ssklower 20342944Ssklower #define END_WHILE_OPTIONS(P) } } 20436401Ssklower 20536401Ssklower /* end groan */ 20636401Ssklower 20736401Ssklower /* 20836401Ssklower * NAME: tp_newsocket() 20936401Ssklower * 21036401Ssklower * CALLED FROM: 21136401Ssklower * tp_input() on incoming CR, when a socket w/ the called suffix 21236401Ssklower * is awaiting a connection request 21336401Ssklower * 21436401Ssklower * FUNCTION and ARGUMENTS: 21536401Ssklower * Create a new socket structure, attach to it a new transport pcb, 21636401Ssklower * using a copy of the net level pcb for the parent socket. 21736401Ssklower * (so) is the parent socket. 21836401Ssklower * (fname) is the foreign address (all that's used is the nsap portion) 21936401Ssklower * 22036401Ssklower * RETURN VALUE: 22136401Ssklower * a new socket structure, being this end of the newly formed connection. 22236401Ssklower * 22336401Ssklower * SIDE EFFECTS: 22436401Ssklower * Sets a few things in the tpcb and net level pcb 22536401Ssklower * 22636401Ssklower * NOTES: 22736401Ssklower */ 22836401Ssklower static struct socket * 22936401Ssklower tp_newsocket(so, fname, cons_channel, class_to_use, netservice) 23036401Ssklower struct socket *so; 23136401Ssklower struct sockaddr *fname; 23250648Ssklower caddr_t cons_channel; 23336401Ssklower u_char class_to_use; 23436401Ssklower u_int netservice; 23536401Ssklower { 23636401Ssklower register struct tp_pcb *tpcb = sototpcb(so); /* old tpcb, needed below */ 23745900Ssklower register struct tp_pcb *newtpcb; 23836401Ssklower 23936401Ssklower /* 24036401Ssklower * sonewconn() gets a new socket structure, 24136401Ssklower * a new lower layer pcb and a new tpcb, 24236401Ssklower * but the pcbs are unnamed (not bound) 24336401Ssklower */ 24436401Ssklower IFTRACE(D_NEWSOCK) 24538841Ssklower tptraceTPCB(TPPTmisc, "newsock: listg_so, _tpcb, so_head", 24639196Ssklower so, tpcb, so->so_head, 0); 24736401Ssklower ENDTRACE 24836401Ssklower 24940636Skarels if ((so = sonewconn(so, SS_ISCONFIRMING)) == (struct socket *)0) 25036401Ssklower return so; 25136401Ssklower IFTRACE(D_NEWSOCK) 25238841Ssklower tptraceTPCB(TPPTmisc, "newsock: after newconn so, so_head", 25338841Ssklower so, so->so_head, 0, 0); 25436401Ssklower ENDTRACE 25536401Ssklower 25636401Ssklower IFDEBUG(D_NEWSOCK) 25737469Ssklower printf("tp_newsocket(channel 0x%x) after sonewconn so 0x%x \n", 25837469Ssklower cons_channel, so); 25937469Ssklower dump_addr(fname); 26036401Ssklower { 26136401Ssklower struct socket *t, *head ; 26236401Ssklower 26336401Ssklower head = so->so_head; 26436401Ssklower t = so; 26536401Ssklower printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n", 26636401Ssklower t, t->so_head, t->so_q0, t->so_q0len); 26736401Ssklower while( (t=t->so_q0) && t!= so && t!= head) 26836401Ssklower printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n", 26936401Ssklower t, t->so_head, t->so_q0, t->so_q0len); 27036401Ssklower } 27136401Ssklower ENDDEBUG 27236401Ssklower 27336401Ssklower /* 27436401Ssklower * before we clobber the old tpcb ptr, get these items from the parent pcb 27536401Ssklower */ 27636401Ssklower newtpcb = sototpcb(so); 27736401Ssklower newtpcb->_tp_param = tpcb->_tp_param; 27836401Ssklower newtpcb->tp_flags = tpcb->tp_flags; 27936401Ssklower newtpcb->tp_lcredit = tpcb->tp_lcredit; 28036401Ssklower newtpcb->tp_l_tpdusize = tpcb->tp_l_tpdusize; 28136401Ssklower newtpcb->tp_lsuffixlen = tpcb->tp_lsuffixlen; 28236401Ssklower bcopy( tpcb->tp_lsuffix, newtpcb->tp_lsuffix, newtpcb->tp_lsuffixlen); 28336401Ssklower 28437469Ssklower if( /* old */ tpcb->tp_ucddata) { 28536401Ssklower /* 28637469Ssklower * These data are the connect- , confirm- or disconnect- data. 28736401Ssklower */ 28836401Ssklower struct mbuf *conndata; 28936401Ssklower 29037469Ssklower conndata = m_copy(tpcb->tp_ucddata, 0, (int)M_COPYALL); 29136401Ssklower IFDEBUG(D_CONN) 29236401Ssklower dump_mbuf(conndata, "conndata after mcopy"); 29336401Ssklower ENDDEBUG 29437469Ssklower newtpcb->tp_ucddata = conndata; 29536401Ssklower } 29636401Ssklower 29736401Ssklower tpcb = newtpcb; 29836401Ssklower tpcb->tp_state = TP_LISTENING; 29936401Ssklower tpcb->tp_class = class_to_use; 30036401Ssklower tpcb->tp_netservice = netservice; 30136401Ssklower 30236401Ssklower 30336401Ssklower ASSERT( fname != 0 ) ; /* just checking */ 30436401Ssklower if ( fname ) { 30536401Ssklower /* 30636401Ssklower * tp_route_to takes its address argument in the form of an mbuf. 30736401Ssklower */ 30836401Ssklower struct mbuf *m; 30936401Ssklower int err; 31036401Ssklower 31136401Ssklower MGET(m, M_DONTWAIT, MT_SONAME); /* mbuf type used is confusing */ 31236401Ssklower if (m) { 31336401Ssklower /* 31436401Ssklower * this seems a bit grotesque, but tp_route_to expects 31536401Ssklower * an mbuf * instead of simply a sockaddr; it calls the ll 31636401Ssklower * pcb_connect, which expects the name/addr in an mbuf as well. 31736401Ssklower * sigh. 31836401Ssklower */ 31937469Ssklower bcopy((caddr_t)fname, mtod(m, caddr_t), fname->sa_len); 32037469Ssklower m->m_len = fname->sa_len; 32136401Ssklower 32236401Ssklower /* grot : have to say the kernel can override params in 32336401Ssklower * the passive open case 32436401Ssklower */ 32536401Ssklower tpcb->tp_dont_change_params = 0; 32636401Ssklower err = tp_route_to( m, tpcb, cons_channel); 32736401Ssklower m_free(m); 32836401Ssklower 32936401Ssklower if (!err) 33036401Ssklower goto ok; 33136401Ssklower } 33236401Ssklower IFDEBUG(D_CONN) 33336401Ssklower printf("tp_route_to FAILED! detaching tpcb 0x%x, so 0x%x\n", 33436401Ssklower tpcb, so); 33536401Ssklower ENDDEBUG 33636401Ssklower (void) tp_detach(tpcb); 33736401Ssklower return 0; 33836401Ssklower } 33936401Ssklower ok: 34036401Ssklower IFDEBUG(D_TPINPUT) 34136401Ssklower printf("tp_newsocket returning so 0x%x, sototpcb(so) 0x%x\n", 34236401Ssklower so, sototpcb(so)); 34336401Ssklower ENDDEBUG 34436401Ssklower return so; 34536401Ssklower } 34636401Ssklower 34745900Ssklower #ifndef TPCONS 34836401Ssklower tpcons_output() 34936401Ssklower { 35036401Ssklower return(0); 35136401Ssklower } 35236401Ssklower #endif !CONS 35336401Ssklower 35436401Ssklower /* 35536401Ssklower * NAME: tp_input() 35636401Ssklower * 35736401Ssklower * CALLED FROM: 35836401Ssklower * net layer input routine 35936401Ssklower * 36036401Ssklower * FUNCTION and ARGUMENTS: 36136401Ssklower * Process an incoming TPDU (m), finding the associated tpcb if there 36236401Ssklower * is one. Create the appropriate type of event and call the driver. 36336401Ssklower * (faddr) and (laddr) are the foreign and local addresses. 36436401Ssklower * 36536401Ssklower * When tp_input() is called we KNOW that the ENTIRE TP HEADER 36636401Ssklower * has been m_pullup-ed. 36736401Ssklower * 36836401Ssklower * RETURN VALUE: Nada 36936401Ssklower * 37036401Ssklower * SIDE EFFECTS: 37136401Ssklower * When using COSNS it may affect the state of the net-level pcb 37236401Ssklower * 37336401Ssklower * NOTE: 37436401Ssklower * The initial value of acktime is 2 so that we will never 37536401Ssklower * have a 0 value for tp_peer_acktime. It gets used in the 37636401Ssklower * computation of the retransmission timer value, and so it 37736401Ssklower * mustn't be zero. 37836401Ssklower * 2 seems like a reasonable minimum. 37936401Ssklower */ 38036401Ssklower ProtoHook 38139929Ssklower tp_input(m, faddr, laddr, cons_channel, dgout_routine, ce_bit) 38236401Ssklower register struct mbuf *m; 38336401Ssklower struct sockaddr *faddr, *laddr; /* NSAP addresses */ 38450648Ssklower caddr_t cons_channel; 38536401Ssklower int (*dgout_routine)(); 38639929Ssklower int ce_bit; 38736401Ssklower 38836401Ssklower { 38936401Ssklower register struct tp_pcb *tpcb = (struct tp_pcb *)0; 39044947Ssklower register struct tpdu *hdr; 39136401Ssklower struct socket *so; 39236401Ssklower struct tp_event e; 39342944Ssklower int error = 0; 39436401Ssklower unsigned dutype; 39542944Ssklower u_short dref, sref = 0, acktime = 2, subseq = 0; /*VAX*/ 39651996Ssklower u_char preferred_class = 0, class_to_use = 0, pdusize = 0; 39742944Ssklower u_char opt, dusize = TP_DFL_TPDUSIZE, addlopt = 0, version; 39836401Ssklower #ifdef TP_PERF_MEAS 39938841Ssklower u_char perf_meas; 40036401Ssklower #endif TP_PERF_MEAS 40150648Ssklower u_char fsufxlen = 0, lsufxlen = 0; 40242944Ssklower caddr_t fsufxloc = 0, lsufxloc = 0; 40342944Ssklower int tpdu_len = 0; 40442944Ssklower u_int takes_data = FALSE; 40542944Ssklower u_int fcc_present = FALSE; 40642944Ssklower int errlen = 0; 40736401Ssklower struct tp_conn_param tpp; 40836401Ssklower int tpcons_output(); 40936401Ssklower 41038841Ssklower again: 41144947Ssklower hdr = mtod(m, struct tpdu *); 41236401Ssklower #ifdef TP_PERF_MEAS 41338841Ssklower GET_CUR_TIME( &e.e_time ); perf_meas = 0; 41436401Ssklower #endif TP_PERF_MEAS 41536401Ssklower 41636401Ssklower IFDEBUG(D_TPINPUT) 41736401Ssklower printf("tp_input(0x%x, ... 0x%x)\n", m, cons_channel); 41836401Ssklower ENDDEBUG 41936401Ssklower 42036401Ssklower 42136401Ssklower /* 42236401Ssklower * get the actual tpdu length - necessary for monitoring 42336401Ssklower * and for checksumming 42436401Ssklower * 42536401Ssklower * Also, maybe measure the mbuf chain lengths and sizes. 42636401Ssklower */ 42736401Ssklower 42836401Ssklower { register struct mbuf *n=m; 42936401Ssklower # ifdef ARGO_DEBUG 43036401Ssklower int chain_length = 0; 43136401Ssklower # endif ARGO_DEBUG 43236401Ssklower 43336401Ssklower for(;;) { 43436401Ssklower tpdu_len += n->m_len; 43536401Ssklower IFDEBUG(D_MBUF_MEAS) 43637469Ssklower if( n->m_flags & M_EXT) { 43736401Ssklower IncStat(ts_mb_cluster); 43836401Ssklower } else { 43936401Ssklower IncStat(ts_mb_small); 44036401Ssklower } 44136401Ssklower chain_length ++; 44236401Ssklower ENDDEBUG 44336401Ssklower if (n->m_next == MNULL ) { 44436401Ssklower break; 44536401Ssklower } 44636401Ssklower n = n->m_next; 44736401Ssklower } 44836401Ssklower IFDEBUG(D_MBUF_MEAS) 44936401Ssklower if(chain_length > 16) 45036401Ssklower chain_length = 0; /* zero used for anything > 16 */ 45136401Ssklower tp_stat.ts_mb_len_distr[chain_length] ++; 45236401Ssklower ENDDEBUG 45336401Ssklower } 45436401Ssklower IFTRACE(D_TPINPUT) 45536401Ssklower tptraceTPCB(TPPTtpduin, hdr->tpdu_type, hdr, hdr->tpdu_li+1, tpdu_len, 45636401Ssklower 0); 45736401Ssklower ENDTRACE 45836401Ssklower 45936401Ssklower dref = ntohs((short)hdr->tpdu_dref); 46036401Ssklower sref = ntohs((short)hdr->tpdu_sref); 46136401Ssklower dutype = (int)hdr->tpdu_type; 46236401Ssklower 46336401Ssklower IFDEBUG(D_TPINPUT) 46436401Ssklower printf("input: dutype 0x%x cons_channel 0x%x dref 0x%x\n", dutype, 46536401Ssklower cons_channel, dref); 46636401Ssklower printf("input: dref 0x%x sref 0x%x\n", dref, sref); 46736401Ssklower ENDDEBUG 46836401Ssklower IFTRACE(D_TPINPUT) 46936401Ssklower tptrace(TPPTmisc, "channel dutype dref ", 47036401Ssklower cons_channel, dutype, dref, 0); 47136401Ssklower ENDTRACE 47236401Ssklower 47336401Ssklower 47436401Ssklower #ifdef ARGO_DEBUG 47536401Ssklower if( (dutype < TP_MIN_TPDUTYPE) || (dutype > TP_MAX_TPDUTYPE)) { 47636401Ssklower printf("BAD dutype! 0x%x, channel 0x%x dref 0x%x\n", 47736401Ssklower dutype, cons_channel, dref); 47836401Ssklower dump_buf (m, sizeof( struct mbuf )); 47936401Ssklower 48036401Ssklower IncStat(ts_inv_dutype); 48136401Ssklower goto discard; 48236401Ssklower } 48336401Ssklower #endif ARGO_DEBUG 48436401Ssklower 48536401Ssklower CHECK( (dutype < TP_MIN_TPDUTYPE || dutype > TP_MAX_TPDUTYPE), 48636401Ssklower E_TP_INV_TPDU, ts_inv_dutype, respond, 48736401Ssklower 2 ); 48836401Ssklower /* unfortunately we can't take the address of the tpdu_type field, 48936401Ssklower * since it's a bit field - so we just use the constant offset 2 49036401Ssklower */ 49136401Ssklower 49236401Ssklower /* Now this isn't very neat but since you locate a pcb one way 49336401Ssklower * at the beginning of connection establishment, and by 49436401Ssklower * the dref for each tpdu after that, we have to treat CRs differently 49536401Ssklower */ 49636401Ssklower if ( dutype == CR_TPDU_type ) { 49736401Ssklower u_char alt_classes = 0; 49836401Ssklower 49937469Ssklower preferred_class = 1 << hdr->tpdu_CRclass; 50036401Ssklower opt = hdr->tpdu_CRoptions; 50136401Ssklower 50236401Ssklower WHILE_OPTIONS(P, hdr, 1 ) /* { */ 50336401Ssklower 50436401Ssklower switch( vbptr(P)->tpv_code ) { 50536401Ssklower 50636401Ssklower case TPP_tpdu_size: 50736401Ssklower vb_getval(P, u_char, dusize); 50836401Ssklower IFDEBUG(D_TPINPUT) 50936401Ssklower printf("CR dusize 0x%x\n", dusize); 51036401Ssklower ENDDEBUG 51142944Ssklower /* COS tests: NBS IA (Dec. 1987) Sec. 4.5.2.1 */ 51242944Ssklower if (dusize < TP_MIN_TPDUSIZE || dusize > TP_MAX_TPDUSIZE) 51342944Ssklower dusize = TP_DFL_TPDUSIZE; 51436401Ssklower break; 51551996Ssklower case TPP_ptpdu_size: 51651996Ssklower switch (vbptr(P)->tpv_len) { 51751996Ssklower case 1: pdusize = vbval(P, u_char); break; 51851996Ssklower case 2: pdusize = ntohs(vbval(P, u_short)); break; 51951996Ssklower default: ; 52051996Ssklower IFDEBUG(D_TPINPUT) 52151996Ssklower printf("malformed prefered TPDU option\n"); 52251996Ssklower ENDDEBUG 52351996Ssklower } 52451996Ssklower break; 52536401Ssklower case TPP_addl_opt: 52636401Ssklower vb_getval(P, u_char, addlopt); 52736401Ssklower break; 52836401Ssklower case TPP_calling_sufx: 52936401Ssklower /* could use vb_getval, but we want to save the loc & len 53036401Ssklower * for later use 53136401Ssklower */ 53236401Ssklower fsufxloc = (caddr_t) &vbptr(P)->tpv_val; 53336401Ssklower fsufxlen = vbptr(P)->tpv_len; 53436401Ssklower IFDEBUG(D_TPINPUT) 53536401Ssklower printf("CR fsufx:"); 53636401Ssklower { register int j; 53736401Ssklower for(j=0; j<fsufxlen; j++ ) { 53836401Ssklower printf(" 0x%x. ", *((caddr_t)(fsufxloc+j)) ); 53936401Ssklower } 54036401Ssklower printf("\n"); 54136401Ssklower } 54236401Ssklower ENDDEBUG 54336401Ssklower break; 54436401Ssklower case TPP_called_sufx: 54536401Ssklower /* could use vb_getval, but we want to save the loc & len 54636401Ssklower * for later use 54736401Ssklower */ 54836401Ssklower lsufxloc = (caddr_t) &vbptr(P)->tpv_val; 54936401Ssklower lsufxlen = vbptr(P)->tpv_len; 55036401Ssklower IFDEBUG(D_TPINPUT) 55136401Ssklower printf("CR lsufx:"); 55236401Ssklower { register int j; 55336401Ssklower for(j=0; j<lsufxlen; j++ ) { 55437469Ssklower printf(" 0x%x. ", *((u_char *)(lsufxloc+j)) ); 55536401Ssklower } 55636401Ssklower printf("\n"); 55736401Ssklower } 55836401Ssklower ENDDEBUG 55936401Ssklower break; 56036401Ssklower 56136401Ssklower #ifdef TP_PERF_MEAS 56236401Ssklower case TPP_perf_meas: 56336401Ssklower vb_getval(P, u_char, perf_meas); 56436401Ssklower break; 56536401Ssklower #endif TP_PERF_MEAS 56636401Ssklower 56736401Ssklower case TPP_vers: 56836401Ssklower /* not in class 0; 1 octet; in CR_TPDU only */ 56942944Ssklower /* COS tests says if version wrong, use default version!?XXX */ 57036401Ssklower CHECK( (vbval(P, u_char) != TP_VERSION ), 57142491Ssklower E_TP_INV_PVAL, ts_inv_pval, setversion, 57242944Ssklower (1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) ); 57342491Ssklower setversion: 57442491Ssklower version = vbval(P, u_char); 57536401Ssklower break; 57636401Ssklower case TPP_acktime: 57736401Ssklower vb_getval(P, u_short, acktime); 57836401Ssklower acktime = ntohs(acktime); 57936401Ssklower acktime = acktime/500; /* convert to slowtimo ticks */ 58036401Ssklower if((short)acktime <=0 ) 58136401Ssklower acktime = 2; /* don't allow a bad peer to screw us up */ 58236401Ssklower IFDEBUG(D_TPINPUT) 58336401Ssklower printf("CR acktime 0x%x\n", acktime); 58436401Ssklower ENDDEBUG 58536401Ssklower break; 58636401Ssklower 58736401Ssklower case TPP_alt_class: 58836401Ssklower { 58936401Ssklower u_char *aclass = 0; 59036401Ssklower register int i; 59142944Ssklower static u_char bad_alt_classes[5] = 59242944Ssklower { ~0, ~3, ~5, ~0xf, ~0x1f}; 59336401Ssklower 59442944Ssklower aclass = 59542944Ssklower (u_char *) &(((struct tp_vbp *)P)->tpv_val); 59636401Ssklower for (i = ((struct tp_vbp *)P)->tpv_len; i>0; i--) { 59742944Ssklower alt_classes |= (1<<((*aclass++)>>4)); 59836401Ssklower } 59942944Ssklower CHECK( (bad_alt_classes[hdr->tpdu_CRclass] & alt_classes), 60042944Ssklower E_TP_INV_PVAL, ts_inv_aclass, respond, 60142944Ssklower ((caddr_t)aclass) - (caddr_t)hdr); 60236401Ssklower IFDEBUG(D_TPINPUT) 60336401Ssklower printf("alt_classes 0x%x\n", alt_classes); 60436401Ssklower ENDDEBUG 60536401Ssklower } 60636401Ssklower break; 60736401Ssklower 60836401Ssklower case TPP_security: 60936401Ssklower case TPP_residER: 61036401Ssklower case TPP_priority: 61136401Ssklower case TPP_transdelay: 61236401Ssklower case TPP_throughput: 61336401Ssklower case TPP_addl_info: 61436401Ssklower case TPP_subseq: 61544947Ssklower default: 61636401Ssklower IFDEBUG(D_TPINPUT) 61736401Ssklower printf("param ignored CR_TPDU code= 0x%x\n", 61836401Ssklower vbptr(P)->tpv_code); 61936401Ssklower ENDDEBUG 62036401Ssklower IncStat(ts_param_ignored); 62136401Ssklower break; 62236401Ssklower 62336401Ssklower case TPP_checksum: 62436401Ssklower IFDEBUG(D_TPINPUT) 62536401Ssklower printf("CR before cksum\n"); 62636401Ssklower ENDDEBUG 62736401Ssklower 62836401Ssklower CHECK( iso_check_csum(m, tpdu_len), 62936401Ssklower E_TP_INV_PVAL, ts_bad_csum, discard, 0) 63036401Ssklower 63136401Ssklower IFDEBUG(D_TPINPUT) 63236401Ssklower printf("CR before cksum\n"); 63336401Ssklower ENDDEBUG 63436401Ssklower break; 63536401Ssklower } 63636401Ssklower 63736401Ssklower /* } */ END_WHILE_OPTIONS(P) 63836401Ssklower 63944422Ssklower if (lsufxlen == 0) { 64036401Ssklower /* can't look for a tpcb w/o any called sufx */ 64136401Ssklower error = E_TP_LENGTH_INVAL; 64236401Ssklower IncStat(ts_inv_sufx); 64336401Ssklower goto respond; 64436401Ssklower } else { 64544422Ssklower register struct tp_pcb *t; 64650648Ssklower /* 64750648Ssklower * The intention here is to trap all CR requests 64850648Ssklower * to a given nsap, for constructing transport 64950648Ssklower * service bridges at user level; so these 65050648Ssklower * intercepts should precede the normal listens. 65150648Ssklower * Phrasing the logic in this way also allows for 65250648Ssklower * mop-up listeners, which we don't currently implement. 65350648Ssklower * We also wish to have a single socket be able to 65450648Ssklower * listen over any network service provider, 65550648Ssklower * (cons or clns or ip). 65650648Ssklower */ 65750648Ssklower for (t = tp_listeners; t ; t = t->tp_nextlisten) 65850648Ssklower if ((t->tp_lsuffixlen == 0 || 65950648Ssklower (lsufxlen == t->tp_lsuffixlen && 66050648Ssklower bcmp(lsufxloc, t->tp_lsuffix, lsufxlen) == 0)) && 66150648Ssklower ((t->tp_flags & TPF_GENERAL_ADDR) || 66250648Ssklower (laddr->sa_family == t->tp_domain && 66350648Ssklower (*t->tp_nlproto->nlp_cmpnetaddr) 66450648Ssklower (t->tp_npcb, laddr, TP_LOCAL)))) 66550648Ssklower break; 66636401Ssklower 66744422Ssklower CHECK(t == 0, E_TP_NO_SESSION, ts_inv_sufx, respond, 66836401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 66936401Ssklower /* _tpduf is the fixed part; add 2 to get the dref bits of 67036401Ssklower * the fixed part (can't take the address of a bit field) 67136401Ssklower */ 67244601Ssklower IFDEBUG(D_TPINPUT) 67344601Ssklower printf("checking if dup CR\n"); 67444601Ssklower ENDDEBUG 67544422Ssklower tpcb = t; 67644422Ssklower for (t = tpcb->tp_next; t != tpcb; t = t->tp_next) { 67744422Ssklower if (sref != t->tp_fref) 67844422Ssklower continue; 67944422Ssklower if ((*tpcb->tp_nlproto->nlp_cmpnetaddr)( 68044422Ssklower t->tp_npcb, faddr, TP_FOREIGN)) { 68144422Ssklower IFDEBUG(D_TPINPUT) 68244422Ssklower printf("duplicate CR discarded\n"); 68344422Ssklower ENDDEBUG 68444422Ssklower goto discard; 68544422Ssklower } 68644422Ssklower } 68744422Ssklower IFTRACE(D_TPINPUT) 68844422Ssklower tptrace(TPPTmisc, "tp_input: tpcb *lsufxloc tpstate", 68944422Ssklower tpcb, *lsufxloc, tpcb->tp_state, 0); 69044422Ssklower ENDTRACE 69136401Ssklower } 69236401Ssklower 69336401Ssklower /* 69436401Ssklower * WE HAVE A TPCB 69536401Ssklower * already know that the classes in the CR match at least 69636401Ssklower * one class implemented, but we don't know yet if they 69736401Ssklower * include any classes permitted by this server. 69836401Ssklower */ 69936401Ssklower 70036401Ssklower IFDEBUG(D_TPINPUT) 70136401Ssklower printf("HAVE A TPCB 1: 0x%x\n", tpcb); 70236401Ssklower ENDDEBUG 70336401Ssklower IFDEBUG(D_CONN) 70436401Ssklower printf( 70536401Ssklower "CR: bef CHKS: flags 0x%x class_to_use 0x%x alt 0x%x opt 0x%x tp_class 0x%x\n", 70636401Ssklower tpcb->tp_flags, class_to_use, alt_classes, opt, tpcb->tp_class); 70736401Ssklower ENDDEBUG 70836401Ssklower /* tpcb->tp_class doesn't include any classes not implemented */ 70936401Ssklower class_to_use = (preferred_class & tpcb->tp_class); 71036401Ssklower if( (class_to_use = preferred_class & tpcb->tp_class) == 0 ) 71136401Ssklower class_to_use = alt_classes & tpcb->tp_class; 71236401Ssklower 71336401Ssklower class_to_use = 1 << tp_mask_to_num(class_to_use); 71436401Ssklower 71536401Ssklower { 71636401Ssklower tpp = tpcb->_tp_param; 71736401Ssklower tpp.p_class = class_to_use; 71836401Ssklower tpp.p_tpdusize = dusize; 71951996Ssklower tpp.p_ptpdusize = pdusize; 72036401Ssklower tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT; 72136401Ssklower tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD; 72236401Ssklower tpp.p_use_checksum = (tpp.p_class == TP_CLASS_0)?0: 72336401Ssklower (addlopt & TPAO_NO_CSUM) == 0; 72442491Ssklower tpp.p_version = version; 72536401Ssklower #ifdef notdef 72636401Ssklower tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC; 72736401Ssklower tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD; 72836401Ssklower tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC; 72936401Ssklower #endif notdef 73036401Ssklower 73136401Ssklower CHECK( 73236401Ssklower tp_consistency(tpcb, 0 /* not force or strict */, &tpp) != 0, 73350648Ssklower E_TP_NEGOT_FAILED, ts_negotfailed, clear_parent_tcb, 73436401Ssklower (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 73536401Ssklower /* ^ more or less the location of class */ 73636401Ssklower ) 73736401Ssklower } 73836401Ssklower IFTRACE(D_CONN) 73936401Ssklower tptrace(TPPTmisc, 74036401Ssklower "after 1 consist class_to_use class, out, tpconsout", 74136401Ssklower class_to_use, 74236401Ssklower tpcb->tp_class, dgout_routine, tpcons_output 74336401Ssklower ); 74436401Ssklower ENDTRACE 74536401Ssklower CHECK( 74636401Ssklower ((class_to_use == TP_CLASS_0)&&(dgout_routine != tpcons_output)), 74750648Ssklower E_TP_NEGOT_FAILED, ts_negotfailed, clear_parent_tcb, 74836401Ssklower (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 74936401Ssklower /* ^ more or less the location of class */ 75036401Ssklower ) 75136401Ssklower IFDEBUG(D_CONN) 75236401Ssklower printf("CR: after CRCCCHECKS: tpcb 0x%x, flags 0x%x\n", 75336401Ssklower tpcb, tpcb->tp_flags); 75436401Ssklower ENDDEBUG 75536401Ssklower takes_data = TRUE; 75636401Ssklower e.ATTR(CR_TPDU).e_cdt = hdr->tpdu_CRcdt; 75736401Ssklower e.ev_number = CR_TPDU; 75836401Ssklower 75936401Ssklower so = tpcb->tp_sock; 76036401Ssklower if (so->so_options & SO_ACCEPTCONN) { 76144422Ssklower struct tp_pcb *parent_tpcb = tpcb; 76236401Ssklower /* 76336401Ssklower * Create a socket, tpcb, ll pcb, etc. 76436401Ssklower * for this newborn connection, and fill in all the values. 76536401Ssklower */ 76636401Ssklower IFDEBUG(D_CONN) 76736401Ssklower printf("abt to call tp_newsocket(0x%x, 0x%x, 0x%x, 0x%x)\n", 76836401Ssklower so, laddr, faddr, cons_channel); 76936401Ssklower ENDDEBUG 77036401Ssklower if( (so = 77136401Ssklower tp_newsocket(so, faddr, cons_channel, 77236401Ssklower class_to_use, 77337469Ssklower ((tpcb->tp_netservice == IN_CLNS) ? IN_CLNS : 77437469Ssklower (dgout_routine == tpcons_output)?ISO_CONS:ISO_CLNS)) 77536401Ssklower ) == (struct socket *)0 ) { 77636401Ssklower /* note - even if netservice is IN_CLNS, as far as 77736401Ssklower * the tp entity is concerned, the only differences 77837469Ssklower * are CO vs CL 77936401Ssklower */ 78036401Ssklower IFDEBUG(D_CONN) 78136401Ssklower printf("tp_newsocket returns 0\n"); 78236401Ssklower ENDDEBUG 78336401Ssklower goto discard; 78450648Ssklower clear_parent_tcb: 78550648Ssklower tpcb = 0; 78650648Ssklower goto respond; 78736401Ssklower } 78836401Ssklower tpcb = sototpcb(so); 78944601Ssklower insque(tpcb, parent_tpcb); 79036401Ssklower 79136401Ssklower /* 79237469Ssklower * Stash the addresses in the net level pcb 79336401Ssklower * kind of like a pcbconnect() but don't need 79436401Ssklower * or want all those checks. 79536401Ssklower */ 79650435Ssklower (tpcb->tp_nlproto->nlp_putnetaddr)(tpcb->tp_npcb, faddr, TP_FOREIGN); 79750435Ssklower (tpcb->tp_nlproto->nlp_putnetaddr)(tpcb->tp_npcb, laddr, TP_LOCAL); 79836401Ssklower 79937469Ssklower /* stash the f suffix in the new tpcb */ 80050648Ssklower if (tpcb->tp_fsuffixlen = fsufxlen) { 80150648Ssklower bcopy(fsufxloc, tpcb->tp_fsuffix, fsufxlen); 80250648Ssklower (tpcb->tp_nlproto->nlp_putsufx) 80350648Ssklower (tpcb->tp_npcb, fsufxloc, fsufxlen, TP_FOREIGN); 80450648Ssklower } 80550648Ssklower /* stash the l suffix in the new tpcb */ 80650648Ssklower tpcb->tp_lsuffixlen = lsufxlen; 80750648Ssklower bcopy(lsufxloc, tpcb->tp_lsuffix, lsufxlen); 80837469Ssklower (tpcb->tp_nlproto->nlp_putsufx) 80950435Ssklower (tpcb->tp_npcb, lsufxloc, lsufxlen, TP_LOCAL); 81036401Ssklower #ifdef TP_PERF_MEAS 81136401Ssklower if( tpcb->tp_perf_on = perf_meas ) { /* assignment */ 81236401Ssklower /* ok, let's create an mbuf for stashing the 81336401Ssklower * statistics if one doesn't already exist 81436401Ssklower */ 81536401Ssklower (void) tp_setup_perf(tpcb); 81636401Ssklower } 81736401Ssklower #endif TP_PERF_MEAS 81836401Ssklower tpcb->tp_fref = sref; 81936401Ssklower 82036401Ssklower /* We've already checked for consistency with the options 82136401Ssklower * set in tpp, but we couldn't set them earlier because 82236401Ssklower * we didn't want to change options in the LISTENING tpcb. 82336401Ssklower * Now we set the options in the new socket's tpcb. 82436401Ssklower */ 82536401Ssklower (void) tp_consistency( tpcb, TP_FORCE, &tpp); 82636401Ssklower 82736401Ssklower if(!tpcb->tp_use_checksum) 82836401Ssklower IncStat(ts_csum_off); 82936401Ssklower if(tpcb->tp_xpd_service) 83036401Ssklower IncStat(ts_use_txpd); 83136401Ssklower if(tpcb->tp_xtd_format) 83236401Ssklower IncStat(ts_xtd_fmt); 83336401Ssklower 83436401Ssklower tpcb->tp_peer_acktime = acktime; 83536401Ssklower 83636401Ssklower /* 83736401Ssklower * The following kludge is used to test retransmissions and 83836401Ssklower * timeout during connection establishment. 83936401Ssklower */ 84036401Ssklower IFDEBUG(D_ZDREF) 84136401Ssklower IncStat(ts_zdebug); 84237469Ssklower /*tpcb->tp_fref = 0;*/ 84336401Ssklower ENDDEBUG 84436401Ssklower } 845*53682Ssklower LOCAL_CREDIT(tpcb); 84636401Ssklower IncStat(ts_CR_rcvd); 84739929Ssklower if (!tpcb->tp_cebit_off) { 84839929Ssklower tpcb->tp_win_recv = tp_start_win << 8; 84939929Ssklower tpcb->tp_cong_sample.cs_size = 0; 85039929Ssklower CONG_INIT_SAMPLE(tpcb); 85139929Ssklower CONG_UPDATE_SAMPLE(tpcb, ce_bit); 85239929Ssklower } 85336401Ssklower } else if ( dutype == ER_TPDU_type ) { 85436401Ssklower /* 85536401Ssklower * ER TPDUs have to be recognized separately 85636401Ssklower * because they don't necessarily have a tpcb 85736401Ssklower * with them and we don't want err out looking for such 85836401Ssklower * a beast. 85936401Ssklower * We could put a bunch of little kludges in the 86036401Ssklower * next section of code so it would avoid references to tpcb 86136401Ssklower * if dutype == ER_TPDU_type but we don't want code for ERs to 86236401Ssklower * mess up code for data transfer. 86336401Ssklower */ 86436401Ssklower IncStat(ts_ER_rcvd); 86536401Ssklower e.ev_number = ER_TPDU; 86636401Ssklower e.ATTR(ER_TPDU).e_reason = (u_char)hdr->tpdu_ERreason; 86751007Ssklower CHECK (((int)dref <= 0 || dref >= tp_refinfo.tpr_size || 86850176Ssklower (tpcb = tp_ref[dref].tpr_pcb ) == (struct tp_pcb *) 0 || 86951204Ssklower tpcb->tp_refstate == REF_FREE || 87051204Ssklower tpcb->tp_refstate == REF_FROZEN), 87150176Ssklower E_TP_MISM_REFS, ts_inv_dref, discard, 0) 87250176Ssklower 87336401Ssklower } else { 87436401Ssklower /* tpdu type is CC, XPD, XAK, GR, AK, DR, DC, or DT */ 87536401Ssklower 87636401Ssklower /* In the next 4 checks, 87736401Ssklower * _tpduf is the fixed part; add 2 to get the dref bits of 87836401Ssklower * the fixed part (can't take the address of a bit field) 87936401Ssklower */ 88050648Ssklower #ifdef TPCONS 88150648Ssklower if (cons_channel && dutype == DT_TPDU_type) { 88250648Ssklower struct isopcb *isop = ((struct isopcb *) 88350648Ssklower ((struct pklcd *)cons_channel)->lcd_upnext); 88450648Ssklower if (isop && isop->isop_refcnt == 1 && isop->isop_socket && 88550648Ssklower (tpcb = sototpcb(isop->isop_socket)) && 88650648Ssklower (tpcb->tp_class == TP_CLASS_0/* || == CLASS_1 */)) { 88750648Ssklower IFDEBUG(D_TPINPUT) 88850648Ssklower printf("tpinput_dt: class 0 short circuit\n"); 88950648Ssklower ENDDEBUG 89050648Ssklower dref = tpcb->tp_lref; 89150648Ssklower sref = tpcb->tp_fref; 89251204Ssklower CHECK( (tpcb->tp_refstate == REF_FREE), 89350648Ssklower E_TP_MISM_REFS,ts_inv_dref, nonx_dref, 89450648Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 89550648Ssklower goto tp0_data; 89650648Ssklower } 89736401Ssklower 89850648Ssklower } 89945900Ssklower #endif 90045900Ssklower { 90136401Ssklower 90251007Ssklower CHECK( ((int)dref <= 0 || dref >= tp_refinfo.tpr_size) , 90342944Ssklower E_TP_MISM_REFS,ts_inv_dref, nonx_dref, 90436401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 90536401Ssklower CHECK( ((tpcb = tp_ref[dref].tpr_pcb ) == (struct tp_pcb *) 0 ), 90642944Ssklower E_TP_MISM_REFS,ts_inv_dref, nonx_dref, 90736401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 90851204Ssklower CHECK( (tpcb->tp_refstate == REF_FREE), 90942944Ssklower E_TP_MISM_REFS,ts_inv_dref, nonx_dref, 91036401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 91136401Ssklower } 91236401Ssklower 91336401Ssklower IFDEBUG(D_TPINPUT) 91436401Ssklower printf("HAVE A TPCB 2: 0x%x\n", tpcb); 91536401Ssklower ENDDEBUG 91636401Ssklower 91736401Ssklower /* causes a DR to be sent for CC; ER for all else */ 91851204Ssklower CHECK( (tpcb->tp_refstate == REF_FROZEN), 91936401Ssklower (dutype == CC_TPDU_type?E_TP_NO_SESSION:E_TP_MISM_REFS), 92036401Ssklower ts_inv_dref, respond, 92136401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 92236401Ssklower 92336401Ssklower IFDEBUG(D_TPINPUT) 92436401Ssklower printf("state of dref %d ok, tpcb 0x%x\n", dref,tpcb); 92536401Ssklower ENDDEBUG 92636401Ssklower /* 92736401Ssklower * At this point the state of the dref could be 92836401Ssklower * FROZEN: tpr_pcb == NULL, has ( reference only) timers 92936401Ssklower * for example, DC may arrive after the close() has detached 93036401Ssklower * the tpcb (e.g., if user turned off SO_LISTEN option) 93136401Ssklower * OPENING : a tpcb exists but no timers yet 93236401Ssklower * OPEN : tpcb exists & timers are outstanding 93336401Ssklower */ 93436401Ssklower 93539929Ssklower if (!tpcb->tp_cebit_off) 93639929Ssklower CONG_UPDATE_SAMPLE(tpcb, ce_bit); 93739929Ssklower 93836401Ssklower dusize = tpcb->tp_tpdusize; 93951996Ssklower pdusize = tpcb->tp_ptpdusize; 94036401Ssklower 94136401Ssklower dutype = hdr->tpdu_type << 8; /* for the switch below */ 94236401Ssklower 94336401Ssklower WHILE_OPTIONS(P, hdr, tpcb->tp_xtd_format) /* { */ 94436401Ssklower 94537469Ssklower #define caseof(x,y) case (((x)<<8)+(y)) 94636401Ssklower switch( dutype | vbptr(P)->tpv_code ) { 94736401Ssklower 94836401Ssklower caseof( CC_TPDU_type, TPP_addl_opt ): 94936401Ssklower /* not in class 0; 1 octet */ 95036401Ssklower vb_getval(P, u_char, addlopt); 95136401Ssklower break; 95236401Ssklower caseof( CC_TPDU_type, TPP_tpdu_size ): 95342944Ssklower { 95442944Ssklower u_char odusize = dusize; 95536401Ssklower vb_getval(P, u_char, dusize); 95642944Ssklower CHECK( (dusize < TP_MIN_TPDUSIZE || 95742944Ssklower dusize > TP_MAX_TPDUSIZE || dusize > odusize), 95842944Ssklower E_TP_INV_PVAL, ts_inv_pval, respond, 95942944Ssklower (1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) ) 96036401Ssklower IFDEBUG(D_TPINPUT) 96136401Ssklower printf("CC dusize 0x%x\n", dusize); 96236401Ssklower ENDDEBUG 96342944Ssklower } 96436401Ssklower break; 96551996Ssklower caseof( CC_TPDU_type, TPP_ptpdu_size ): 96651996Ssklower { 96751996Ssklower u_short opdusize = pdusize; 96851996Ssklower switch (vbptr(P)->tpv_len) { 96951996Ssklower case 1: pdusize = vbval(P, u_char); break; 97051996Ssklower case 2: pdusize = ntohs(vbval(P, u_short)); break; 97151996Ssklower default: ; 97251996Ssklower IFDEBUG(D_TPINPUT) 97351996Ssklower printf("malformed prefered TPDU option\n"); 97451996Ssklower ENDDEBUG 97551996Ssklower } 97651996Ssklower CHECK( (pdusize == 0 || 97751996Ssklower (opdusize && (pdusize > opdusize))), 97851996Ssklower E_TP_INV_PVAL, ts_inv_pval, respond, 97951996Ssklower (1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) ) 98051996Ssklower } 98151996Ssklower break; 98236401Ssklower caseof( CC_TPDU_type, TPP_calling_sufx): 98336401Ssklower IFDEBUG(D_TPINPUT) 98436401Ssklower printf("CC calling (local) sufxlen 0x%x\n", lsufxlen); 98536401Ssklower ENDDEBUG 98636401Ssklower lsufxloc = (caddr_t) &vbptr(P)->tpv_val; 98736401Ssklower lsufxlen = vbptr(P)->tpv_len; 98836401Ssklower break; 98936401Ssklower caseof( CC_TPDU_type, TPP_acktime ): 99036401Ssklower /* class 4 only, 2 octets */ 99136401Ssklower vb_getval(P, u_short, acktime); 99244947Ssklower acktime = ntohs(acktime); 99336401Ssklower acktime = acktime/500; /* convert to slowtimo ticks */ 99436401Ssklower if( (short)acktime <=0 ) 99536401Ssklower acktime = 2; 99636401Ssklower break; 99736401Ssklower caseof( CC_TPDU_type, TPP_called_sufx): 99836401Ssklower fsufxloc = (caddr_t) &vbptr(P)->tpv_val; 99936401Ssklower fsufxlen = vbptr(P)->tpv_len; 100036401Ssklower IFDEBUG(D_TPINPUT) 100136401Ssklower printf("CC called (foreign) sufx len %d\n", fsufxlen); 100236401Ssklower ENDDEBUG 100336401Ssklower break; 100436401Ssklower 100536401Ssklower caseof( CC_TPDU_type, TPP_checksum): 100636401Ssklower caseof( DR_TPDU_type, TPP_checksum): 100736401Ssklower caseof( DT_TPDU_type, TPP_checksum): 100836401Ssklower caseof( XPD_TPDU_type, TPP_checksum): 100936401Ssklower if( tpcb->tp_use_checksum ) { 101036401Ssklower CHECK( iso_check_csum(m, tpdu_len), 101136401Ssklower E_TP_INV_PVAL, ts_bad_csum, discard, 0) 101236401Ssklower } 101336401Ssklower break; 101436401Ssklower 101536401Ssklower /* this is different from the above because in the context 101636401Ssklower * of concat/ sep tpdu_len might not be the same as hdr len 101736401Ssklower */ 101836401Ssklower caseof( AK_TPDU_type, TPP_checksum): 101936401Ssklower caseof( XAK_TPDU_type, TPP_checksum): 102036401Ssklower caseof( DC_TPDU_type, TPP_checksum): 102136401Ssklower if( tpcb->tp_use_checksum ) { 102237469Ssklower CHECK( iso_check_csum(m, (int)hdr->tpdu_li + 1), 102336401Ssklower E_TP_INV_PVAL, ts_bad_csum, discard, 0) 102436401Ssklower } 102536401Ssklower break; 102636401Ssklower #ifdef notdef 102736401Ssklower caseof( DR_TPDU_type, TPP_addl_info ): 102836401Ssklower /* ignore - its length and meaning are 102936401Ssklower * user defined and there's no way 103036401Ssklower * to pass this info to the user anyway 103136401Ssklower */ 103236401Ssklower break; 103336401Ssklower #endif notdef 103436401Ssklower 103536401Ssklower caseof( AK_TPDU_type, TPP_subseq ): 103636401Ssklower /* used after reduction of window */ 103736401Ssklower vb_getval(P, u_short, subseq); 103836401Ssklower subseq = ntohs(subseq); 103936401Ssklower IFDEBUG(D_ACKRECV) 104051204Ssklower printf("AK dref 0x%x Subseq 0x%x\n", dref, subseq); 104136401Ssklower ENDDEBUG 104236401Ssklower break; 104336401Ssklower 104436401Ssklower caseof( AK_TPDU_type, TPP_flow_cntl_conf ): 104536401Ssklower { 104636401Ssklower u_int ylwe; 104736401Ssklower u_short ysubseq, ycredit; 104836401Ssklower 104936401Ssklower fcc_present = TRUE; 105036401Ssklower vb_getval(P, u_int, ylwe); 105136401Ssklower vb_getval(P, u_short, ysubseq); 105236401Ssklower vb_getval(P, u_short, ycredit); 105336401Ssklower ylwe = ntohl(ylwe); 105436401Ssklower ysubseq = ntohs(ysubseq); 105536401Ssklower ycredit = ntohs(ycredit); 105636401Ssklower IFDEBUG(D_ACKRECV) 105751204Ssklower printf("%s%x, subseq 0x%x, cdt 0x%x dref 0x%x\n", 105851204Ssklower "AK FCC lwe 0x", ylwe, ysubseq, ycredit, dref); 105936401Ssklower ENDDEBUG 106036401Ssklower } 106136401Ssklower break; 106236401Ssklower 106336401Ssklower default: 106436401Ssklower IFDEBUG(D_TPINPUT) 106536401Ssklower printf("param ignored dutype 0x%x, code 0x%x\n", 106636401Ssklower dutype, vbptr(P)->tpv_code); 106736401Ssklower ENDDEBUG 106836401Ssklower IFTRACE(D_TPINPUT) 106936401Ssklower tptrace(TPPTmisc, "param ignored dutype code ", 107036401Ssklower dutype, vbptr(P)->tpv_code ,0,0); 107136401Ssklower ENDTRACE 107236401Ssklower IncStat(ts_param_ignored); 107336401Ssklower break; 107436401Ssklower #undef caseof 107536401Ssklower } 107636401Ssklower /* } */ END_WHILE_OPTIONS(P) 107736401Ssklower 107836401Ssklower /* NOTE: the variable dutype has been shifted left! */ 107936401Ssklower 108036401Ssklower switch( hdr->tpdu_type ) { 108136401Ssklower case CC_TPDU_type: 108236401Ssklower /* If CC comes back with an unacceptable class 108336401Ssklower * respond with a DR or ER 108436401Ssklower */ 108536401Ssklower 108636401Ssklower opt = hdr->tpdu_CCoptions; /* 1 byte */ 108736401Ssklower 108836401Ssklower { 108936401Ssklower tpp = tpcb->_tp_param; 109036401Ssklower tpp.p_class = (1<<hdr->tpdu_CCclass); 109136401Ssklower tpp.p_tpdusize = dusize; 109251996Ssklower tpp.p_ptpdusize = pdusize; 109336401Ssklower tpp.p_dont_change_params = 0; 109436401Ssklower tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT; 109536401Ssklower tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD; 109636401Ssklower tpp.p_use_checksum = (addlopt & TPAO_NO_CSUM) == 0; 109736401Ssklower #ifdef notdef 109836401Ssklower tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC; 109936401Ssklower tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD; 110036401Ssklower tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC; 110136401Ssklower #endif notdef 110236401Ssklower 110336401Ssklower CHECK( 110436401Ssklower tp_consistency(tpcb, TP_FORCE, &tpp) != 0, 110536401Ssklower E_TP_NEGOT_FAILED, ts_negotfailed, respond, 110636401Ssklower (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 110736401Ssklower /* ^ more or less the location of class */ 110836401Ssklower ) 110936401Ssklower IFTRACE(D_CONN) 111036401Ssklower tptrace(TPPTmisc, 111136401Ssklower "after 1 consist class, out, tpconsout", 111236401Ssklower tpcb->tp_class, dgout_routine, tpcons_output, 0 111336401Ssklower ); 111436401Ssklower ENDTRACE 111536401Ssklower CHECK( 111636401Ssklower ((class_to_use == TP_CLASS_0)&& 111736401Ssklower (dgout_routine != tpcons_output)), 111836401Ssklower E_TP_NEGOT_FAILED, ts_negotfailed, respond, 111936401Ssklower (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 112036401Ssklower /* ^ more or less the location of class */ 112136401Ssklower ) 112245900Ssklower #ifdef TPCONS 112345900Ssklower if (tpcb->tp_netservice == ISO_CONS && 112445900Ssklower class_to_use == TP_CLASS_0) { 112545900Ssklower struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb; 112645900Ssklower struct pklcd *lcp = (struct pklcd *)isop->isop_chan; 112745900Ssklower lcp->lcd_flags &= ~X25_DG_CIRCUIT; 112845900Ssklower } 112945900Ssklower #endif 113036401Ssklower } 113136401Ssklower if( ! tpcb->tp_use_checksum) 113236401Ssklower IncStat(ts_csum_off); 113336401Ssklower if(tpcb->tp_xpd_service) 113436401Ssklower IncStat(ts_use_txpd); 113536401Ssklower if(tpcb->tp_xtd_format) 113636401Ssklower IncStat(ts_xtd_fmt); 113736401Ssklower 113836401Ssklower IFTRACE(D_CONN) 113936401Ssklower tptrace(TPPTmisc, "after CC class flags dusize CCclass", 114036401Ssklower tpcb->tp_class, tpcb->tp_flags, tpcb->tp_tpdusize, 114136401Ssklower hdr->tpdu_CCclass); 114236401Ssklower ENDTRACE 114336401Ssklower 114436401Ssklower /* if called or calling suffices appeared on the CC, 114536401Ssklower * they'd better jive with what's in the pcb 114636401Ssklower */ 114736401Ssklower if( fsufxlen ) { 114836401Ssklower CHECK( ((tpcb->tp_fsuffixlen != fsufxlen) || 114936401Ssklower bcmp(fsufxloc, tpcb->tp_fsuffix, fsufxlen)), 115036401Ssklower E_TP_INV_PVAL,ts_inv_sufx, respond, 115136401Ssklower (1+fsufxloc - (caddr_t)hdr)) 115236401Ssklower } 115336401Ssklower if( lsufxlen ) { 115436401Ssklower CHECK( ((tpcb->tp_lsuffixlen != lsufxlen) || 115536401Ssklower bcmp(lsufxloc, tpcb->tp_lsuffix, lsufxlen)), 115636401Ssklower E_TP_INV_PVAL,ts_inv_sufx, respond, 115736401Ssklower (1+lsufxloc - (caddr_t)hdr)) 115836401Ssklower } 115936401Ssklower 116036401Ssklower e.ATTR(CC_TPDU).e_sref = sref; 116136401Ssklower e.ATTR(CC_TPDU).e_cdt = hdr->tpdu_CCcdt; 116236401Ssklower takes_data = TRUE; 116336401Ssklower e.ev_number = CC_TPDU; 116436401Ssklower IncStat(ts_CC_rcvd); 116536401Ssklower break; 116636401Ssklower 116736401Ssklower case DC_TPDU_type: 116836401Ssklower if (sref != tpcb->tp_fref) 116936401Ssklower printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n", 117036401Ssklower sref, tpcb->tp_fref); 117136401Ssklower 117236401Ssklower CHECK( (sref != tpcb->tp_fref), 117342944Ssklower E_TP_MISM_REFS, ts_inv_sufx, discard, 117436401Ssklower (1 + (caddr_t)&hdr->tpdu_DCsref - (caddr_t)hdr)) 117542944Ssklower 117636401Ssklower e.ev_number = DC_TPDU; 117736401Ssklower IncStat(ts_DC_rcvd); 117836401Ssklower break; 117936401Ssklower 118036401Ssklower case DR_TPDU_type: 118136401Ssklower IFTRACE(D_TPINPUT) 118236401Ssklower tptrace(TPPTmisc, "DR recvd", hdr->tpdu_DRreason, 0, 0, 0); 118336401Ssklower ENDTRACE 118442944Ssklower if (sref != tpcb->tp_fref) { 118536401Ssklower printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n", 118636401Ssklower sref, tpcb->tp_fref); 118742944Ssklower } 118836401Ssklower 118942944Ssklower CHECK( (sref != 0 && sref != tpcb->tp_fref && 119042944Ssklower tpcb->tp_state != TP_CRSENT), 119142944Ssklower (TP_ERROR_SNDC | E_TP_MISM_REFS),ts_inv_sufx, respond, 119236401Ssklower (1 + (caddr_t)&hdr->tpdu_DRsref - (caddr_t)hdr)) 119336401Ssklower 119436401Ssklower e.ATTR(DR_TPDU).e_reason = hdr->tpdu_DRreason; 119536401Ssklower e.ATTR(DR_TPDU).e_sref = (u_short)sref; 119636401Ssklower takes_data = TRUE; 119736401Ssklower e.ev_number = DR_TPDU; 119836401Ssklower IncStat(ts_DR_rcvd); 119936401Ssklower break; 120036401Ssklower 120136401Ssklower case ER_TPDU_type: 120236401Ssklower IFTRACE(D_TPINPUT) 120336401Ssklower tptrace(TPPTmisc, "ER recvd", hdr->tpdu_ERreason,0,0,0); 120436401Ssklower ENDTRACE 120536401Ssklower e.ev_number = ER_TPDU; 120636401Ssklower e.ATTR(ER_TPDU).e_reason = hdr->tpdu_ERreason; 120736401Ssklower IncStat(ts_ER_rcvd); 120836401Ssklower break; 120936401Ssklower 121036401Ssklower case AK_TPDU_type: 121136401Ssklower 121236401Ssklower e.ATTR(AK_TPDU).e_subseq = subseq; 121336401Ssklower e.ATTR(AK_TPDU).e_fcc_present = fcc_present; 121436401Ssklower 121536401Ssklower if (tpcb->tp_xtd_format) { 121636401Ssklower #ifdef BYTE_ORDER 121736401Ssklower union seq_type seqeotX; 121836401Ssklower 121936401Ssklower seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 122036401Ssklower e.ATTR(AK_TPDU).e_seq = seqeotX.s_seq; 122136401Ssklower e.ATTR(AK_TPDU).e_cdt = ntohs(hdr->tpdu_AKcdtX); 122236401Ssklower #else 122336401Ssklower e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdtX; 122436401Ssklower e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseqX; 122536401Ssklower #endif BYTE_ORDER 122636401Ssklower } else { 122736401Ssklower e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdt; 122836401Ssklower e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseq; 122936401Ssklower } 123036401Ssklower IFTRACE(D_TPINPUT) 123136401Ssklower tptrace(TPPTmisc, "AK recvd seq cdt subseq fcc_pres", 123236401Ssklower e.ATTR(AK_TPDU).e_seq, e.ATTR(AK_TPDU).e_cdt, 123336401Ssklower subseq, fcc_present); 123436401Ssklower ENDTRACE 123536401Ssklower 123636401Ssklower e.ev_number = AK_TPDU; 123736401Ssklower IncStat(ts_AK_rcvd); 123836401Ssklower IncPStat(tpcb, tps_AK_rcvd); 123936401Ssklower break; 124036401Ssklower 124136401Ssklower case XAK_TPDU_type: 124236401Ssklower if (tpcb->tp_xtd_format) { 124336401Ssklower #ifdef BYTE_ORDER 124436401Ssklower union seq_type seqeotX; 124536401Ssklower 124636401Ssklower seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 124736401Ssklower e.ATTR(XAK_TPDU).e_seq = seqeotX.s_seq; 124836401Ssklower #else 124936401Ssklower e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseqX; 125036401Ssklower #endif BYTE_ORDER 125136401Ssklower } else { 125236401Ssklower e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseq; 125336401Ssklower } 125436401Ssklower e.ev_number = XAK_TPDU; 125536401Ssklower IncStat(ts_XAK_rcvd); 125636401Ssklower IncPStat(tpcb, tps_XAK_rcvd); 125736401Ssklower break; 125836401Ssklower 125936401Ssklower case XPD_TPDU_type: 126036401Ssklower if (tpcb->tp_xtd_format) { 126136401Ssklower #ifdef BYTE_ORDER 126236401Ssklower union seq_type seqeotX; 126336401Ssklower 126436401Ssklower seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 126536401Ssklower e.ATTR(XPD_TPDU).e_seq = seqeotX.s_seq; 126636401Ssklower #else 126736401Ssklower e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseqX; 126836401Ssklower #endif BYTE_ORDER 126936401Ssklower } else { 127036401Ssklower e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseq; 127136401Ssklower } 127236401Ssklower takes_data = TRUE; 127336401Ssklower e.ev_number = XPD_TPDU; 127436401Ssklower IncStat(ts_XPD_rcvd); 127536401Ssklower IncPStat(tpcb, tps_XPD_rcvd); 127636401Ssklower break; 127736401Ssklower 127836401Ssklower case DT_TPDU_type: 127936401Ssklower { /* the y option will cause occasional packets to be dropped. 128036401Ssklower * A little crude but it works. 128136401Ssklower */ 128236401Ssklower 128336401Ssklower IFDEBUG(D_DROP) 128436401Ssklower if(time.tv_usec & 0x4 && hdr->tpdu_DTseq & 0x1) { 128536401Ssklower IncStat(ts_ydebug); 128636401Ssklower goto discard; 128736401Ssklower } 128836401Ssklower ENDDEBUG 128936401Ssklower } 129036401Ssklower if (tpcb->tp_class == TP_CLASS_0) { 129150648Ssklower tp0_data: 129236401Ssklower e.ATTR(DT_TPDU).e_seq = 0; /* actually don't care */ 129336401Ssklower e.ATTR(DT_TPDU).e_eot = (((struct tp0du *)hdr)->tp0du_eot); 129436401Ssklower } else if (tpcb->tp_xtd_format) { 129536401Ssklower #ifdef BYTE_ORDER 129636401Ssklower union seq_type seqeotX; 129736401Ssklower 129836401Ssklower seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 129936401Ssklower e.ATTR(DT_TPDU).e_seq = seqeotX.s_seq; 130036401Ssklower e.ATTR(DT_TPDU).e_eot = seqeotX.s_eot; 130136401Ssklower #else 130236401Ssklower e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseqX; 130336401Ssklower e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeotX; 130436401Ssklower #endif BYTE_ORDER 130536401Ssklower } else { 130636401Ssklower e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseq; 130736401Ssklower e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeot; 130836401Ssklower } 130936401Ssklower if(e.ATTR(DT_TPDU).e_eot) 131036401Ssklower IncStat(ts_eot_input); 131136401Ssklower takes_data = TRUE; 131236401Ssklower e.ev_number = DT_TPDU; 131336401Ssklower IncStat(ts_DT_rcvd); 131436401Ssklower IncPStat(tpcb, tps_DT_rcvd); 131536401Ssklower break; 131636401Ssklower 131736401Ssklower case GR_TPDU_type: 131836401Ssklower tp_indicate(T_DISCONNECT, tpcb, ECONNABORTED); 131936401Ssklower /* drop through */ 132036401Ssklower default: 132136401Ssklower /* this should NEVER happen because there is a 132236401Ssklower * check for dutype well above here 132336401Ssklower */ 132436401Ssklower error = E_TP_INV_TPDU; /* causes an ER */ 132536401Ssklower IFDEBUG(D_TPINPUT) 132636401Ssklower printf("INVALID dutype 0x%x\n", hdr->tpdu_type); 132736401Ssklower ENDDEBUG 132836401Ssklower IncStat(ts_inv_dutype); 132936401Ssklower goto respond; 133036401Ssklower } 133136401Ssklower } 133236401Ssklower /* peel off the tp header; 133336401Ssklower * remember that the du_li doesn't count itself. 133436401Ssklower * This may leave us w/ an empty mbuf at the front of a chain. 133536401Ssklower * We can't just throw away the empty mbuf because hdr still points 133636401Ssklower * into the mbuf's data area and we're still using hdr (the tpdu header) 133736401Ssklower */ 133836401Ssklower m->m_len -= ((int)hdr->tpdu_li + 1); 133937469Ssklower m->m_data += ((int)hdr->tpdu_li + 1); 134036401Ssklower 134137469Ssklower if (takes_data) { 134237469Ssklower int max = tpdu_info[ hdr->tpdu_type ] [TP_MAX_DATA_INDEX]; 134337469Ssklower int datalen = tpdu_len - hdr->tpdu_li - 1, mbtype = MT_DATA; 134448749Ssklower struct { 134548749Ssklower struct tp_disc_reason dr; 134648749Ssklower struct cmsghdr x_hdr; 134748749Ssklower } x; 134848749Ssklower #define c_hdr x.x_hdr 134948749Ssklower register struct mbuf *n; 135036401Ssklower 135137469Ssklower CHECK( (max && datalen > max), E_TP_LENGTH_INVAL, 135237469Ssklower ts_inv_length, respond, (max + hdr->tpdu_li + 1) ); 135336401Ssklower switch( hdr->tpdu_type ) { 135437469Ssklower 135536401Ssklower case CR_TPDU_type: 135637469Ssklower c_hdr.cmsg_type = TPOPT_CONN_DATA; 135737469Ssklower goto make_control_msg; 135837469Ssklower 135936401Ssklower case CC_TPDU_type: 136037469Ssklower c_hdr.cmsg_type = TPOPT_CFRM_DATA; 136137469Ssklower goto make_control_msg; 136237469Ssklower 136336401Ssklower case DR_TPDU_type: 136448749Ssklower x.dr.dr_hdr.cmsg_len = sizeof(x) - sizeof(c_hdr); 136548749Ssklower x.dr.dr_hdr.cmsg_type = TPOPT_DISC_REASON; 136648749Ssklower x.dr.dr_hdr.cmsg_level = SOL_TRANSPORT; 136748749Ssklower x.dr.dr_reason = hdr->tpdu_DRreason; 136837469Ssklower c_hdr.cmsg_type = TPOPT_DISC_DATA; 136937469Ssklower make_control_msg: 137048749Ssklower datalen += sizeof(c_hdr); 137148749Ssklower c_hdr.cmsg_len = datalen; 137237469Ssklower c_hdr.cmsg_level = SOL_TRANSPORT; 137337469Ssklower mbtype = MT_CONTROL; 137443334Ssklower MGET(n, M_DONTWAIT, MT_DATA); 137548749Ssklower if (n == 0) 137648749Ssklower {m_freem(m); m = 0; datalen = 0; goto invoke; } 137748749Ssklower if (hdr->tpdu_type == DR_TPDU_type) { 137848749Ssklower datalen += sizeof(x) - sizeof(c_hdr); 137948749Ssklower bcopy((caddr_t)&x, mtod(n, caddr_t), n->m_len = sizeof(x)); 138048749Ssklower } else 138148749Ssklower bcopy((caddr_t)&c_hdr, mtod(n, caddr_t), 138248749Ssklower n->m_len = sizeof(c_hdr)); 138348749Ssklower n->m_next = m; 138448749Ssklower m = n; 138537469Ssklower /* FALLTHROUGH */ 138637469Ssklower 138736401Ssklower case XPD_TPDU_type: 138837469Ssklower if (mbtype != MT_CONTROL) 138937469Ssklower mbtype = MT_OOBDATA; 139037469Ssklower m->m_flags |= M_EOR; 139137469Ssklower /* FALLTHROUGH */ 139237469Ssklower 139336401Ssklower case DT_TPDU_type: 139437469Ssklower for (n = m; n; n = n->m_next) { 139537469Ssklower MCHTYPE(n, mbtype); 139637469Ssklower } 139743334Ssklower invoke: 139837469Ssklower e.ATTR(DT_TPDU).e_datalen = datalen; 139936401Ssklower e.ATTR(DT_TPDU).e_data = m; 140036401Ssklower break; 140136401Ssklower 140236401Ssklower default: 140336401Ssklower printf( 140436401Ssklower "ERROR in tp_input! hdr->tpdu_type 0x%x takes_data 0x%x m 0x%x\n", 140536401Ssklower hdr->tpdu_type, takes_data, m); 140636401Ssklower break; 140736401Ssklower } 140836401Ssklower /* prevent m_freem() after tp_driver() from throwing it all away */ 140936401Ssklower m = MNULL; 141036401Ssklower } 141136401Ssklower 141236401Ssklower IncStat(ts_tpdu_rcvd); 141336401Ssklower 141436401Ssklower IFDEBUG(D_TPINPUT) 141536401Ssklower printf( "tp_input: before driver, state 0x%x event 0x%x m 0x%x", 141636401Ssklower tpcb->tp_state, e.ev_number, m ); 141736401Ssklower printf(" e.e_data 0x%x\n", e.ATTR(DT_TPDU).e_data); 141836401Ssklower printf("takes_data 0x%x m_len 0x%x, tpdu_len 0x%x\n", 141936401Ssklower takes_data, (m==MNULL)?0:m->m_len, tpdu_len); 142036401Ssklower ENDDEBUG 142136401Ssklower 142236401Ssklower error = tp_driver(tpcb, &e); 142336401Ssklower 142436401Ssklower ASSERT(tpcb != (struct tp_pcb *)0); 142536401Ssklower ASSERT(tpcb->tp_sock != (struct socket *)0); 142636401Ssklower if( tpcb->tp_sock->so_error == 0 ) 142736401Ssklower tpcb->tp_sock->so_error = error; 142836401Ssklower 142936401Ssklower /* Kludge to keep the state tables under control (adding 143036401Ssklower * data on connect & disconnect & freeing the mbuf containing 143136401Ssklower * the data would have exploded the tables and made a big mess ). 143236401Ssklower */ 143336401Ssklower switch(e.ev_number) { 143436401Ssklower case CC_TPDU: 143536401Ssklower case DR_TPDU: 143636401Ssklower case CR_TPDU: 143736401Ssklower m = e.ATTR(CC_TPDU).e_data; /* same field for all three dutypes */ 143836401Ssklower IFDEBUG(D_TPINPUT) 143936401Ssklower printf("after driver, restoring m to 0x%x, takes_data 0x%x\n", 144036401Ssklower m, takes_data); 144136401Ssklower ENDDEBUG 144236401Ssklower break; 144336401Ssklower default: 144436401Ssklower break; 144536401Ssklower } 144636401Ssklower /* Concatenated sequences are terminated by any tpdu that 144736401Ssklower * carries data: CR, CC, DT, XPD, DR. 144836401Ssklower * All other tpdu types may be concatenated: AK, XAK, DC, ER. 144936401Ssklower */ 145036401Ssklower 145136401Ssklower separate: 145236401Ssklower if ( takes_data == 0 ) { 145336401Ssklower ASSERT( m != MNULL ); 145436401Ssklower /* 145536401Ssklower * we already peeled off the prev. tp header so 145636401Ssklower * we can just pull up some more and repeat 145736401Ssklower */ 145836401Ssklower 145937469Ssklower if( m = tp_inputprep(m) ) { 146036401Ssklower IFDEBUG(D_TPINPUT) 146136401Ssklower hdr = mtod(m, struct tpdu *); 146236401Ssklower printf("tp_input @ separate: hdr 0x%x size %d m 0x%x\n", 146336401Ssklower hdr, (int) hdr->tpdu_li + 1, m); 146436401Ssklower dump_mbuf(m, "tp_input after driver, at separate"); 146536401Ssklower ENDDEBUG 146636401Ssklower 146736401Ssklower IncStat(ts_concat_rcvd); 146836401Ssklower goto again; 146936401Ssklower } 147036401Ssklower } 147136401Ssklower if ( m != MNULL ) { 147236401Ssklower IFDEBUG(D_TPINPUT) 147336401Ssklower printf("tp_input : m_freem(0x%x)\n", m); 147436401Ssklower ENDDEBUG 147536401Ssklower m_freem(m); 147636401Ssklower IFDEBUG(D_TPINPUT) 147736401Ssklower printf("tp_input : after m_freem 0x%x\n", m); 147836401Ssklower ENDDEBUG 147936401Ssklower } 148036401Ssklower return (ProtoHook) tpcb; 148136401Ssklower 148236401Ssklower discard: 148336401Ssklower /* class 4: drop the tpdu */ 148436401Ssklower /* class 2,0: Should drop the net connection, if you can figure out 148536401Ssklower * to which connection it applies 148636401Ssklower */ 148736401Ssklower IFDEBUG(D_TPINPUT) 148836401Ssklower printf("tp_input DISCARD\n"); 148936401Ssklower ENDDEBUG 149036401Ssklower IFTRACE(D_TPINPUT) 149136401Ssklower tptrace(TPPTmisc, "tp_input DISCARD m", m,0,0,0); 149236401Ssklower ENDTRACE 149336401Ssklower m_freem(m); 149436401Ssklower IncStat(ts_recv_drop); 149536401Ssklower return (ProtoHook)0; 149636401Ssklower 149742944Ssklower nonx_dref: 149842944Ssklower switch (dutype) { 149942944Ssklower default: 150042944Ssklower goto discard; 150142944Ssklower case CC_TPDU_type: 150242944Ssklower /* error = E_TP_MISM_REFS; */ 150342944Ssklower break; 150442944Ssklower case DR_TPDU_type: 150542944Ssklower error |= TP_ERROR_SNDC; 150642944Ssklower } 150736401Ssklower respond: 150843334Ssklower IFDEBUG(D_TPINPUT) 150942944Ssklower printf("RESPOND: error 0x%x, errlen 0x%x\n", error, errlen); 151036401Ssklower ENDDEBUG 151136401Ssklower IFTRACE(D_TPINPUT) 151242944Ssklower tptrace(TPPTmisc, "tp_input RESPOND m error sref", m, error, sref, 0); 151336401Ssklower ENDTRACE 151442944Ssklower if (sref == 0) 151536401Ssklower goto discard; 151637469Ssklower (void) tp_error_emit(error, (u_long)sref, (struct sockaddr_iso *)faddr, 151742944Ssklower (struct sockaddr_iso *)laddr, m, errlen, tpcb, 151850648Ssklower cons_channel, dgout_routine); 151936401Ssklower IFDEBUG(D_ERROR_EMIT) 152036401Ssklower printf("tp_input after error_emit\n"); 152136401Ssklower ENDDEBUG 152236401Ssklower 152336401Ssklower #ifdef lint 152436401Ssklower printf("",sref,opt); 152536401Ssklower #endif lint 152636401Ssklower IncStat(ts_recv_drop); 152736401Ssklower return (ProtoHook)0; 152836401Ssklower } 152936401Ssklower 153036401Ssklower 153136401Ssklower /* 153236401Ssklower * NAME: tp_headersize() 153336401Ssklower * 153436401Ssklower * CALLED FROM: 153536401Ssklower * tp_emit() and tp_sbsend() 153636401Ssklower * TP needs to know the header size so it can figure out how 153736401Ssklower * much data to put in each tpdu. 153836401Ssklower * 153936401Ssklower * FUNCTION, ARGUMENTS, and RETURN VALUE: 154036401Ssklower * For a given connection, represented by (tpcb), and 154136401Ssklower * tpdu type (dutype), return the size of a tp header. 154236401Ssklower * 154336401Ssklower * RETURNS: the expected size of the heade in bytesr 154436401Ssklower * 154536401Ssklower * SIDE EFFECTS: 154636401Ssklower * 154736401Ssklower * NOTES: It would be nice if it got the network header size as well. 154836401Ssklower */ 154936401Ssklower int 155036401Ssklower tp_headersize(dutype, tpcb) 155136401Ssklower int dutype; 155236401Ssklower struct tp_pcb *tpcb; 155336401Ssklower { 155436401Ssklower register int size = 0; 155536401Ssklower 155636401Ssklower IFTRACE(D_CONN) 155736401Ssklower tptrace(TPPTmisc, "tp_headersize dutype class xtd_format", 155836401Ssklower dutype, tpcb->tp_class, tpcb->tp_xtd_format, 0); 155936401Ssklower ENDTRACE 156036401Ssklower if( !( (tpcb->tp_class == TP_CLASS_0) || 156136401Ssklower (tpcb->tp_class == TP_CLASS_4) || 156236401Ssklower (dutype == DR_TPDU_type) || 156336401Ssklower (dutype == CR_TPDU_type) )) { 156436401Ssklower printf("tp_headersize:dutype 0x%x, class 0x%x", 156536401Ssklower dutype, tpcb->tp_class); 156636401Ssklower /* TODO: identify this and GET RID OF IT */ 156736401Ssklower } 156836401Ssklower ASSERT( (tpcb->tp_class == TP_CLASS_0) || 156936401Ssklower (tpcb->tp_class == TP_CLASS_4) || 157036401Ssklower (dutype == DR_TPDU_type) || 157136401Ssklower (dutype == CR_TPDU_type) ); 157236401Ssklower 157336401Ssklower if( tpcb->tp_class == TP_CLASS_0 ) { 157436401Ssklower size = tpdu_info[ dutype ] [TP_LEN_CLASS_0_INDEX]; 157536401Ssklower } else { 157636401Ssklower size = tpdu_info[ dutype ] [tpcb->tp_xtd_format]; 157736401Ssklower } 157836401Ssklower return size; 157936401Ssklower /* caller must get network level header size separately */ 158036401Ssklower } 1581