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