149268Sbostic /*- 249268Sbostic * Copyright (c) 1991 The Regents of the University of California. 349268Sbostic * All rights reserved. 449268Sbostic * 549268Sbostic * %sccs.include.redist.c% 649268Sbostic * 7*51007Ssklower * @(#)tp_input.c 7.22 (Berkeley) 09/05/91 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); 12637469Ssklower ovbcopy(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); 28337469Ssklower soreserve(so, (u_long)tpcb->tp_winsize, (u_long)tpcb->tp_winsize); 28436401Ssklower 28537469Ssklower if( /* old */ tpcb->tp_ucddata) { 28636401Ssklower /* 28737469Ssklower * These data are the connect- , confirm- or disconnect- data. 28836401Ssklower */ 28936401Ssklower struct mbuf *conndata; 29036401Ssklower 29137469Ssklower conndata = m_copy(tpcb->tp_ucddata, 0, (int)M_COPYALL); 29236401Ssklower IFDEBUG(D_CONN) 29336401Ssklower dump_mbuf(conndata, "conndata after mcopy"); 29436401Ssklower ENDDEBUG 29537469Ssklower newtpcb->tp_ucddata = conndata; 29636401Ssklower } 29736401Ssklower 29836401Ssklower tpcb = newtpcb; 29936401Ssklower tpcb->tp_state = TP_LISTENING; 30036401Ssklower tpcb->tp_class = class_to_use; 30136401Ssklower tpcb->tp_netservice = netservice; 30236401Ssklower 30336401Ssklower 30436401Ssklower ASSERT( fname != 0 ) ; /* just checking */ 30536401Ssklower if ( fname ) { 30636401Ssklower /* 30736401Ssklower * tp_route_to takes its address argument in the form of an mbuf. 30836401Ssklower */ 30936401Ssklower struct mbuf *m; 31036401Ssklower int err; 31136401Ssklower 31236401Ssklower MGET(m, M_DONTWAIT, MT_SONAME); /* mbuf type used is confusing */ 31336401Ssklower if (m) { 31436401Ssklower /* 31536401Ssklower * this seems a bit grotesque, but tp_route_to expects 31636401Ssklower * an mbuf * instead of simply a sockaddr; it calls the ll 31736401Ssklower * pcb_connect, which expects the name/addr in an mbuf as well. 31836401Ssklower * sigh. 31936401Ssklower */ 32037469Ssklower bcopy((caddr_t)fname, mtod(m, caddr_t), fname->sa_len); 32137469Ssklower m->m_len = fname->sa_len; 32236401Ssklower 32336401Ssklower /* grot : have to say the kernel can override params in 32436401Ssklower * the passive open case 32536401Ssklower */ 32636401Ssklower tpcb->tp_dont_change_params = 0; 32736401Ssklower err = tp_route_to( m, tpcb, cons_channel); 32836401Ssklower m_free(m); 32936401Ssklower 33036401Ssklower if (!err) 33136401Ssklower goto ok; 33236401Ssklower } 33336401Ssklower IFDEBUG(D_CONN) 33436401Ssklower printf("tp_route_to FAILED! detaching tpcb 0x%x, so 0x%x\n", 33536401Ssklower tpcb, so); 33636401Ssklower ENDDEBUG 33736401Ssklower (void) tp_detach(tpcb); 33836401Ssklower return 0; 33936401Ssklower } 34036401Ssklower ok: 34136401Ssklower IFDEBUG(D_TPINPUT) 34236401Ssklower printf("tp_newsocket returning so 0x%x, sototpcb(so) 0x%x\n", 34336401Ssklower so, sototpcb(so)); 34436401Ssklower ENDDEBUG 34536401Ssklower return so; 34636401Ssklower } 34736401Ssklower 34845900Ssklower #ifndef TPCONS 34936401Ssklower tpcons_output() 35036401Ssklower { 35136401Ssklower return(0); 35236401Ssklower } 35336401Ssklower #endif !CONS 35436401Ssklower 35536401Ssklower /* 35636401Ssklower * NAME: tp_input() 35736401Ssklower * 35836401Ssklower * CALLED FROM: 35936401Ssklower * net layer input routine 36036401Ssklower * 36136401Ssklower * FUNCTION and ARGUMENTS: 36236401Ssklower * Process an incoming TPDU (m), finding the associated tpcb if there 36336401Ssklower * is one. Create the appropriate type of event and call the driver. 36436401Ssklower * (faddr) and (laddr) are the foreign and local addresses. 36536401Ssklower * 36636401Ssklower * When tp_input() is called we KNOW that the ENTIRE TP HEADER 36736401Ssklower * has been m_pullup-ed. 36836401Ssklower * 36936401Ssklower * RETURN VALUE: Nada 37036401Ssklower * 37136401Ssklower * SIDE EFFECTS: 37236401Ssklower * When using COSNS it may affect the state of the net-level pcb 37336401Ssklower * 37436401Ssklower * NOTE: 37536401Ssklower * The initial value of acktime is 2 so that we will never 37636401Ssklower * have a 0 value for tp_peer_acktime. It gets used in the 37736401Ssklower * computation of the retransmission timer value, and so it 37836401Ssklower * mustn't be zero. 37936401Ssklower * 2 seems like a reasonable minimum. 38036401Ssklower */ 38136401Ssklower ProtoHook 38239929Ssklower tp_input(m, faddr, laddr, cons_channel, dgout_routine, ce_bit) 38336401Ssklower register struct mbuf *m; 38436401Ssklower struct sockaddr *faddr, *laddr; /* NSAP addresses */ 38550648Ssklower caddr_t cons_channel; 38636401Ssklower int (*dgout_routine)(); 38739929Ssklower int ce_bit; 38836401Ssklower 38936401Ssklower { 39036401Ssklower register struct tp_pcb *tpcb = (struct tp_pcb *)0; 39144947Ssklower register struct tpdu *hdr; 39236401Ssklower struct socket *so; 39336401Ssklower struct tp_event e; 39442944Ssklower int error = 0; 39536401Ssklower unsigned dutype; 39642944Ssklower u_short dref, sref = 0, acktime = 2, subseq = 0; /*VAX*/ 39742944Ssklower u_char preferred_class = 0, class_to_use = 0; 39842944Ssklower u_char opt, dusize = TP_DFL_TPDUSIZE, addlopt = 0, version; 39936401Ssklower #ifdef TP_PERF_MEAS 40038841Ssklower u_char perf_meas; 40136401Ssklower #endif TP_PERF_MEAS 40250648Ssklower u_char fsufxlen = 0, lsufxlen = 0; 40342944Ssklower caddr_t fsufxloc = 0, lsufxloc = 0; 40442944Ssklower int tpdu_len = 0; 40542944Ssklower u_int takes_data = FALSE; 40642944Ssklower u_int fcc_present = FALSE; 40742944Ssklower int errlen = 0; 40836401Ssklower struct tp_conn_param tpp; 40936401Ssklower int tpcons_output(); 41036401Ssklower 41138841Ssklower again: 41244947Ssklower hdr = mtod(m, struct tpdu *); 41336401Ssklower #ifdef TP_PERF_MEAS 41438841Ssklower GET_CUR_TIME( &e.e_time ); perf_meas = 0; 41536401Ssklower #endif TP_PERF_MEAS 41636401Ssklower 41736401Ssklower IFDEBUG(D_TPINPUT) 41836401Ssklower printf("tp_input(0x%x, ... 0x%x)\n", m, cons_channel); 41936401Ssklower ENDDEBUG 42036401Ssklower 42136401Ssklower 42236401Ssklower /* 42336401Ssklower * get the actual tpdu length - necessary for monitoring 42436401Ssklower * and for checksumming 42536401Ssklower * 42636401Ssklower * Also, maybe measure the mbuf chain lengths and sizes. 42736401Ssklower */ 42836401Ssklower 42936401Ssklower { register struct mbuf *n=m; 43036401Ssklower # ifdef ARGO_DEBUG 43136401Ssklower int chain_length = 0; 43236401Ssklower # endif ARGO_DEBUG 43336401Ssklower 43436401Ssklower for(;;) { 43536401Ssklower tpdu_len += n->m_len; 43636401Ssklower IFDEBUG(D_MBUF_MEAS) 43737469Ssklower if( n->m_flags & M_EXT) { 43836401Ssklower IncStat(ts_mb_cluster); 43936401Ssklower } else { 44036401Ssklower IncStat(ts_mb_small); 44136401Ssklower } 44236401Ssklower chain_length ++; 44336401Ssklower ENDDEBUG 44436401Ssklower if (n->m_next == MNULL ) { 44536401Ssklower break; 44636401Ssklower } 44736401Ssklower n = n->m_next; 44836401Ssklower } 44936401Ssklower IFDEBUG(D_MBUF_MEAS) 45036401Ssklower if(chain_length > 16) 45136401Ssklower chain_length = 0; /* zero used for anything > 16 */ 45236401Ssklower tp_stat.ts_mb_len_distr[chain_length] ++; 45336401Ssklower ENDDEBUG 45436401Ssklower } 45536401Ssklower IFTRACE(D_TPINPUT) 45636401Ssklower tptraceTPCB(TPPTtpduin, hdr->tpdu_type, hdr, hdr->tpdu_li+1, tpdu_len, 45736401Ssklower 0); 45836401Ssklower ENDTRACE 45936401Ssklower 46036401Ssklower dref = ntohs((short)hdr->tpdu_dref); 46136401Ssklower sref = ntohs((short)hdr->tpdu_sref); 46236401Ssklower dutype = (int)hdr->tpdu_type; 46336401Ssklower 46436401Ssklower IFDEBUG(D_TPINPUT) 46536401Ssklower printf("input: dutype 0x%x cons_channel 0x%x dref 0x%x\n", dutype, 46636401Ssklower cons_channel, dref); 46736401Ssklower printf("input: dref 0x%x sref 0x%x\n", dref, sref); 46836401Ssklower ENDDEBUG 46936401Ssklower IFTRACE(D_TPINPUT) 47036401Ssklower tptrace(TPPTmisc, "channel dutype dref ", 47136401Ssklower cons_channel, dutype, dref, 0); 47236401Ssklower ENDTRACE 47336401Ssklower 47436401Ssklower 47536401Ssklower #ifdef ARGO_DEBUG 47636401Ssklower if( (dutype < TP_MIN_TPDUTYPE) || (dutype > TP_MAX_TPDUTYPE)) { 47736401Ssklower printf("BAD dutype! 0x%x, channel 0x%x dref 0x%x\n", 47836401Ssklower dutype, cons_channel, dref); 47936401Ssklower dump_buf (m, sizeof( struct mbuf )); 48036401Ssklower 48136401Ssklower IncStat(ts_inv_dutype); 48236401Ssklower goto discard; 48336401Ssklower } 48436401Ssklower #endif ARGO_DEBUG 48536401Ssklower 48636401Ssklower CHECK( (dutype < TP_MIN_TPDUTYPE || dutype > TP_MAX_TPDUTYPE), 48736401Ssklower E_TP_INV_TPDU, ts_inv_dutype, respond, 48836401Ssklower 2 ); 48936401Ssklower /* unfortunately we can't take the address of the tpdu_type field, 49036401Ssklower * since it's a bit field - so we just use the constant offset 2 49136401Ssklower */ 49236401Ssklower 49336401Ssklower /* Now this isn't very neat but since you locate a pcb one way 49436401Ssklower * at the beginning of connection establishment, and by 49536401Ssklower * the dref for each tpdu after that, we have to treat CRs differently 49636401Ssklower */ 49736401Ssklower if ( dutype == CR_TPDU_type ) { 49836401Ssklower u_char alt_classes = 0; 49936401Ssklower 50037469Ssklower preferred_class = 1 << hdr->tpdu_CRclass; 50136401Ssklower opt = hdr->tpdu_CRoptions; 50236401Ssklower 50336401Ssklower WHILE_OPTIONS(P, hdr, 1 ) /* { */ 50436401Ssklower 50536401Ssklower switch( vbptr(P)->tpv_code ) { 50636401Ssklower 50736401Ssklower case TPP_tpdu_size: 50836401Ssklower vb_getval(P, u_char, dusize); 50936401Ssklower IFDEBUG(D_TPINPUT) 51036401Ssklower printf("CR dusize 0x%x\n", dusize); 51136401Ssklower ENDDEBUG 51242944Ssklower /* COS tests: NBS IA (Dec. 1987) Sec. 4.5.2.1 */ 51342944Ssklower if (dusize < TP_MIN_TPDUSIZE || dusize > TP_MAX_TPDUSIZE) 51442944Ssklower dusize = TP_DFL_TPDUSIZE; 51536401Ssklower break; 51636401Ssklower case TPP_addl_opt: 51736401Ssklower vb_getval(P, u_char, addlopt); 51836401Ssklower break; 51936401Ssklower case TPP_calling_sufx: 52036401Ssklower /* could use vb_getval, but we want to save the loc & len 52136401Ssklower * for later use 52236401Ssklower */ 52336401Ssklower fsufxloc = (caddr_t) &vbptr(P)->tpv_val; 52436401Ssklower fsufxlen = vbptr(P)->tpv_len; 52536401Ssklower IFDEBUG(D_TPINPUT) 52636401Ssklower printf("CR fsufx:"); 52736401Ssklower { register int j; 52836401Ssklower for(j=0; j<fsufxlen; j++ ) { 52936401Ssklower printf(" 0x%x. ", *((caddr_t)(fsufxloc+j)) ); 53036401Ssklower } 53136401Ssklower printf("\n"); 53236401Ssklower } 53336401Ssklower ENDDEBUG 53436401Ssklower break; 53536401Ssklower case TPP_called_sufx: 53636401Ssklower /* could use vb_getval, but we want to save the loc & len 53736401Ssklower * for later use 53836401Ssklower */ 53936401Ssklower lsufxloc = (caddr_t) &vbptr(P)->tpv_val; 54036401Ssklower lsufxlen = vbptr(P)->tpv_len; 54136401Ssklower IFDEBUG(D_TPINPUT) 54236401Ssklower printf("CR lsufx:"); 54336401Ssklower { register int j; 54436401Ssklower for(j=0; j<lsufxlen; j++ ) { 54537469Ssklower printf(" 0x%x. ", *((u_char *)(lsufxloc+j)) ); 54636401Ssklower } 54736401Ssklower printf("\n"); 54836401Ssklower } 54936401Ssklower ENDDEBUG 55036401Ssklower break; 55136401Ssklower 55236401Ssklower #ifdef TP_PERF_MEAS 55336401Ssklower case TPP_perf_meas: 55436401Ssklower vb_getval(P, u_char, perf_meas); 55536401Ssklower break; 55636401Ssklower #endif TP_PERF_MEAS 55736401Ssklower 55836401Ssklower case TPP_vers: 55936401Ssklower /* not in class 0; 1 octet; in CR_TPDU only */ 56042944Ssklower /* COS tests says if version wrong, use default version!?XXX */ 56136401Ssklower CHECK( (vbval(P, u_char) != TP_VERSION ), 56242491Ssklower E_TP_INV_PVAL, ts_inv_pval, setversion, 56342944Ssklower (1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) ); 56442491Ssklower setversion: 56542491Ssklower version = vbval(P, u_char); 56636401Ssklower break; 56736401Ssklower case TPP_acktime: 56836401Ssklower vb_getval(P, u_short, acktime); 56936401Ssklower acktime = ntohs(acktime); 57036401Ssklower acktime = acktime/500; /* convert to slowtimo ticks */ 57136401Ssklower if((short)acktime <=0 ) 57236401Ssklower acktime = 2; /* don't allow a bad peer to screw us up */ 57336401Ssklower IFDEBUG(D_TPINPUT) 57436401Ssklower printf("CR acktime 0x%x\n", acktime); 57536401Ssklower ENDDEBUG 57636401Ssklower break; 57736401Ssklower 57836401Ssklower case TPP_alt_class: 57936401Ssklower { 58036401Ssklower u_char *aclass = 0; 58136401Ssklower register int i; 58242944Ssklower static u_char bad_alt_classes[5] = 58342944Ssklower { ~0, ~3, ~5, ~0xf, ~0x1f}; 58436401Ssklower 58542944Ssklower aclass = 58642944Ssklower (u_char *) &(((struct tp_vbp *)P)->tpv_val); 58736401Ssklower for (i = ((struct tp_vbp *)P)->tpv_len; i>0; i--) { 58842944Ssklower alt_classes |= (1<<((*aclass++)>>4)); 58936401Ssklower } 59042944Ssklower CHECK( (bad_alt_classes[hdr->tpdu_CRclass] & alt_classes), 59142944Ssklower E_TP_INV_PVAL, ts_inv_aclass, respond, 59242944Ssklower ((caddr_t)aclass) - (caddr_t)hdr); 59336401Ssklower IFDEBUG(D_TPINPUT) 59436401Ssklower printf("alt_classes 0x%x\n", alt_classes); 59536401Ssklower ENDDEBUG 59636401Ssklower } 59736401Ssklower break; 59836401Ssklower 59936401Ssklower case TPP_security: 60036401Ssklower case TPP_residER: 60136401Ssklower case TPP_priority: 60236401Ssklower case TPP_transdelay: 60336401Ssklower case TPP_throughput: 60436401Ssklower case TPP_addl_info: 60536401Ssklower case TPP_subseq: 60644947Ssklower default: 60736401Ssklower IFDEBUG(D_TPINPUT) 60836401Ssklower printf("param ignored CR_TPDU code= 0x%x\n", 60936401Ssklower vbptr(P)->tpv_code); 61036401Ssklower ENDDEBUG 61136401Ssklower IncStat(ts_param_ignored); 61236401Ssklower break; 61336401Ssklower 61436401Ssklower case TPP_checksum: 61536401Ssklower IFDEBUG(D_TPINPUT) 61636401Ssklower printf("CR before cksum\n"); 61736401Ssklower ENDDEBUG 61836401Ssklower 61936401Ssklower CHECK( iso_check_csum(m, tpdu_len), 62036401Ssklower E_TP_INV_PVAL, ts_bad_csum, discard, 0) 62136401Ssklower 62236401Ssklower IFDEBUG(D_TPINPUT) 62336401Ssklower printf("CR before cksum\n"); 62436401Ssklower ENDDEBUG 62536401Ssklower break; 62636401Ssklower } 62736401Ssklower 62836401Ssklower /* } */ END_WHILE_OPTIONS(P) 62936401Ssklower 63044422Ssklower if (lsufxlen == 0) { 63136401Ssklower /* can't look for a tpcb w/o any called sufx */ 63236401Ssklower error = E_TP_LENGTH_INVAL; 63336401Ssklower IncStat(ts_inv_sufx); 63436401Ssklower goto respond; 63536401Ssklower } else { 63644422Ssklower register struct tp_pcb *t; 63750648Ssklower /* 63850648Ssklower * The intention here is to trap all CR requests 63950648Ssklower * to a given nsap, for constructing transport 64050648Ssklower * service bridges at user level; so these 64150648Ssklower * intercepts should precede the normal listens. 64250648Ssklower * Phrasing the logic in this way also allows for 64350648Ssklower * mop-up listeners, which we don't currently implement. 64450648Ssklower * We also wish to have a single socket be able to 64550648Ssklower * listen over any network service provider, 64650648Ssklower * (cons or clns or ip). 64750648Ssklower */ 64850648Ssklower for (t = tp_listeners; t ; t = t->tp_nextlisten) 64950648Ssklower if ((t->tp_lsuffixlen == 0 || 65050648Ssklower (lsufxlen == t->tp_lsuffixlen && 65150648Ssklower bcmp(lsufxloc, t->tp_lsuffix, lsufxlen) == 0)) && 65250648Ssklower ((t->tp_flags & TPF_GENERAL_ADDR) || 65350648Ssklower (laddr->sa_family == t->tp_domain && 65450648Ssklower (*t->tp_nlproto->nlp_cmpnetaddr) 65550648Ssklower (t->tp_npcb, laddr, TP_LOCAL)))) 65650648Ssklower break; 65736401Ssklower 65844422Ssklower CHECK(t == 0, E_TP_NO_SESSION, ts_inv_sufx, respond, 65936401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 66036401Ssklower /* _tpduf is the fixed part; add 2 to get the dref bits of 66136401Ssklower * the fixed part (can't take the address of a bit field) 66236401Ssklower */ 66344601Ssklower IFDEBUG(D_TPINPUT) 66444601Ssklower printf("checking if dup CR\n"); 66544601Ssklower ENDDEBUG 66644422Ssklower tpcb = t; 66744422Ssklower for (t = tpcb->tp_next; t != tpcb; t = t->tp_next) { 66844422Ssklower if (sref != t->tp_fref) 66944422Ssklower continue; 67044422Ssklower if ((*tpcb->tp_nlproto->nlp_cmpnetaddr)( 67144422Ssklower t->tp_npcb, faddr, TP_FOREIGN)) { 67244422Ssklower IFDEBUG(D_TPINPUT) 67344422Ssklower printf("duplicate CR discarded\n"); 67444422Ssklower ENDDEBUG 67544422Ssklower goto discard; 67644422Ssklower } 67744422Ssklower } 67844422Ssklower IFTRACE(D_TPINPUT) 67944422Ssklower tptrace(TPPTmisc, "tp_input: tpcb *lsufxloc tpstate", 68044422Ssklower tpcb, *lsufxloc, tpcb->tp_state, 0); 68144422Ssklower ENDTRACE 68236401Ssklower } 68336401Ssklower 68436401Ssklower /* 68536401Ssklower * WE HAVE A TPCB 68636401Ssklower * already know that the classes in the CR match at least 68736401Ssklower * one class implemented, but we don't know yet if they 68836401Ssklower * include any classes permitted by this server. 68936401Ssklower */ 69036401Ssklower 69136401Ssklower IFDEBUG(D_TPINPUT) 69236401Ssklower printf("HAVE A TPCB 1: 0x%x\n", tpcb); 69336401Ssklower ENDDEBUG 69436401Ssklower IFDEBUG(D_CONN) 69536401Ssklower printf( 69636401Ssklower "CR: bef CHKS: flags 0x%x class_to_use 0x%x alt 0x%x opt 0x%x tp_class 0x%x\n", 69736401Ssklower tpcb->tp_flags, class_to_use, alt_classes, opt, tpcb->tp_class); 69836401Ssklower ENDDEBUG 69936401Ssklower /* tpcb->tp_class doesn't include any classes not implemented */ 70036401Ssklower class_to_use = (preferred_class & tpcb->tp_class); 70136401Ssklower if( (class_to_use = preferred_class & tpcb->tp_class) == 0 ) 70236401Ssklower class_to_use = alt_classes & tpcb->tp_class; 70336401Ssklower 70436401Ssklower class_to_use = 1 << tp_mask_to_num(class_to_use); 70536401Ssklower 70636401Ssklower { 70736401Ssklower tpp = tpcb->_tp_param; 70836401Ssklower tpp.p_class = class_to_use; 70936401Ssklower tpp.p_tpdusize = dusize; 71036401Ssklower tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT; 71136401Ssklower tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD; 71236401Ssklower tpp.p_use_checksum = (tpp.p_class == TP_CLASS_0)?0: 71336401Ssklower (addlopt & TPAO_NO_CSUM) == 0; 71442491Ssklower tpp.p_version = version; 71536401Ssklower #ifdef notdef 71636401Ssklower tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC; 71736401Ssklower tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD; 71836401Ssklower tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC; 71936401Ssklower #endif notdef 72036401Ssklower 72136401Ssklower CHECK( 72236401Ssklower tp_consistency(tpcb, 0 /* not force or strict */, &tpp) != 0, 72350648Ssklower E_TP_NEGOT_FAILED, ts_negotfailed, clear_parent_tcb, 72436401Ssklower (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 72536401Ssklower /* ^ more or less the location of class */ 72636401Ssklower ) 72736401Ssklower } 72836401Ssklower IFTRACE(D_CONN) 72936401Ssklower tptrace(TPPTmisc, 73036401Ssklower "after 1 consist class_to_use class, out, tpconsout", 73136401Ssklower class_to_use, 73236401Ssklower tpcb->tp_class, dgout_routine, tpcons_output 73336401Ssklower ); 73436401Ssklower ENDTRACE 73536401Ssklower CHECK( 73636401Ssklower ((class_to_use == TP_CLASS_0)&&(dgout_routine != tpcons_output)), 73750648Ssklower E_TP_NEGOT_FAILED, ts_negotfailed, clear_parent_tcb, 73836401Ssklower (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 73936401Ssklower /* ^ more or less the location of class */ 74036401Ssklower ) 74136401Ssklower IFDEBUG(D_CONN) 74236401Ssklower printf("CR: after CRCCCHECKS: tpcb 0x%x, flags 0x%x\n", 74336401Ssklower tpcb, tpcb->tp_flags); 74436401Ssklower ENDDEBUG 74536401Ssklower takes_data = TRUE; 74636401Ssklower e.ATTR(CR_TPDU).e_cdt = hdr->tpdu_CRcdt; 74736401Ssklower e.ev_number = CR_TPDU; 74836401Ssklower 74936401Ssklower so = tpcb->tp_sock; 75036401Ssklower if (so->so_options & SO_ACCEPTCONN) { 75144422Ssklower struct tp_pcb *parent_tpcb = tpcb; 75236401Ssklower /* 75336401Ssklower * Create a socket, tpcb, ll pcb, etc. 75436401Ssklower * for this newborn connection, and fill in all the values. 75536401Ssklower */ 75636401Ssklower IFDEBUG(D_CONN) 75736401Ssklower printf("abt to call tp_newsocket(0x%x, 0x%x, 0x%x, 0x%x)\n", 75836401Ssklower so, laddr, faddr, cons_channel); 75936401Ssklower ENDDEBUG 76036401Ssklower if( (so = 76136401Ssklower tp_newsocket(so, faddr, cons_channel, 76236401Ssklower class_to_use, 76337469Ssklower ((tpcb->tp_netservice == IN_CLNS) ? IN_CLNS : 76437469Ssklower (dgout_routine == tpcons_output)?ISO_CONS:ISO_CLNS)) 76536401Ssklower ) == (struct socket *)0 ) { 76636401Ssklower /* note - even if netservice is IN_CLNS, as far as 76736401Ssklower * the tp entity is concerned, the only differences 76837469Ssklower * are CO vs CL 76936401Ssklower */ 77036401Ssklower IFDEBUG(D_CONN) 77136401Ssklower printf("tp_newsocket returns 0\n"); 77236401Ssklower ENDDEBUG 77336401Ssklower goto discard; 77450648Ssklower clear_parent_tcb: 77550648Ssklower tpcb = 0; 77650648Ssklower goto respond; 77736401Ssklower } 77836401Ssklower tpcb = sototpcb(so); 77944601Ssklower insque(tpcb, parent_tpcb); 78036401Ssklower 78136401Ssklower /* 78237469Ssklower * Stash the addresses in the net level pcb 78336401Ssklower * kind of like a pcbconnect() but don't need 78436401Ssklower * or want all those checks. 78536401Ssklower */ 78650435Ssklower (tpcb->tp_nlproto->nlp_putnetaddr)(tpcb->tp_npcb, faddr, TP_FOREIGN); 78750435Ssklower (tpcb->tp_nlproto->nlp_putnetaddr)(tpcb->tp_npcb, laddr, TP_LOCAL); 78836401Ssklower 78937469Ssklower /* stash the f suffix in the new tpcb */ 79050648Ssklower if (tpcb->tp_fsuffixlen = fsufxlen) { 79150648Ssklower bcopy(fsufxloc, tpcb->tp_fsuffix, fsufxlen); 79250648Ssklower (tpcb->tp_nlproto->nlp_putsufx) 79350648Ssklower (tpcb->tp_npcb, fsufxloc, fsufxlen, TP_FOREIGN); 79450648Ssklower } 79550648Ssklower /* stash the l suffix in the new tpcb */ 79650648Ssklower tpcb->tp_lsuffixlen = lsufxlen; 79750648Ssklower bcopy(lsufxloc, tpcb->tp_lsuffix, lsufxlen); 79837469Ssklower (tpcb->tp_nlproto->nlp_putsufx) 79950435Ssklower (tpcb->tp_npcb, lsufxloc, lsufxlen, TP_LOCAL); 80036401Ssklower #ifdef TP_PERF_MEAS 80136401Ssklower if( tpcb->tp_perf_on = perf_meas ) { /* assignment */ 80236401Ssklower /* ok, let's create an mbuf for stashing the 80336401Ssklower * statistics if one doesn't already exist 80436401Ssklower */ 80536401Ssklower (void) tp_setup_perf(tpcb); 80636401Ssklower } 80736401Ssklower #endif TP_PERF_MEAS 80836401Ssklower tpcb->tp_fref = sref; 80936401Ssklower 81036401Ssklower /* We've already checked for consistency with the options 81136401Ssklower * set in tpp, but we couldn't set them earlier because 81236401Ssklower * we didn't want to change options in the LISTENING tpcb. 81336401Ssklower * Now we set the options in the new socket's tpcb. 81436401Ssklower */ 81536401Ssklower (void) tp_consistency( tpcb, TP_FORCE, &tpp); 81636401Ssklower 81736401Ssklower if(!tpcb->tp_use_checksum) 81836401Ssklower IncStat(ts_csum_off); 81936401Ssklower if(tpcb->tp_xpd_service) 82036401Ssklower IncStat(ts_use_txpd); 82136401Ssklower if(tpcb->tp_xtd_format) 82236401Ssklower IncStat(ts_xtd_fmt); 82336401Ssklower 82436401Ssklower /* 82536401Ssklower * Get the maximum transmission unit from the lower layer(s) 82636401Ssklower * so we can negotiate a reasonable max TPDU size. 82736401Ssklower */ 82850435Ssklower (tpcb->tp_nlproto->nlp_mtu)(so, tpcb->tp_npcb, 82936401Ssklower &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0); 83036401Ssklower tpcb->tp_peer_acktime = acktime; 83136401Ssklower 83236401Ssklower /* 83336401Ssklower * The following kludge is used to test retransmissions and 83436401Ssklower * timeout during connection establishment. 83536401Ssklower */ 83636401Ssklower IFDEBUG(D_ZDREF) 83736401Ssklower IncStat(ts_zdebug); 83837469Ssklower /*tpcb->tp_fref = 0;*/ 83936401Ssklower ENDDEBUG 84036401Ssklower } 84136401Ssklower IncStat(ts_CR_rcvd); 84239929Ssklower if (!tpcb->tp_cebit_off) { 84339929Ssklower tpcb->tp_win_recv = tp_start_win << 8; 84439929Ssklower tpcb->tp_cong_sample.cs_size = 0; 84539929Ssklower LOCAL_CREDIT(tpcb); 84639929Ssklower CONG_INIT_SAMPLE(tpcb); 84739929Ssklower CONG_UPDATE_SAMPLE(tpcb, ce_bit); 84839929Ssklower } 84939929Ssklower tpcb->tp_ackrcvd = 0; 85036401Ssklower } else if ( dutype == ER_TPDU_type ) { 85136401Ssklower /* 85236401Ssklower * ER TPDUs have to be recognized separately 85336401Ssklower * because they don't necessarily have a tpcb 85436401Ssklower * with them and we don't want err out looking for such 85536401Ssklower * a beast. 85636401Ssklower * We could put a bunch of little kludges in the 85736401Ssklower * next section of code so it would avoid references to tpcb 85836401Ssklower * if dutype == ER_TPDU_type but we don't want code for ERs to 85936401Ssklower * mess up code for data transfer. 86036401Ssklower */ 86136401Ssklower IncStat(ts_ER_rcvd); 86236401Ssklower e.ev_number = ER_TPDU; 86336401Ssklower e.ATTR(ER_TPDU).e_reason = (u_char)hdr->tpdu_ERreason; 864*51007Ssklower CHECK (((int)dref <= 0 || dref >= tp_refinfo.tpr_size || 86550176Ssklower (tpcb = tp_ref[dref].tpr_pcb ) == (struct tp_pcb *) 0 || 86650176Ssklower tpcb->tp_refp->tpr_state == REF_FREE || 86750176Ssklower tpcb->tp_refp->tpr_state == REF_FROZEN), 86850176Ssklower E_TP_MISM_REFS, ts_inv_dref, discard, 0) 86950176Ssklower 87036401Ssklower } else { 87136401Ssklower /* tpdu type is CC, XPD, XAK, GR, AK, DR, DC, or DT */ 87236401Ssklower 87336401Ssklower /* In the next 4 checks, 87436401Ssklower * _tpduf is the fixed part; add 2 to get the dref bits of 87536401Ssklower * the fixed part (can't take the address of a bit field) 87636401Ssklower */ 87750648Ssklower #ifdef TPCONS 87850648Ssklower if (cons_channel && dutype == DT_TPDU_type) { 87950648Ssklower struct isopcb *isop = ((struct isopcb *) 88050648Ssklower ((struct pklcd *)cons_channel)->lcd_upnext); 88150648Ssklower if (isop && isop->isop_refcnt == 1 && isop->isop_socket && 88250648Ssklower (tpcb = sototpcb(isop->isop_socket)) && 88350648Ssklower (tpcb->tp_class == TP_CLASS_0/* || == CLASS_1 */)) { 88450648Ssklower IFDEBUG(D_TPINPUT) 88550648Ssklower printf("tpinput_dt: class 0 short circuit\n"); 88650648Ssklower ENDDEBUG 88750648Ssklower dref = tpcb->tp_lref; 88850648Ssklower sref = tpcb->tp_fref; 88950648Ssklower CHECK( (tpcb->tp_refp->tpr_state == REF_FREE), 89050648Ssklower E_TP_MISM_REFS,ts_inv_dref, nonx_dref, 89150648Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 89250648Ssklower goto tp0_data; 89350648Ssklower } 89436401Ssklower 89550648Ssklower } 89645900Ssklower #endif 89745900Ssklower { 89836401Ssklower 899*51007Ssklower CHECK( ((int)dref <= 0 || dref >= tp_refinfo.tpr_size) , 90042944Ssklower E_TP_MISM_REFS,ts_inv_dref, nonx_dref, 90136401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 90236401Ssklower CHECK( ((tpcb = tp_ref[dref].tpr_pcb ) == (struct tp_pcb *) 0 ), 90342944Ssklower E_TP_MISM_REFS,ts_inv_dref, nonx_dref, 90436401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 90536401Ssklower CHECK( (tpcb->tp_refp->tpr_state == REF_FREE), 90642944Ssklower E_TP_MISM_REFS,ts_inv_dref, nonx_dref, 90736401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 90836401Ssklower } 90936401Ssklower 91036401Ssklower IFDEBUG(D_TPINPUT) 91136401Ssklower printf("HAVE A TPCB 2: 0x%x\n", tpcb); 91236401Ssklower ENDDEBUG 91336401Ssklower 91436401Ssklower /* causes a DR to be sent for CC; ER for all else */ 91536401Ssklower CHECK( (tpcb->tp_refp->tpr_state == REF_FROZEN), 91636401Ssklower (dutype == CC_TPDU_type?E_TP_NO_SESSION:E_TP_MISM_REFS), 91736401Ssklower ts_inv_dref, respond, 91836401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 91936401Ssklower 92036401Ssklower IFDEBUG(D_TPINPUT) 92136401Ssklower printf("state of dref %d ok, tpcb 0x%x\n", dref,tpcb); 92236401Ssklower ENDDEBUG 92336401Ssklower /* 92436401Ssklower * At this point the state of the dref could be 92536401Ssklower * FROZEN: tpr_pcb == NULL, has ( reference only) timers 92636401Ssklower * for example, DC may arrive after the close() has detached 92736401Ssklower * the tpcb (e.g., if user turned off SO_LISTEN option) 92836401Ssklower * OPENING : a tpcb exists but no timers yet 92936401Ssklower * OPEN : tpcb exists & timers are outstanding 93036401Ssklower */ 93136401Ssklower 93239929Ssklower if (!tpcb->tp_cebit_off) 93339929Ssklower CONG_UPDATE_SAMPLE(tpcb, ce_bit); 93439929Ssklower 93536401Ssklower dusize = tpcb->tp_tpdusize; 93636401Ssklower 93736401Ssklower dutype = hdr->tpdu_type << 8; /* for the switch below */ 93836401Ssklower 93936401Ssklower WHILE_OPTIONS(P, hdr, tpcb->tp_xtd_format) /* { */ 94036401Ssklower 94137469Ssklower #define caseof(x,y) case (((x)<<8)+(y)) 94236401Ssklower switch( dutype | vbptr(P)->tpv_code ) { 94336401Ssklower 94436401Ssklower caseof( CC_TPDU_type, TPP_addl_opt ): 94536401Ssklower /* not in class 0; 1 octet */ 94636401Ssklower vb_getval(P, u_char, addlopt); 94736401Ssklower break; 94836401Ssklower caseof( CC_TPDU_type, TPP_tpdu_size ): 94942944Ssklower { 95042944Ssklower u_char odusize = dusize; 95136401Ssklower vb_getval(P, u_char, dusize); 95242944Ssklower CHECK( (dusize < TP_MIN_TPDUSIZE || 95342944Ssklower dusize > TP_MAX_TPDUSIZE || dusize > odusize), 95442944Ssklower E_TP_INV_PVAL, ts_inv_pval, respond, 95542944Ssklower (1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) ) 95636401Ssklower IFDEBUG(D_TPINPUT) 95736401Ssklower printf("CC dusize 0x%x\n", dusize); 95836401Ssklower ENDDEBUG 95942944Ssklower } 96036401Ssklower break; 96136401Ssklower caseof( CC_TPDU_type, TPP_calling_sufx): 96236401Ssklower IFDEBUG(D_TPINPUT) 96336401Ssklower printf("CC calling (local) sufxlen 0x%x\n", lsufxlen); 96436401Ssklower ENDDEBUG 96536401Ssklower lsufxloc = (caddr_t) &vbptr(P)->tpv_val; 96636401Ssklower lsufxlen = vbptr(P)->tpv_len; 96736401Ssklower break; 96836401Ssklower caseof( CC_TPDU_type, TPP_acktime ): 96936401Ssklower /* class 4 only, 2 octets */ 97036401Ssklower vb_getval(P, u_short, acktime); 97144947Ssklower acktime = ntohs(acktime); 97236401Ssklower acktime = acktime/500; /* convert to slowtimo ticks */ 97336401Ssklower if( (short)acktime <=0 ) 97436401Ssklower acktime = 2; 97536401Ssklower break; 97636401Ssklower caseof( CC_TPDU_type, TPP_called_sufx): 97736401Ssklower fsufxloc = (caddr_t) &vbptr(P)->tpv_val; 97836401Ssklower fsufxlen = vbptr(P)->tpv_len; 97936401Ssklower IFDEBUG(D_TPINPUT) 98036401Ssklower printf("CC called (foreign) sufx len %d\n", fsufxlen); 98136401Ssklower ENDDEBUG 98236401Ssklower break; 98336401Ssklower 98436401Ssklower caseof( CC_TPDU_type, TPP_checksum): 98536401Ssklower caseof( DR_TPDU_type, TPP_checksum): 98636401Ssklower caseof( DT_TPDU_type, TPP_checksum): 98736401Ssklower caseof( XPD_TPDU_type, TPP_checksum): 98836401Ssklower if( tpcb->tp_use_checksum ) { 98936401Ssklower CHECK( iso_check_csum(m, tpdu_len), 99036401Ssklower E_TP_INV_PVAL, ts_bad_csum, discard, 0) 99136401Ssklower } 99236401Ssklower break; 99336401Ssklower 99436401Ssklower /* this is different from the above because in the context 99536401Ssklower * of concat/ sep tpdu_len might not be the same as hdr len 99636401Ssklower */ 99736401Ssklower caseof( AK_TPDU_type, TPP_checksum): 99836401Ssklower caseof( XAK_TPDU_type, TPP_checksum): 99936401Ssklower caseof( DC_TPDU_type, TPP_checksum): 100036401Ssklower if( tpcb->tp_use_checksum ) { 100137469Ssklower CHECK( iso_check_csum(m, (int)hdr->tpdu_li + 1), 100236401Ssklower E_TP_INV_PVAL, ts_bad_csum, discard, 0) 100336401Ssklower } 100436401Ssklower break; 100536401Ssklower #ifdef notdef 100636401Ssklower caseof( DR_TPDU_type, TPP_addl_info ): 100736401Ssklower /* ignore - its length and meaning are 100836401Ssklower * user defined and there's no way 100936401Ssklower * to pass this info to the user anyway 101036401Ssklower */ 101136401Ssklower break; 101236401Ssklower #endif notdef 101336401Ssklower 101436401Ssklower caseof( AK_TPDU_type, TPP_subseq ): 101536401Ssklower /* used after reduction of window */ 101636401Ssklower vb_getval(P, u_short, subseq); 101736401Ssklower subseq = ntohs(subseq); 101836401Ssklower IFDEBUG(D_ACKRECV) 101936401Ssklower printf("AK Subsequence # 0x%x\n", subseq); 102036401Ssklower ENDDEBUG 102136401Ssklower break; 102236401Ssklower 102336401Ssklower caseof( AK_TPDU_type, TPP_flow_cntl_conf ): 102436401Ssklower { 102536401Ssklower u_int ylwe; 102636401Ssklower u_short ysubseq, ycredit; 102736401Ssklower 102836401Ssklower fcc_present = TRUE; 102936401Ssklower vb_getval(P, u_int, ylwe); 103036401Ssklower vb_getval(P, u_short, ysubseq); 103136401Ssklower vb_getval(P, u_short, ycredit); 103236401Ssklower ylwe = ntohl(ylwe); 103336401Ssklower ysubseq = ntohs(ysubseq); 103436401Ssklower ycredit = ntohs(ycredit); 103536401Ssklower IFDEBUG(D_ACKRECV) 103636401Ssklower printf("AK FCC lwe 0x%x, subseq 0x%x, cdt 0x%x\n", 103736401Ssklower ylwe, ysubseq, ycredit); 103836401Ssklower ENDDEBUG 103936401Ssklower } 104036401Ssklower break; 104136401Ssklower 104236401Ssklower default: 104336401Ssklower IFDEBUG(D_TPINPUT) 104436401Ssklower printf("param ignored dutype 0x%x, code 0x%x\n", 104536401Ssklower dutype, vbptr(P)->tpv_code); 104636401Ssklower ENDDEBUG 104736401Ssklower IFTRACE(D_TPINPUT) 104836401Ssklower tptrace(TPPTmisc, "param ignored dutype code ", 104936401Ssklower dutype, vbptr(P)->tpv_code ,0,0); 105036401Ssklower ENDTRACE 105136401Ssklower IncStat(ts_param_ignored); 105236401Ssklower break; 105336401Ssklower #undef caseof 105436401Ssklower } 105536401Ssklower /* } */ END_WHILE_OPTIONS(P) 105636401Ssklower 105736401Ssklower /* NOTE: the variable dutype has been shifted left! */ 105836401Ssklower 105936401Ssklower switch( hdr->tpdu_type ) { 106036401Ssklower case CC_TPDU_type: 106136401Ssklower /* If CC comes back with an unacceptable class 106236401Ssklower * respond with a DR or ER 106336401Ssklower */ 106436401Ssklower 106536401Ssklower opt = hdr->tpdu_CCoptions; /* 1 byte */ 106636401Ssklower 106736401Ssklower { 106836401Ssklower tpp = tpcb->_tp_param; 106936401Ssklower tpp.p_class = (1<<hdr->tpdu_CCclass); 107036401Ssklower tpp.p_tpdusize = dusize; 107136401Ssklower tpp.p_dont_change_params = 0; 107236401Ssklower tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT; 107336401Ssklower tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD; 107436401Ssklower tpp.p_use_checksum = (addlopt & TPAO_NO_CSUM) == 0; 107536401Ssklower #ifdef notdef 107636401Ssklower tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC; 107736401Ssklower tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD; 107836401Ssklower tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC; 107936401Ssklower #endif notdef 108036401Ssklower 108136401Ssklower CHECK( 108236401Ssklower tp_consistency(tpcb, TP_FORCE, &tpp) != 0, 108336401Ssklower E_TP_NEGOT_FAILED, ts_negotfailed, respond, 108436401Ssklower (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 108536401Ssklower /* ^ more or less the location of class */ 108636401Ssklower ) 108736401Ssklower IFTRACE(D_CONN) 108836401Ssklower tptrace(TPPTmisc, 108936401Ssklower "after 1 consist class, out, tpconsout", 109036401Ssklower tpcb->tp_class, dgout_routine, tpcons_output, 0 109136401Ssklower ); 109236401Ssklower ENDTRACE 109336401Ssklower CHECK( 109436401Ssklower ((class_to_use == TP_CLASS_0)&& 109536401Ssklower (dgout_routine != tpcons_output)), 109636401Ssklower E_TP_NEGOT_FAILED, ts_negotfailed, respond, 109736401Ssklower (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 109836401Ssklower /* ^ more or less the location of class */ 109936401Ssklower ) 110045900Ssklower #ifdef TPCONS 110145900Ssklower if (tpcb->tp_netservice == ISO_CONS && 110245900Ssklower class_to_use == TP_CLASS_0) { 110345900Ssklower struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb; 110445900Ssklower struct pklcd *lcp = (struct pklcd *)isop->isop_chan; 110545900Ssklower lcp->lcd_flags &= ~X25_DG_CIRCUIT; 110645900Ssklower } 110745900Ssklower #endif 110836401Ssklower } 110936401Ssklower if( ! tpcb->tp_use_checksum) 111036401Ssklower IncStat(ts_csum_off); 111136401Ssklower if(tpcb->tp_xpd_service) 111236401Ssklower IncStat(ts_use_txpd); 111336401Ssklower if(tpcb->tp_xtd_format) 111436401Ssklower IncStat(ts_xtd_fmt); 111536401Ssklower 111636401Ssklower IFTRACE(D_CONN) 111736401Ssklower tptrace(TPPTmisc, "after CC class flags dusize CCclass", 111836401Ssklower tpcb->tp_class, tpcb->tp_flags, tpcb->tp_tpdusize, 111936401Ssklower hdr->tpdu_CCclass); 112036401Ssklower ENDTRACE 112136401Ssklower 112236401Ssklower /* 112336401Ssklower * Get the maximum transmission unit from the lower layer(s) 112436401Ssklower * so we can decide how large a TPDU size to negotiate. 112536401Ssklower * It would be nice if the arguments to this 112636401Ssklower * were more reasonable. 112736401Ssklower */ 112850435Ssklower (tpcb->tp_nlproto->nlp_mtu)(tpcb->tp_sock, tpcb->tp_npcb, 112936401Ssklower &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0); 113036401Ssklower 113136401Ssklower 113236401Ssklower /* if called or calling suffices appeared on the CC, 113336401Ssklower * they'd better jive with what's in the pcb 113436401Ssklower */ 113536401Ssklower if( fsufxlen ) { 113636401Ssklower CHECK( ((tpcb->tp_fsuffixlen != fsufxlen) || 113736401Ssklower bcmp(fsufxloc, tpcb->tp_fsuffix, fsufxlen)), 113836401Ssklower E_TP_INV_PVAL,ts_inv_sufx, respond, 113936401Ssklower (1+fsufxloc - (caddr_t)hdr)) 114036401Ssklower } 114136401Ssklower if( lsufxlen ) { 114236401Ssklower CHECK( ((tpcb->tp_lsuffixlen != lsufxlen) || 114336401Ssklower bcmp(lsufxloc, tpcb->tp_lsuffix, lsufxlen)), 114436401Ssklower E_TP_INV_PVAL,ts_inv_sufx, respond, 114536401Ssklower (1+lsufxloc - (caddr_t)hdr)) 114636401Ssklower } 114736401Ssklower 114836401Ssklower e.ATTR(CC_TPDU).e_sref = sref; 114936401Ssklower e.ATTR(CC_TPDU).e_cdt = hdr->tpdu_CCcdt; 115036401Ssklower takes_data = TRUE; 115136401Ssklower e.ev_number = CC_TPDU; 115236401Ssklower IncStat(ts_CC_rcvd); 115336401Ssklower break; 115436401Ssklower 115536401Ssklower case DC_TPDU_type: 115636401Ssklower if (sref != tpcb->tp_fref) 115736401Ssklower printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n", 115836401Ssklower sref, tpcb->tp_fref); 115936401Ssklower 116036401Ssklower CHECK( (sref != tpcb->tp_fref), 116142944Ssklower E_TP_MISM_REFS, ts_inv_sufx, discard, 116236401Ssklower (1 + (caddr_t)&hdr->tpdu_DCsref - (caddr_t)hdr)) 116342944Ssklower 116436401Ssklower e.ev_number = DC_TPDU; 116536401Ssklower IncStat(ts_DC_rcvd); 116636401Ssklower break; 116736401Ssklower 116836401Ssklower case DR_TPDU_type: 116936401Ssklower IFTRACE(D_TPINPUT) 117036401Ssklower tptrace(TPPTmisc, "DR recvd", hdr->tpdu_DRreason, 0, 0, 0); 117136401Ssklower ENDTRACE 117242944Ssklower if (sref != tpcb->tp_fref) { 117336401Ssklower printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n", 117436401Ssklower sref, tpcb->tp_fref); 117542944Ssklower } 117636401Ssklower 117742944Ssklower CHECK( (sref != 0 && sref != tpcb->tp_fref && 117842944Ssklower tpcb->tp_state != TP_CRSENT), 117942944Ssklower (TP_ERROR_SNDC | E_TP_MISM_REFS),ts_inv_sufx, respond, 118036401Ssklower (1 + (caddr_t)&hdr->tpdu_DRsref - (caddr_t)hdr)) 118136401Ssklower 118236401Ssklower e.ATTR(DR_TPDU).e_reason = hdr->tpdu_DRreason; 118336401Ssklower e.ATTR(DR_TPDU).e_sref = (u_short)sref; 118436401Ssklower takes_data = TRUE; 118536401Ssklower e.ev_number = DR_TPDU; 118636401Ssklower IncStat(ts_DR_rcvd); 118736401Ssklower break; 118836401Ssklower 118936401Ssklower case ER_TPDU_type: 119036401Ssklower IFTRACE(D_TPINPUT) 119136401Ssklower tptrace(TPPTmisc, "ER recvd", hdr->tpdu_ERreason,0,0,0); 119236401Ssklower ENDTRACE 119336401Ssklower e.ev_number = ER_TPDU; 119436401Ssklower e.ATTR(ER_TPDU).e_reason = hdr->tpdu_ERreason; 119536401Ssklower IncStat(ts_ER_rcvd); 119636401Ssklower break; 119736401Ssklower 119836401Ssklower case AK_TPDU_type: 119936401Ssklower 120036401Ssklower e.ATTR(AK_TPDU).e_subseq = subseq; 120136401Ssklower e.ATTR(AK_TPDU).e_fcc_present = fcc_present; 120236401Ssklower 120336401Ssklower if (tpcb->tp_xtd_format) { 120436401Ssklower #ifdef BYTE_ORDER 120536401Ssklower union seq_type seqeotX; 120636401Ssklower 120736401Ssklower seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 120836401Ssklower e.ATTR(AK_TPDU).e_seq = seqeotX.s_seq; 120936401Ssklower e.ATTR(AK_TPDU).e_cdt = ntohs(hdr->tpdu_AKcdtX); 121036401Ssklower #else 121136401Ssklower e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdtX; 121236401Ssklower e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseqX; 121336401Ssklower #endif BYTE_ORDER 121436401Ssklower } else { 121536401Ssklower e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdt; 121636401Ssklower e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseq; 121736401Ssklower } 121836401Ssklower IFTRACE(D_TPINPUT) 121936401Ssklower tptrace(TPPTmisc, "AK recvd seq cdt subseq fcc_pres", 122036401Ssklower e.ATTR(AK_TPDU).e_seq, e.ATTR(AK_TPDU).e_cdt, 122136401Ssklower subseq, fcc_present); 122236401Ssklower ENDTRACE 122336401Ssklower 122436401Ssklower e.ev_number = AK_TPDU; 122536401Ssklower IncStat(ts_AK_rcvd); 122636401Ssklower IncPStat(tpcb, tps_AK_rcvd); 122736401Ssklower break; 122836401Ssklower 122936401Ssklower case XAK_TPDU_type: 123036401Ssklower if (tpcb->tp_xtd_format) { 123136401Ssklower #ifdef BYTE_ORDER 123236401Ssklower union seq_type seqeotX; 123336401Ssklower 123436401Ssklower seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 123536401Ssklower e.ATTR(XAK_TPDU).e_seq = seqeotX.s_seq; 123636401Ssklower #else 123736401Ssklower e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseqX; 123836401Ssklower #endif BYTE_ORDER 123936401Ssklower } else { 124036401Ssklower e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseq; 124136401Ssklower } 124236401Ssklower e.ev_number = XAK_TPDU; 124336401Ssklower IncStat(ts_XAK_rcvd); 124436401Ssklower IncPStat(tpcb, tps_XAK_rcvd); 124536401Ssklower break; 124636401Ssklower 124736401Ssklower case XPD_TPDU_type: 124836401Ssklower if (tpcb->tp_xtd_format) { 124936401Ssklower #ifdef BYTE_ORDER 125036401Ssklower union seq_type seqeotX; 125136401Ssklower 125236401Ssklower seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 125336401Ssklower e.ATTR(XPD_TPDU).e_seq = seqeotX.s_seq; 125436401Ssklower #else 125536401Ssklower e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseqX; 125636401Ssklower #endif BYTE_ORDER 125736401Ssklower } else { 125836401Ssklower e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseq; 125936401Ssklower } 126036401Ssklower takes_data = TRUE; 126136401Ssklower e.ev_number = XPD_TPDU; 126236401Ssklower IncStat(ts_XPD_rcvd); 126336401Ssklower IncPStat(tpcb, tps_XPD_rcvd); 126436401Ssklower break; 126536401Ssklower 126636401Ssklower case DT_TPDU_type: 126736401Ssklower { /* the y option will cause occasional packets to be dropped. 126836401Ssklower * A little crude but it works. 126936401Ssklower */ 127036401Ssklower 127136401Ssklower IFDEBUG(D_DROP) 127236401Ssklower if(time.tv_usec & 0x4 && hdr->tpdu_DTseq & 0x1) { 127336401Ssklower IncStat(ts_ydebug); 127436401Ssklower goto discard; 127536401Ssklower } 127636401Ssklower ENDDEBUG 127736401Ssklower } 127836401Ssklower if (tpcb->tp_class == TP_CLASS_0) { 127950648Ssklower tp0_data: 128036401Ssklower e.ATTR(DT_TPDU).e_seq = 0; /* actually don't care */ 128136401Ssklower e.ATTR(DT_TPDU).e_eot = (((struct tp0du *)hdr)->tp0du_eot); 128236401Ssklower } else if (tpcb->tp_xtd_format) { 128336401Ssklower #ifdef BYTE_ORDER 128436401Ssklower union seq_type seqeotX; 128536401Ssklower 128636401Ssklower seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 128736401Ssklower e.ATTR(DT_TPDU).e_seq = seqeotX.s_seq; 128836401Ssklower e.ATTR(DT_TPDU).e_eot = seqeotX.s_eot; 128936401Ssklower #else 129036401Ssklower e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseqX; 129136401Ssklower e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeotX; 129236401Ssklower #endif BYTE_ORDER 129336401Ssklower } else { 129436401Ssklower e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseq; 129536401Ssklower e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeot; 129636401Ssklower } 129736401Ssklower if(e.ATTR(DT_TPDU).e_eot) 129836401Ssklower IncStat(ts_eot_input); 129936401Ssklower takes_data = TRUE; 130036401Ssklower e.ev_number = DT_TPDU; 130136401Ssklower IncStat(ts_DT_rcvd); 130236401Ssklower IncPStat(tpcb, tps_DT_rcvd); 130336401Ssklower break; 130436401Ssklower 130536401Ssklower case GR_TPDU_type: 130636401Ssklower tp_indicate(T_DISCONNECT, tpcb, ECONNABORTED); 130736401Ssklower /* drop through */ 130836401Ssklower default: 130936401Ssklower /* this should NEVER happen because there is a 131036401Ssklower * check for dutype well above here 131136401Ssklower */ 131236401Ssklower error = E_TP_INV_TPDU; /* causes an ER */ 131336401Ssklower IFDEBUG(D_TPINPUT) 131436401Ssklower printf("INVALID dutype 0x%x\n", hdr->tpdu_type); 131536401Ssklower ENDDEBUG 131636401Ssklower IncStat(ts_inv_dutype); 131736401Ssklower goto respond; 131836401Ssklower } 131936401Ssklower } 132036401Ssklower /* peel off the tp header; 132136401Ssklower * remember that the du_li doesn't count itself. 132236401Ssklower * This may leave us w/ an empty mbuf at the front of a chain. 132336401Ssklower * We can't just throw away the empty mbuf because hdr still points 132436401Ssklower * into the mbuf's data area and we're still using hdr (the tpdu header) 132536401Ssklower */ 132636401Ssklower m->m_len -= ((int)hdr->tpdu_li + 1); 132737469Ssklower m->m_data += ((int)hdr->tpdu_li + 1); 132836401Ssklower 132937469Ssklower if (takes_data) { 133037469Ssklower int max = tpdu_info[ hdr->tpdu_type ] [TP_MAX_DATA_INDEX]; 133137469Ssklower int datalen = tpdu_len - hdr->tpdu_li - 1, mbtype = MT_DATA; 133248749Ssklower struct { 133348749Ssklower struct tp_disc_reason dr; 133448749Ssklower struct cmsghdr x_hdr; 133548749Ssklower } x; 133648749Ssklower #define c_hdr x.x_hdr 133748749Ssklower register struct mbuf *n; 133836401Ssklower 133937469Ssklower CHECK( (max && datalen > max), E_TP_LENGTH_INVAL, 134037469Ssklower ts_inv_length, respond, (max + hdr->tpdu_li + 1) ); 134136401Ssklower switch( hdr->tpdu_type ) { 134237469Ssklower 134336401Ssklower case CR_TPDU_type: 134437469Ssklower c_hdr.cmsg_type = TPOPT_CONN_DATA; 134537469Ssklower goto make_control_msg; 134637469Ssklower 134736401Ssklower case CC_TPDU_type: 134837469Ssklower c_hdr.cmsg_type = TPOPT_CFRM_DATA; 134937469Ssklower goto make_control_msg; 135037469Ssklower 135136401Ssklower case DR_TPDU_type: 135248749Ssklower x.dr.dr_hdr.cmsg_len = sizeof(x) - sizeof(c_hdr); 135348749Ssklower x.dr.dr_hdr.cmsg_type = TPOPT_DISC_REASON; 135448749Ssklower x.dr.dr_hdr.cmsg_level = SOL_TRANSPORT; 135548749Ssklower x.dr.dr_reason = hdr->tpdu_DRreason; 135637469Ssklower c_hdr.cmsg_type = TPOPT_DISC_DATA; 135737469Ssklower make_control_msg: 135848749Ssklower datalen += sizeof(c_hdr); 135948749Ssklower c_hdr.cmsg_len = datalen; 136037469Ssklower c_hdr.cmsg_level = SOL_TRANSPORT; 136137469Ssklower mbtype = MT_CONTROL; 136243334Ssklower MGET(n, M_DONTWAIT, MT_DATA); 136348749Ssklower if (n == 0) 136448749Ssklower {m_freem(m); m = 0; datalen = 0; goto invoke; } 136548749Ssklower if (hdr->tpdu_type == DR_TPDU_type) { 136648749Ssklower datalen += sizeof(x) - sizeof(c_hdr); 136748749Ssklower bcopy((caddr_t)&x, mtod(n, caddr_t), n->m_len = sizeof(x)); 136848749Ssklower } else 136948749Ssklower bcopy((caddr_t)&c_hdr, mtod(n, caddr_t), 137048749Ssklower n->m_len = sizeof(c_hdr)); 137148749Ssklower n->m_next = m; 137248749Ssklower m = n; 137337469Ssklower /* FALLTHROUGH */ 137437469Ssklower 137536401Ssklower case XPD_TPDU_type: 137637469Ssklower if (mbtype != MT_CONTROL) 137737469Ssklower mbtype = MT_OOBDATA; 137837469Ssklower m->m_flags |= M_EOR; 137937469Ssklower /* FALLTHROUGH */ 138037469Ssklower 138136401Ssklower case DT_TPDU_type: 138237469Ssklower for (n = m; n; n = n->m_next) { 138337469Ssklower MCHTYPE(n, mbtype); 138437469Ssklower } 138543334Ssklower invoke: 138637469Ssklower e.ATTR(DT_TPDU).e_datalen = datalen; 138736401Ssklower e.ATTR(DT_TPDU).e_data = m; 138836401Ssklower break; 138936401Ssklower 139036401Ssklower default: 139136401Ssklower printf( 139236401Ssklower "ERROR in tp_input! hdr->tpdu_type 0x%x takes_data 0x%x m 0x%x\n", 139336401Ssklower hdr->tpdu_type, takes_data, m); 139436401Ssklower break; 139536401Ssklower } 139636401Ssklower /* prevent m_freem() after tp_driver() from throwing it all away */ 139736401Ssklower m = MNULL; 139836401Ssklower } 139936401Ssklower 140036401Ssklower IncStat(ts_tpdu_rcvd); 140136401Ssklower 140236401Ssklower IFDEBUG(D_TPINPUT) 140336401Ssklower printf( "tp_input: before driver, state 0x%x event 0x%x m 0x%x", 140436401Ssklower tpcb->tp_state, e.ev_number, m ); 140536401Ssklower printf(" e.e_data 0x%x\n", e.ATTR(DT_TPDU).e_data); 140636401Ssklower printf("takes_data 0x%x m_len 0x%x, tpdu_len 0x%x\n", 140736401Ssklower takes_data, (m==MNULL)?0:m->m_len, tpdu_len); 140836401Ssklower ENDDEBUG 140936401Ssklower 141036401Ssklower error = tp_driver(tpcb, &e); 141136401Ssklower 141236401Ssklower ASSERT(tpcb != (struct tp_pcb *)0); 141336401Ssklower ASSERT(tpcb->tp_sock != (struct socket *)0); 141436401Ssklower if( tpcb->tp_sock->so_error == 0 ) 141536401Ssklower tpcb->tp_sock->so_error = error; 141636401Ssklower 141736401Ssklower /* Kludge to keep the state tables under control (adding 141836401Ssklower * data on connect & disconnect & freeing the mbuf containing 141936401Ssklower * the data would have exploded the tables and made a big mess ). 142036401Ssklower */ 142136401Ssklower switch(e.ev_number) { 142236401Ssklower case CC_TPDU: 142336401Ssklower case DR_TPDU: 142436401Ssklower case CR_TPDU: 142536401Ssklower m = e.ATTR(CC_TPDU).e_data; /* same field for all three dutypes */ 142636401Ssklower IFDEBUG(D_TPINPUT) 142736401Ssklower printf("after driver, restoring m to 0x%x, takes_data 0x%x\n", 142836401Ssklower m, takes_data); 142936401Ssklower ENDDEBUG 143036401Ssklower break; 143136401Ssklower default: 143236401Ssklower break; 143336401Ssklower } 143436401Ssklower /* Concatenated sequences are terminated by any tpdu that 143536401Ssklower * carries data: CR, CC, DT, XPD, DR. 143636401Ssklower * All other tpdu types may be concatenated: AK, XAK, DC, ER. 143736401Ssklower */ 143836401Ssklower 143936401Ssklower separate: 144036401Ssklower if ( takes_data == 0 ) { 144136401Ssklower ASSERT( m != MNULL ); 144236401Ssklower /* 144336401Ssklower * we already peeled off the prev. tp header so 144436401Ssklower * we can just pull up some more and repeat 144536401Ssklower */ 144636401Ssklower 144737469Ssklower if( m = tp_inputprep(m) ) { 144836401Ssklower IFDEBUG(D_TPINPUT) 144936401Ssklower hdr = mtod(m, struct tpdu *); 145036401Ssklower printf("tp_input @ separate: hdr 0x%x size %d m 0x%x\n", 145136401Ssklower hdr, (int) hdr->tpdu_li + 1, m); 145236401Ssklower dump_mbuf(m, "tp_input after driver, at separate"); 145336401Ssklower ENDDEBUG 145436401Ssklower 145536401Ssklower IncStat(ts_concat_rcvd); 145636401Ssklower goto again; 145736401Ssklower } 145836401Ssklower } 145936401Ssklower if ( m != MNULL ) { 146036401Ssklower IFDEBUG(D_TPINPUT) 146136401Ssklower printf("tp_input : m_freem(0x%x)\n", m); 146236401Ssklower ENDDEBUG 146336401Ssklower m_freem(m); 146436401Ssklower IFDEBUG(D_TPINPUT) 146536401Ssklower printf("tp_input : after m_freem 0x%x\n", m); 146636401Ssklower ENDDEBUG 146736401Ssklower } 146836401Ssklower return (ProtoHook) tpcb; 146936401Ssklower 147036401Ssklower discard: 147136401Ssklower /* class 4: drop the tpdu */ 147236401Ssklower /* class 2,0: Should drop the net connection, if you can figure out 147336401Ssklower * to which connection it applies 147436401Ssklower */ 147536401Ssklower IFDEBUG(D_TPINPUT) 147636401Ssklower printf("tp_input DISCARD\n"); 147736401Ssklower ENDDEBUG 147836401Ssklower IFTRACE(D_TPINPUT) 147936401Ssklower tptrace(TPPTmisc, "tp_input DISCARD m", m,0,0,0); 148036401Ssklower ENDTRACE 148136401Ssklower m_freem(m); 148236401Ssklower IncStat(ts_recv_drop); 148336401Ssklower return (ProtoHook)0; 148436401Ssklower 148542944Ssklower nonx_dref: 148642944Ssklower switch (dutype) { 148742944Ssklower default: 148842944Ssklower goto discard; 148942944Ssklower case CC_TPDU_type: 149042944Ssklower /* error = E_TP_MISM_REFS; */ 149142944Ssklower break; 149242944Ssklower case DR_TPDU_type: 149342944Ssklower error |= TP_ERROR_SNDC; 149442944Ssklower } 149536401Ssklower respond: 149643334Ssklower IFDEBUG(D_TPINPUT) 149742944Ssklower printf("RESPOND: error 0x%x, errlen 0x%x\n", error, errlen); 149836401Ssklower ENDDEBUG 149936401Ssklower IFTRACE(D_TPINPUT) 150042944Ssklower tptrace(TPPTmisc, "tp_input RESPOND m error sref", m, error, sref, 0); 150136401Ssklower ENDTRACE 150242944Ssklower if (sref == 0) 150336401Ssklower goto discard; 150437469Ssklower (void) tp_error_emit(error, (u_long)sref, (struct sockaddr_iso *)faddr, 150542944Ssklower (struct sockaddr_iso *)laddr, m, errlen, tpcb, 150650648Ssklower cons_channel, dgout_routine); 150736401Ssklower IFDEBUG(D_ERROR_EMIT) 150836401Ssklower printf("tp_input after error_emit\n"); 150936401Ssklower ENDDEBUG 151036401Ssklower 151136401Ssklower #ifdef lint 151236401Ssklower printf("",sref,opt); 151336401Ssklower #endif lint 151436401Ssklower IncStat(ts_recv_drop); 151536401Ssklower return (ProtoHook)0; 151636401Ssklower } 151736401Ssklower 151836401Ssklower 151936401Ssklower /* 152036401Ssklower * NAME: tp_headersize() 152136401Ssklower * 152236401Ssklower * CALLED FROM: 152336401Ssklower * tp_emit() and tp_sbsend() 152436401Ssklower * TP needs to know the header size so it can figure out how 152536401Ssklower * much data to put in each tpdu. 152636401Ssklower * 152736401Ssklower * FUNCTION, ARGUMENTS, and RETURN VALUE: 152836401Ssklower * For a given connection, represented by (tpcb), and 152936401Ssklower * tpdu type (dutype), return the size of a tp header. 153036401Ssklower * 153136401Ssklower * RETURNS: the expected size of the heade in bytesr 153236401Ssklower * 153336401Ssklower * SIDE EFFECTS: 153436401Ssklower * 153536401Ssklower * NOTES: It would be nice if it got the network header size as well. 153636401Ssklower */ 153736401Ssklower int 153836401Ssklower tp_headersize(dutype, tpcb) 153936401Ssklower int dutype; 154036401Ssklower struct tp_pcb *tpcb; 154136401Ssklower { 154236401Ssklower register int size = 0; 154336401Ssklower 154436401Ssklower IFTRACE(D_CONN) 154536401Ssklower tptrace(TPPTmisc, "tp_headersize dutype class xtd_format", 154636401Ssklower dutype, tpcb->tp_class, tpcb->tp_xtd_format, 0); 154736401Ssklower ENDTRACE 154836401Ssklower if( !( (tpcb->tp_class == TP_CLASS_0) || 154936401Ssklower (tpcb->tp_class == TP_CLASS_4) || 155036401Ssklower (dutype == DR_TPDU_type) || 155136401Ssklower (dutype == CR_TPDU_type) )) { 155236401Ssklower printf("tp_headersize:dutype 0x%x, class 0x%x", 155336401Ssklower dutype, tpcb->tp_class); 155436401Ssklower /* TODO: identify this and GET RID OF IT */ 155536401Ssklower } 155636401Ssklower ASSERT( (tpcb->tp_class == TP_CLASS_0) || 155736401Ssklower (tpcb->tp_class == TP_CLASS_4) || 155836401Ssklower (dutype == DR_TPDU_type) || 155936401Ssklower (dutype == CR_TPDU_type) ); 156036401Ssklower 156136401Ssklower if( tpcb->tp_class == TP_CLASS_0 ) { 156236401Ssklower size = tpdu_info[ dutype ] [TP_LEN_CLASS_0_INDEX]; 156336401Ssklower } else { 156436401Ssklower size = tpdu_info[ dutype ] [tpcb->tp_xtd_format]; 156536401Ssklower } 156636401Ssklower return size; 156736401Ssklower /* caller must get network level header size separately */ 156836401Ssklower } 1569