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*42468Ssklower * @(#)tp_input.c 7.8 (Berkeley) 05/30/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 17136401Ssklower /* 17236401Ssklower * WHENEVER YOU USE THE FOLLOWING MACRO, 17336401Ssklower * BE SURE THE TPDUTYPE IS A LEGIT VALUE FIRST! 17436401Ssklower */ 17536401Ssklower 17636401Ssklower #define WHILE_OPTIONS(P, hdr,format)\ 17736401Ssklower { register caddr_t P;\ 17836401Ssklower P = (caddr_t)(hdr) +\ 17936401Ssklower tpdu_info[(hdr)->tpdu_type][(format)];\ 18036401Ssklower while( P < (caddr_t)(hdr) + (int)((hdr)->tpdu_li) ) { 18136401Ssklower 18236401Ssklower #define END_WHILE_OPTIONS(P)\ 18336401Ssklower P = P + 2 + (int)((struct tp_vbp *)P)->tpv_len ;\ 18436401Ssklower } } 18536401Ssklower 18636401Ssklower #define CHECK(Phrase, Erval, Stat, Whattodo, Loc)\ 18736401Ssklower if(Phrase) { error = (Erval); errloc = (caddr_t)(Loc); IncStat(Stat); \ 18836401Ssklower goto Whattodo; } 18936401Ssklower 19036401Ssklower /* end groan */ 19136401Ssklower 19236401Ssklower /* 19336401Ssklower * NAME: tp_newsocket() 19436401Ssklower * 19536401Ssklower * CALLED FROM: 19636401Ssklower * tp_input() on incoming CR, when a socket w/ the called suffix 19736401Ssklower * is awaiting a connection request 19836401Ssklower * 19936401Ssklower * FUNCTION and ARGUMENTS: 20036401Ssklower * Create a new socket structure, attach to it a new transport pcb, 20136401Ssklower * using a copy of the net level pcb for the parent socket. 20236401Ssklower * (so) is the parent socket. 20336401Ssklower * (fname) is the foreign address (all that's used is the nsap portion) 20436401Ssklower * 20536401Ssklower * RETURN VALUE: 20636401Ssklower * a new socket structure, being this end of the newly formed connection. 20736401Ssklower * 20836401Ssklower * SIDE EFFECTS: 20936401Ssklower * Sets a few things in the tpcb and net level pcb 21036401Ssklower * 21136401Ssklower * NOTES: 21236401Ssklower */ 21336401Ssklower static struct socket * 21436401Ssklower tp_newsocket(so, fname, cons_channel, class_to_use, netservice) 21536401Ssklower struct socket *so; 21636401Ssklower struct sockaddr *fname; 21736401Ssklower u_int cons_channel; 21836401Ssklower u_char class_to_use; 21936401Ssklower u_int netservice; 22036401Ssklower { 22136401Ssklower register struct tp_pcb *tpcb = sototpcb(so); /* old tpcb, needed below */ 22236401Ssklower struct tp_pcb * newtpcb; 22336401Ssklower 22436401Ssklower /* 22536401Ssklower * sonewconn() gets a new socket structure, 22636401Ssklower * a new lower layer pcb and a new tpcb, 22736401Ssklower * but the pcbs are unnamed (not bound) 22836401Ssklower */ 22936401Ssklower IFTRACE(D_NEWSOCK) 23038841Ssklower tptraceTPCB(TPPTmisc, "newsock: listg_so, _tpcb, so_head", 23139196Ssklower so, tpcb, so->so_head, 0); 23236401Ssklower ENDTRACE 23336401Ssklower 23440636Skarels if ((so = sonewconn(so, SS_ISCONFIRMING)) == (struct socket *)0) 23536401Ssklower return so; 23636401Ssklower IFTRACE(D_NEWSOCK) 23738841Ssklower tptraceTPCB(TPPTmisc, "newsock: after newconn so, so_head", 23838841Ssklower so, so->so_head, 0, 0); 23936401Ssklower ENDTRACE 24036401Ssklower 24136401Ssklower IFDEBUG(D_NEWSOCK) 24237469Ssklower printf("tp_newsocket(channel 0x%x) after sonewconn so 0x%x \n", 24337469Ssklower cons_channel, so); 24437469Ssklower dump_addr(fname); 24536401Ssklower { 24636401Ssklower struct socket *t, *head ; 24736401Ssklower 24836401Ssklower head = so->so_head; 24936401Ssklower t = so; 25036401Ssklower printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n", 25136401Ssklower t, t->so_head, t->so_q0, t->so_q0len); 25236401Ssklower while( (t=t->so_q0) && t!= so && t!= head) 25336401Ssklower printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n", 25436401Ssklower t, t->so_head, t->so_q0, t->so_q0len); 25536401Ssklower } 25636401Ssklower ENDDEBUG 25736401Ssklower 25836401Ssklower /* 25936401Ssklower * before we clobber the old tpcb ptr, get these items from the parent pcb 26036401Ssklower */ 26136401Ssklower newtpcb = sototpcb(so); 26236401Ssklower newtpcb->_tp_param = tpcb->_tp_param; 26336401Ssklower newtpcb->tp_flags = tpcb->tp_flags; 26436401Ssklower newtpcb->tp_lcredit = tpcb->tp_lcredit; 26536401Ssklower newtpcb->tp_l_tpdusize = tpcb->tp_l_tpdusize; 26636401Ssklower newtpcb->tp_lsuffixlen = tpcb->tp_lsuffixlen; 26736401Ssklower bcopy( tpcb->tp_lsuffix, newtpcb->tp_lsuffix, newtpcb->tp_lsuffixlen); 26837469Ssklower soreserve(so, (u_long)tpcb->tp_winsize, (u_long)tpcb->tp_winsize); 26936401Ssklower 27037469Ssklower if( /* old */ tpcb->tp_ucddata) { 27136401Ssklower /* 27237469Ssklower * These data are the connect- , confirm- or disconnect- data. 27336401Ssklower */ 27436401Ssklower struct mbuf *conndata; 27536401Ssklower 27637469Ssklower conndata = m_copy(tpcb->tp_ucddata, 0, (int)M_COPYALL); 27736401Ssklower IFDEBUG(D_CONN) 27836401Ssklower dump_mbuf(conndata, "conndata after mcopy"); 27936401Ssklower ENDDEBUG 28037469Ssklower newtpcb->tp_ucddata = conndata; 28136401Ssklower } 28236401Ssklower 28336401Ssklower tpcb = newtpcb; 28436401Ssklower tpcb->tp_state = TP_LISTENING; 28536401Ssklower tpcb->tp_class = class_to_use; 28636401Ssklower tpcb->tp_netservice = netservice; 28736401Ssklower 28836401Ssklower 28936401Ssklower ASSERT( fname != 0 ) ; /* just checking */ 29036401Ssklower if ( fname ) { 29136401Ssklower /* 29236401Ssklower * tp_route_to takes its address argument in the form of an mbuf. 29336401Ssklower */ 29436401Ssklower struct mbuf *m; 29536401Ssklower int err; 29636401Ssklower 29736401Ssklower MGET(m, M_DONTWAIT, MT_SONAME); /* mbuf type used is confusing */ 29836401Ssklower if (m) { 29936401Ssklower /* 30036401Ssklower * this seems a bit grotesque, but tp_route_to expects 30136401Ssklower * an mbuf * instead of simply a sockaddr; it calls the ll 30236401Ssklower * pcb_connect, which expects the name/addr in an mbuf as well. 30336401Ssklower * sigh. 30436401Ssklower */ 30537469Ssklower bcopy((caddr_t)fname, mtod(m, caddr_t), fname->sa_len); 30637469Ssklower m->m_len = fname->sa_len; 30736401Ssklower 30836401Ssklower /* grot : have to say the kernel can override params in 30936401Ssklower * the passive open case 31036401Ssklower */ 31136401Ssklower tpcb->tp_dont_change_params = 0; 31236401Ssklower err = tp_route_to( m, tpcb, cons_channel); 31336401Ssklower m_free(m); 31436401Ssklower 31536401Ssklower if (!err) 31636401Ssklower goto ok; 31736401Ssklower } 31836401Ssklower IFDEBUG(D_CONN) 31936401Ssklower printf("tp_route_to FAILED! detaching tpcb 0x%x, so 0x%x\n", 32036401Ssklower tpcb, so); 32136401Ssklower ENDDEBUG 32236401Ssklower (void) tp_detach(tpcb); 32336401Ssklower return 0; 32436401Ssklower } 32536401Ssklower ok: 32636401Ssklower IFDEBUG(D_TPINPUT) 32736401Ssklower printf("tp_newsocket returning so 0x%x, sototpcb(so) 0x%x\n", 32836401Ssklower so, sototpcb(so)); 32936401Ssklower ENDDEBUG 33036401Ssklower return so; 33136401Ssklower } 33236401Ssklower 33336401Ssklower #ifndef CONS 33436401Ssklower tpcons_output() 33536401Ssklower { 33636401Ssklower return(0); 33736401Ssklower } 33836401Ssklower #endif !CONS 33936401Ssklower 34036401Ssklower /* 34136401Ssklower * NAME: tp_input() 34236401Ssklower * 34336401Ssklower * CALLED FROM: 34436401Ssklower * net layer input routine 34536401Ssklower * 34636401Ssklower * FUNCTION and ARGUMENTS: 34736401Ssklower * Process an incoming TPDU (m), finding the associated tpcb if there 34836401Ssklower * is one. Create the appropriate type of event and call the driver. 34936401Ssklower * (faddr) and (laddr) are the foreign and local addresses. 35036401Ssklower * 35136401Ssklower * When tp_input() is called we KNOW that the ENTIRE TP HEADER 35236401Ssklower * has been m_pullup-ed. 35336401Ssklower * 35436401Ssklower * RETURN VALUE: Nada 35536401Ssklower * 35636401Ssklower * SIDE EFFECTS: 35736401Ssklower * When using COSNS it may affect the state of the net-level pcb 35836401Ssklower * 35936401Ssklower * NOTE: 36036401Ssklower * The initial value of acktime is 2 so that we will never 36136401Ssklower * have a 0 value for tp_peer_acktime. It gets used in the 36236401Ssklower * computation of the retransmission timer value, and so it 36336401Ssklower * mustn't be zero. 36436401Ssklower * 2 seems like a reasonable minimum. 36536401Ssklower */ 36636401Ssklower ProtoHook 36739929Ssklower tp_input(m, faddr, laddr, cons_channel, dgout_routine, ce_bit) 36836401Ssklower register struct mbuf *m; 36936401Ssklower struct sockaddr *faddr, *laddr; /* NSAP addresses */ 37036401Ssklower u_int cons_channel; 37136401Ssklower int (*dgout_routine)(); 37239929Ssklower int ce_bit; 37336401Ssklower 37436401Ssklower { 37536401Ssklower register struct tp_pcb *tpcb = (struct tp_pcb *)0; 37636401Ssklower register struct tpdu *hdr = mtod(m, struct tpdu *); 37736401Ssklower struct socket *so; 37836401Ssklower struct tp_event e; 37938841Ssklower int error; 38036401Ssklower unsigned dutype; 38136401Ssklower u_short dref, sref, acktime, subseq; /*VAX*/ 38238841Ssklower u_char preferred_class, class_to_use; 38336401Ssklower u_char opt, dusize, addlopt; 38436401Ssklower #ifdef TP_PERF_MEAS 38538841Ssklower u_char perf_meas; 38636401Ssklower #endif TP_PERF_MEAS 38736401Ssklower u_char fsufxlen; 38836401Ssklower u_char lsufxlen; 38938841Ssklower caddr_t fsufxloc, lsufxloc; 39036401Ssklower int tpdu_len; 39136401Ssklower u_int takes_data; 39236401Ssklower u_int fcc_present; 39338841Ssklower caddr_t errloc; 39436401Ssklower struct tp_conn_param tpp; 39536401Ssklower int tpcons_output(); 39636401Ssklower 39738841Ssklower again: 39836401Ssklower #ifdef TP_PERF_MEAS 39938841Ssklower GET_CUR_TIME( &e.e_time ); perf_meas = 0; 40036401Ssklower #endif TP_PERF_MEAS 40136401Ssklower 40236401Ssklower IFDEBUG(D_TPINPUT) 40336401Ssklower printf("tp_input(0x%x, ... 0x%x)\n", m, cons_channel); 40436401Ssklower ENDDEBUG 40536401Ssklower 40636401Ssklower 40736401Ssklower tpdu_len = 0; 40836401Ssklower tpcb = (struct tp_pcb *)0; 40938841Ssklower fsufxlen = 0; fsufxloc = 0; 41038841Ssklower lsufxlen = 0; lsufxloc = 0; 41138841Ssklower errloc = 0; error = 0; 41236401Ssklower addlopt = 0; 41336401Ssklower acktime = 2; 41436401Ssklower dusize = TP_DFL_TPDUSIZE; 41536401Ssklower sref = 0; 41636401Ssklower subseq = 0; 41736401Ssklower takes_data = FALSE; 41836401Ssklower fcc_present = FALSE; 41938841Ssklower preferred_class = 0; class_to_use = 0; 42036401Ssklower 42136401Ssklower /* 42236401Ssklower * get the actual tpdu length - necessary for monitoring 42336401Ssklower * and for checksumming 42436401Ssklower * 42536401Ssklower * Also, maybe measure the mbuf chain lengths and sizes. 42636401Ssklower */ 42736401Ssklower 42836401Ssklower { register struct mbuf *n=m; 42936401Ssklower # ifdef ARGO_DEBUG 43036401Ssklower int chain_length = 0; 43136401Ssklower # endif ARGO_DEBUG 43236401Ssklower 43336401Ssklower for(;;) { 43436401Ssklower tpdu_len += n->m_len; 43536401Ssklower IFDEBUG(D_MBUF_MEAS) 43637469Ssklower if( n->m_flags & M_EXT) { 43736401Ssklower IncStat(ts_mb_cluster); 43836401Ssklower } else { 43936401Ssklower IncStat(ts_mb_small); 44036401Ssklower } 44136401Ssklower chain_length ++; 44236401Ssklower ENDDEBUG 44336401Ssklower if (n->m_next == MNULL ) { 44436401Ssklower break; 44536401Ssklower } 44636401Ssklower n = n->m_next; 44736401Ssklower } 44836401Ssklower IFDEBUG(D_MBUF_MEAS) 44936401Ssklower if(chain_length > 16) 45036401Ssklower chain_length = 0; /* zero used for anything > 16 */ 45136401Ssklower tp_stat.ts_mb_len_distr[chain_length] ++; 45236401Ssklower ENDDEBUG 45336401Ssklower } 45436401Ssklower IFTRACE(D_TPINPUT) 45536401Ssklower tptraceTPCB(TPPTtpduin, hdr->tpdu_type, hdr, hdr->tpdu_li+1, tpdu_len, 45636401Ssklower 0); 45736401Ssklower ENDTRACE 45836401Ssklower 45936401Ssklower dref = ntohs((short)hdr->tpdu_dref); 46036401Ssklower sref = ntohs((short)hdr->tpdu_sref); 46136401Ssklower dutype = (int)hdr->tpdu_type; 46236401Ssklower 46336401Ssklower IFDEBUG(D_TPINPUT) 46436401Ssklower printf("input: dutype 0x%x cons_channel 0x%x dref 0x%x\n", dutype, 46536401Ssklower cons_channel, dref); 46636401Ssklower printf("input: dref 0x%x sref 0x%x\n", dref, sref); 46736401Ssklower ENDDEBUG 46836401Ssklower IFTRACE(D_TPINPUT) 46936401Ssklower tptrace(TPPTmisc, "channel dutype dref ", 47036401Ssklower cons_channel, dutype, dref, 0); 47136401Ssklower ENDTRACE 47236401Ssklower 47336401Ssklower 47436401Ssklower #ifdef ARGO_DEBUG 47536401Ssklower if( (dutype < TP_MIN_TPDUTYPE) || (dutype > TP_MAX_TPDUTYPE)) { 47636401Ssklower printf("BAD dutype! 0x%x, channel 0x%x dref 0x%x\n", 47736401Ssklower dutype, cons_channel, dref); 47836401Ssklower dump_buf (m, sizeof( struct mbuf )); 47936401Ssklower 48036401Ssklower IncStat(ts_inv_dutype); 48136401Ssklower goto discard; 48236401Ssklower } 48336401Ssklower #endif ARGO_DEBUG 48436401Ssklower 48536401Ssklower CHECK( (dutype < TP_MIN_TPDUTYPE || dutype > TP_MAX_TPDUTYPE), 48636401Ssklower E_TP_INV_TPDU, ts_inv_dutype, respond, 48736401Ssklower 2 ); 48836401Ssklower /* unfortunately we can't take the address of the tpdu_type field, 48936401Ssklower * since it's a bit field - so we just use the constant offset 2 49036401Ssklower */ 49136401Ssklower 49236401Ssklower /* Now this isn't very neat but since you locate a pcb one way 49336401Ssklower * at the beginning of connection establishment, and by 49436401Ssklower * the dref for each tpdu after that, we have to treat CRs differently 49536401Ssklower */ 49636401Ssklower if ( dutype == CR_TPDU_type ) { 49736401Ssklower u_char alt_classes = 0; 49836401Ssklower 49936401Ssklower #ifdef notdef /* This is done up above */ 50036401Ssklower sref = hdr->tpdu_CRsref; 50136401Ssklower #endif notdef 50237469Ssklower preferred_class = 1 << hdr->tpdu_CRclass; 50336401Ssklower opt = hdr->tpdu_CRoptions; 50436401Ssklower 50536401Ssklower WHILE_OPTIONS(P, hdr, 1 ) /* { */ 50636401Ssklower 50736401Ssklower switch( vbptr(P)->tpv_code ) { 50836401Ssklower 50936401Ssklower case TPP_tpdu_size: 51036401Ssklower vb_getval(P, u_char, dusize); 51136401Ssklower IFDEBUG(D_TPINPUT) 51236401Ssklower printf("CR dusize 0x%x\n", dusize); 51336401Ssklower ENDDEBUG 51436401Ssklower CHECK( (dusize < TP_MIN_TPDUSIZE || dusize > TP_MAX_TPDUSIZE), 51536401Ssklower E_TP_INV_PVAL, ts_inv_pval, respond, 51636401Ssklower (1 + (caddr_t)&vbptr(P)->tpv_val - P) ) 51736401Ssklower break; 51836401Ssklower case TPP_addl_opt: 51936401Ssklower vb_getval(P, u_char, addlopt); 52036401Ssklower break; 52136401Ssklower case TPP_calling_sufx: 52236401Ssklower /* could use vb_getval, but we want to save the loc & len 52336401Ssklower * for later use 52436401Ssklower */ 52536401Ssklower fsufxloc = (caddr_t) &vbptr(P)->tpv_val; 52636401Ssklower fsufxlen = vbptr(P)->tpv_len; 52736401Ssklower IFDEBUG(D_TPINPUT) 52836401Ssklower printf("CR fsufx:"); 52936401Ssklower { register int j; 53036401Ssklower for(j=0; j<fsufxlen; j++ ) { 53136401Ssklower printf(" 0x%x. ", *((caddr_t)(fsufxloc+j)) ); 53236401Ssklower } 53336401Ssklower printf("\n"); 53436401Ssklower } 53536401Ssklower ENDDEBUG 53636401Ssklower break; 53736401Ssklower case TPP_called_sufx: 53836401Ssklower /* could use vb_getval, but we want to save the loc & len 53936401Ssklower * for later use 54036401Ssklower */ 54136401Ssklower lsufxloc = (caddr_t) &vbptr(P)->tpv_val; 54236401Ssklower lsufxlen = vbptr(P)->tpv_len; 54336401Ssklower IFDEBUG(D_TPINPUT) 54436401Ssklower printf("CR lsufx:"); 54536401Ssklower { register int j; 54636401Ssklower for(j=0; j<lsufxlen; j++ ) { 54737469Ssklower printf(" 0x%x. ", *((u_char *)(lsufxloc+j)) ); 54836401Ssklower } 54936401Ssklower printf("\n"); 55036401Ssklower } 55136401Ssklower ENDDEBUG 55236401Ssklower break; 55336401Ssklower 55436401Ssklower #ifdef TP_PERF_MEAS 55536401Ssklower case TPP_perf_meas: 55636401Ssklower vb_getval(P, u_char, perf_meas); 55736401Ssklower break; 55836401Ssklower #endif TP_PERF_MEAS 55936401Ssklower 56036401Ssklower case TPP_vers: 56136401Ssklower /* not in class 0; 1 octet; in CR_TPDU only */ 56236401Ssklower CHECK( (vbval(P, u_char) != TP_VERSION ), 56336401Ssklower E_TP_INV_PVAL, ts_inv_pval, respond, 56436401Ssklower (1 + (caddr_t)&vbptr(P)->tpv_val - P) ) 56536401Ssklower break; 56636401Ssklower case TPP_acktime: 56736401Ssklower vb_getval(P, u_short, acktime); 56836401Ssklower acktime = ntohs(acktime); 56936401Ssklower acktime = acktime/500; /* convert to slowtimo ticks */ 57036401Ssklower if((short)acktime <=0 ) 57136401Ssklower acktime = 2; /* don't allow a bad peer to screw us up */ 57236401Ssklower IFDEBUG(D_TPINPUT) 57336401Ssklower printf("CR acktime 0x%x\n", acktime); 57436401Ssklower ENDDEBUG 57536401Ssklower break; 57636401Ssklower 57736401Ssklower case TPP_alt_class: 57836401Ssklower { 57936401Ssklower u_char *aclass = 0; 58036401Ssklower register int i; 58136401Ssklower 58236401Ssklower for (i = ((struct tp_vbp *)P)->tpv_len; i>0; i--) { 58336401Ssklower aclass = 58436401Ssklower (u_char *) &(((struct tp_vbp *)P)->tpv_val); 58537469Ssklower alt_classes |= (1<<((*aclass)>>4)); 58636401Ssklower } 58736401Ssklower IFDEBUG(D_TPINPUT) 58836401Ssklower printf("alt_classes 0x%x\n", alt_classes); 58936401Ssklower ENDDEBUG 59036401Ssklower } 59136401Ssklower break; 59236401Ssklower 59336401Ssklower case TPP_security: 59436401Ssklower case TPP_residER: 59536401Ssklower case TPP_priority: 59636401Ssklower case TPP_transdelay: 59736401Ssklower case TPP_throughput: 59836401Ssklower case TPP_addl_info: 59936401Ssklower case TPP_subseq: 60036401Ssklower IFDEBUG(D_TPINPUT) 60136401Ssklower printf("param ignored CR_TPDU code= 0x%x\n", 60236401Ssklower vbptr(P)->tpv_code); 60336401Ssklower ENDDEBUG 60436401Ssklower IncStat(ts_param_ignored); 60536401Ssklower break; 60636401Ssklower 60736401Ssklower case TPP_checksum: 60836401Ssklower IFDEBUG(D_TPINPUT) 60936401Ssklower printf("CR before cksum\n"); 61036401Ssklower ENDDEBUG 61136401Ssklower 61236401Ssklower CHECK( iso_check_csum(m, tpdu_len), 61336401Ssklower E_TP_INV_PVAL, ts_bad_csum, discard, 0) 61436401Ssklower 61536401Ssklower IFDEBUG(D_TPINPUT) 61636401Ssklower printf("CR before cksum\n"); 61736401Ssklower ENDDEBUG 61836401Ssklower break; 61936401Ssklower 62036401Ssklower default: 62136401Ssklower IncStat(ts_inv_pcode); 62236401Ssklower error = E_TP_INV_PCODE; 62336401Ssklower goto discard; 62436401Ssklower 62536401Ssklower } 62636401Ssklower 62736401Ssklower /* } */ END_WHILE_OPTIONS(P) 62836401Ssklower 62936401Ssklower if( lsufxlen == 0) { 63036401Ssklower /* can't look for a tpcb w/o any called sufx */ 63136401Ssklower error = E_TP_LENGTH_INVAL; 63236401Ssklower IncStat(ts_inv_sufx); 63336401Ssklower goto respond; 63436401Ssklower } else { 63536401Ssklower register struct tp_ref *rp; 63636401Ssklower register int r; 63736401Ssklower extern int tp_maxrefopen; 63836401Ssklower 63936401Ssklower rp = &tp_ref[1]; /* zero-th one is never open */ 64036401Ssklower for( r=1 ; (r <= tp_maxrefopen) ; r++,rp++ ) { 64136401Ssklower if (rp->tpr_state!=REF_OPENING) 64236401Ssklower continue; 64336401Ssklower if ( bcmp(lsufxloc, rp->tpr_pcb->tp_lsuffix, lsufxlen)==0 ) { 64436401Ssklower tpcb = rp->tpr_pcb; 64536401Ssklower if( laddr->sa_family != 64636401Ssklower tpcb->tp_sock->so_proto->pr_domain->dom_family ) { 64736401Ssklower IFDEBUG(D_CONN) 64836401Ssklower printf( 64936401Ssklower "MISMATCHED AF on CR! laddr.family 0x%x expected 0x%x\n", 65036401Ssklower laddr->sa_family, 65136401Ssklower tpcb->tp_sock->so_proto->pr_domain->dom_family ); 65236401Ssklower ENDDEBUG 65336401Ssklower continue; 65436401Ssklower } 65536401Ssklower IFTRACE(D_TPINPUT) 65636401Ssklower tptrace(TPPTmisc, "tp_input: ref *lsufxloc refstate", 65736401Ssklower r, *lsufxloc, rp->tpr_state, 0); 65836401Ssklower ENDTRACE 65936401Ssklower /* found it */ 66036401Ssklower break; 66136401Ssklower } 66236401Ssklower } 66336401Ssklower 66436401Ssklower CHECK( (r > tp_maxrefopen), E_TP_NO_SESSION, ts_inv_sufx, respond, 66536401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 66636401Ssklower /* _tpduf is the fixed part; add 2 to get the dref bits of 66736401Ssklower * the fixed part (can't take the address of a bit field) 66836401Ssklower */ 66936401Ssklower } 67036401Ssklower 67136401Ssklower /* 67236401Ssklower * WE HAVE A TPCB 67336401Ssklower * already know that the classes in the CR match at least 67436401Ssklower * one class implemented, but we don't know yet if they 67536401Ssklower * include any classes permitted by this server. 67636401Ssklower */ 67736401Ssklower 67836401Ssklower IFDEBUG(D_TPINPUT) 67936401Ssklower printf("HAVE A TPCB 1: 0x%x\n", tpcb); 68036401Ssklower ENDDEBUG 68136401Ssklower IFDEBUG(D_CONN) 68236401Ssklower printf( 68336401Ssklower "CR: bef CHKS: flags 0x%x class_to_use 0x%x alt 0x%x opt 0x%x tp_class 0x%x\n", 68436401Ssklower tpcb->tp_flags, class_to_use, alt_classes, opt, tpcb->tp_class); 68536401Ssklower ENDDEBUG 68636401Ssklower /* tpcb->tp_class doesn't include any classes not implemented */ 68736401Ssklower class_to_use = (preferred_class & tpcb->tp_class); 68836401Ssklower if( (class_to_use = preferred_class & tpcb->tp_class) == 0 ) 68936401Ssklower class_to_use = alt_classes & tpcb->tp_class; 69036401Ssklower 69136401Ssklower class_to_use = 1 << tp_mask_to_num(class_to_use); 69236401Ssklower 69336401Ssklower { 69436401Ssklower tpp = tpcb->_tp_param; 69536401Ssklower tpp.p_class = class_to_use; 69636401Ssklower tpp.p_tpdusize = dusize; 69736401Ssklower tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT; 69836401Ssklower tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD; 69936401Ssklower tpp.p_use_checksum = (tpp.p_class == TP_CLASS_0)?0: 70036401Ssklower (addlopt & TPAO_NO_CSUM) == 0; 70136401Ssklower #ifdef notdef 70236401Ssklower tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC; 70336401Ssklower tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD; 70436401Ssklower tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC; 70536401Ssklower #endif notdef 70636401Ssklower 70736401Ssklower CHECK( 70836401Ssklower tp_consistency(tpcb, 0 /* not force or strict */, &tpp) != 0, 70936401Ssklower E_TP_NEGOT_FAILED, ts_negotfailed, respond, 71036401Ssklower (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 71136401Ssklower /* ^ more or less the location of class */ 71236401Ssklower ) 71336401Ssklower } 71436401Ssklower IFTRACE(D_CONN) 71536401Ssklower tptrace(TPPTmisc, 71636401Ssklower "after 1 consist class_to_use class, out, tpconsout", 71736401Ssklower class_to_use, 71836401Ssklower tpcb->tp_class, dgout_routine, tpcons_output 71936401Ssklower ); 72036401Ssklower ENDTRACE 72136401Ssklower CHECK( 72236401Ssklower ((class_to_use == TP_CLASS_0)&&(dgout_routine != tpcons_output)), 72336401Ssklower E_TP_NEGOT_FAILED, ts_negotfailed, respond, 72436401Ssklower (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 72536401Ssklower /* ^ more or less the location of class */ 72636401Ssklower ) 72736401Ssklower IFDEBUG(D_CONN) 72836401Ssklower printf("CR: after CRCCCHECKS: tpcb 0x%x, flags 0x%x\n", 72936401Ssklower tpcb, tpcb->tp_flags); 73036401Ssklower ENDDEBUG 73136401Ssklower takes_data = TRUE; 73236401Ssklower e.ATTR(CR_TPDU).e_cdt = hdr->tpdu_CRcdt; 73336401Ssklower e.ev_number = CR_TPDU; 73436401Ssklower 73536401Ssklower so = tpcb->tp_sock; 73636401Ssklower if (so->so_options & SO_ACCEPTCONN) { 73736401Ssklower /* 73836401Ssklower * Create a socket, tpcb, ll pcb, etc. 73936401Ssklower * for this newborn connection, and fill in all the values. 74036401Ssklower */ 74136401Ssklower IFDEBUG(D_CONN) 74236401Ssklower printf("abt to call tp_newsocket(0x%x, 0x%x, 0x%x, 0x%x)\n", 74336401Ssklower so, laddr, faddr, cons_channel); 74436401Ssklower ENDDEBUG 74536401Ssklower if( (so = 74636401Ssklower tp_newsocket(so, faddr, cons_channel, 74736401Ssklower class_to_use, 74837469Ssklower ((tpcb->tp_netservice == IN_CLNS) ? IN_CLNS : 74937469Ssklower (dgout_routine == tpcons_output)?ISO_CONS:ISO_CLNS)) 75036401Ssklower ) == (struct socket *)0 ) { 75136401Ssklower /* note - even if netservice is IN_CLNS, as far as 75236401Ssklower * the tp entity is concerned, the only differences 75337469Ssklower * are CO vs CL 75436401Ssklower */ 75536401Ssklower IFDEBUG(D_CONN) 75636401Ssklower printf("tp_newsocket returns 0\n"); 75736401Ssklower ENDDEBUG 75836401Ssklower goto discard; 75936401Ssklower } 76036401Ssklower tpcb = sototpcb(so); 76136401Ssklower 76236401Ssklower /* 76337469Ssklower * Stash the addresses in the net level pcb 76436401Ssklower * kind of like a pcbconnect() but don't need 76536401Ssklower * or want all those checks. 76636401Ssklower */ 76736401Ssklower (tpcb->tp_nlproto->nlp_putnetaddr)(so->so_pcb, faddr, TP_FOREIGN); 76836401Ssklower (tpcb->tp_nlproto->nlp_putnetaddr)(so->so_pcb, laddr, TP_LOCAL); 76936401Ssklower 77037469Ssklower /* stash the f suffix in the new tpcb */ 77137469Ssklower /* l suffix is already there */ 77238841Ssklower bcopy(fsufxloc, tpcb->tp_fsuffix, fsufxlen); 77336401Ssklower 77437469Ssklower (tpcb->tp_nlproto->nlp_putsufx) 77537469Ssklower (so->so_pcb, fsufxloc, fsufxlen, TP_FOREIGN); 77638841Ssklower (tpcb->tp_nlproto->nlp_putsufx) 77738841Ssklower (so->so_pcb, lsufxloc, lsufxlen, TP_LOCAL); 77837469Ssklower 77936401Ssklower #ifdef TP_PERF_MEAS 78036401Ssklower if( tpcb->tp_perf_on = perf_meas ) { /* assignment */ 78136401Ssklower /* ok, let's create an mbuf for stashing the 78236401Ssklower * statistics if one doesn't already exist 78336401Ssklower */ 78436401Ssklower (void) tp_setup_perf(tpcb); 78536401Ssklower } 78636401Ssklower #endif TP_PERF_MEAS 78736401Ssklower tpcb->tp_fref = sref; 78836401Ssklower 78936401Ssklower /* We've already checked for consistency with the options 79036401Ssklower * set in tpp, but we couldn't set them earlier because 79136401Ssklower * we didn't want to change options in the LISTENING tpcb. 79236401Ssklower * Now we set the options in the new socket's tpcb. 79336401Ssklower */ 79436401Ssklower (void) tp_consistency( tpcb, TP_FORCE, &tpp); 79536401Ssklower 79636401Ssklower if(!tpcb->tp_use_checksum) 79736401Ssklower IncStat(ts_csum_off); 79836401Ssklower if(tpcb->tp_xpd_service) 79936401Ssklower IncStat(ts_use_txpd); 80036401Ssklower if(tpcb->tp_xtd_format) 80136401Ssklower IncStat(ts_xtd_fmt); 80236401Ssklower 80336401Ssklower /* 80436401Ssklower * Get the maximum transmission unit from the lower layer(s) 80536401Ssklower * so we can negotiate a reasonable max TPDU size. 80636401Ssklower */ 80736401Ssklower (tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb, 80836401Ssklower &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0); 80936401Ssklower tpcb->tp_peer_acktime = acktime; 81036401Ssklower 81136401Ssklower /* 81236401Ssklower * The following kludge is used to test retransmissions and 81336401Ssklower * timeout during connection establishment. 81436401Ssklower */ 81536401Ssklower IFDEBUG(D_ZDREF) 81636401Ssklower IncStat(ts_zdebug); 81737469Ssklower /*tpcb->tp_fref = 0;*/ 81836401Ssklower ENDDEBUG 81936401Ssklower } 82036401Ssklower IncStat(ts_CR_rcvd); 82139929Ssklower if (!tpcb->tp_cebit_off) { 82239929Ssklower tpcb->tp_win_recv = tp_start_win << 8; 82339929Ssklower tpcb->tp_cong_sample.cs_size = 0; 82439929Ssklower LOCAL_CREDIT(tpcb); 82539929Ssklower CONG_INIT_SAMPLE(tpcb); 82639929Ssklower CONG_UPDATE_SAMPLE(tpcb, ce_bit); 82739929Ssklower } 82839929Ssklower tpcb->tp_ackrcvd = 0; 82936401Ssklower } else if ( dutype == ER_TPDU_type ) { 83036401Ssklower /* 83136401Ssklower * ER TPDUs have to be recognized separately 83236401Ssklower * because they don't necessarily have a tpcb 83336401Ssklower * with them and we don't want err out looking for such 83436401Ssklower * a beast. 83536401Ssklower * We could put a bunch of little kludges in the 83636401Ssklower * next section of code so it would avoid references to tpcb 83736401Ssklower * if dutype == ER_TPDU_type but we don't want code for ERs to 83836401Ssklower * mess up code for data transfer. 83936401Ssklower */ 84036401Ssklower IncStat(ts_ER_rcvd); 84136401Ssklower e.ev_number = ER_TPDU; 84236401Ssklower e.ATTR(ER_TPDU).e_reason = (u_char)hdr->tpdu_ERreason; 84336401Ssklower takes_data = 1; 84436401Ssklower } else { 84536401Ssklower /* tpdu type is CC, XPD, XAK, GR, AK, DR, DC, or DT */ 84636401Ssklower 84736401Ssklower /* In the next 4 checks, 84836401Ssklower * _tpduf is the fixed part; add 2 to get the dref bits of 84936401Ssklower * the fixed part (can't take the address of a bit field) 85036401Ssklower */ 85136401Ssklower if(cons_channel) { 85236401Ssklower #if NARGOXTWENTYFIVE > 0 85336401Ssklower extern struct tp_pcb *cons_chan_to_tpcb(); 85436401Ssklower 85536401Ssklower tpcb = cons_chan_to_tpcb( cons_channel ); 85636401Ssklower /* Problem: We may have a legit 85736401Ssklower * error situation yet we may or may not have 85836401Ssklower * a correspondence between the tpcb and the vc, 85936401Ssklower * e.g., TP4cr--> <no dice, respond w/ DR on vc> 86036401Ssklower * <--- DR 86136401Ssklower * Now it's up to TP to look at the tpdu and do one of: 86236401Ssklower * confirm(dgm)(cr), confirm(circuit)(cr), reject(cr), or 86336401Ssklower * nothing, if the circuit is already open (any other tpdu). 86436401Ssklower * Sigh. 86536401Ssklower */ 86636401Ssklower 86736401Ssklower /* I don't know about this error value */ 86836401Ssklower CHECK( (tpcb == (struct tp_pcb *)0) , 86936401Ssklower E_TP_NO_CR_ON_NC, ts_inv_dref, respond, 87036401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 87136401Ssklower #else 87236401Ssklower printf("tp_input(): X25 NOT CONFIGURED!!\n"); 87336401Ssklower #endif NARGOXTWENTYFIVE > 0 87436401Ssklower 87536401Ssklower } else { 87636401Ssklower 87736401Ssklower CHECK( ((int)dref <= 0 || dref >= N_TPREF) , 87836401Ssklower E_TP_MISM_REFS,ts_inv_dref, respond, 87936401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 88036401Ssklower CHECK( ((tpcb = tp_ref[dref].tpr_pcb ) == (struct tp_pcb *) 0 ), 88136401Ssklower E_TP_MISM_REFS,ts_inv_dref, respond, 88236401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 88336401Ssklower CHECK( (tpcb->tp_refp->tpr_state == REF_FREE), 88436401Ssklower E_TP_MISM_REFS,ts_inv_dref, respond, 88536401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 88636401Ssklower } 88736401Ssklower 88836401Ssklower IFDEBUG(D_TPINPUT) 88936401Ssklower printf("HAVE A TPCB 2: 0x%x\n", tpcb); 89036401Ssklower ENDDEBUG 89136401Ssklower 89236401Ssklower /* causes a DR to be sent for CC; ER for all else */ 89336401Ssklower CHECK( (tpcb->tp_refp->tpr_state == REF_FROZEN), 89436401Ssklower (dutype == CC_TPDU_type?E_TP_NO_SESSION:E_TP_MISM_REFS), 89536401Ssklower ts_inv_dref, respond, 89636401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 89736401Ssklower 89836401Ssklower IFDEBUG(D_TPINPUT) 89936401Ssklower printf("state of dref %d ok, tpcb 0x%x\n", dref,tpcb); 90036401Ssklower ENDDEBUG 90136401Ssklower /* 90236401Ssklower * At this point the state of the dref could be 90336401Ssklower * FROZEN: tpr_pcb == NULL, has ( reference only) timers 90436401Ssklower * for example, DC may arrive after the close() has detached 90536401Ssklower * the tpcb (e.g., if user turned off SO_LISTEN option) 90636401Ssklower * OPENING : a tpcb exists but no timers yet 90736401Ssklower * OPEN : tpcb exists & timers are outstanding 90836401Ssklower */ 90936401Ssklower 91039929Ssklower if (!tpcb->tp_cebit_off) 91139929Ssklower CONG_UPDATE_SAMPLE(tpcb, ce_bit); 91239929Ssklower 91336401Ssklower dusize = tpcb->tp_tpdusize; 91436401Ssklower 91536401Ssklower dutype = hdr->tpdu_type << 8; /* for the switch below */ 91636401Ssklower 91736401Ssklower WHILE_OPTIONS(P, hdr, tpcb->tp_xtd_format) /* { */ 91836401Ssklower 91937469Ssklower #define caseof(x,y) case (((x)<<8)+(y)) 92036401Ssklower switch( dutype | vbptr(P)->tpv_code ) { 92136401Ssklower 92236401Ssklower caseof( CC_TPDU_type, TPP_addl_opt ): 92336401Ssklower /* not in class 0; 1 octet */ 92436401Ssklower vb_getval(P, u_char, addlopt); 92536401Ssklower break; 92636401Ssklower caseof( CC_TPDU_type, TPP_tpdu_size ): 92736401Ssklower vb_getval(P, u_char, dusize); 92836401Ssklower CHECK( (dusize < TP_MIN_TPDUSIZE || dusize > 92936401Ssklower TP_MAX_TPDUSIZE), E_TP_INV_PVAL, ts_inv_pval, respond, 93036401Ssklower (1 + (caddr_t)&vbptr(P)->tpv_val - P) ) 93136401Ssklower IFDEBUG(D_TPINPUT) 93236401Ssklower printf("CC dusize 0x%x\n", dusize); 93336401Ssklower ENDDEBUG 93436401Ssklower break; 93536401Ssklower caseof( CC_TPDU_type, TPP_calling_sufx): 93636401Ssklower IFDEBUG(D_TPINPUT) 93736401Ssklower printf("CC calling (local) sufxlen 0x%x\n", lsufxlen); 93836401Ssklower ENDDEBUG 93936401Ssklower lsufxloc = (caddr_t) &vbptr(P)->tpv_val; 94036401Ssklower lsufxlen = vbptr(P)->tpv_len; 94136401Ssklower break; 94236401Ssklower caseof( CC_TPDU_type, TPP_acktime ): 94336401Ssklower /* class 4 only, 2 octets */ 94436401Ssklower vb_getval(P, u_short, acktime); 94536401Ssklower acktime = acktime/500; /* convert to slowtimo ticks */ 94636401Ssklower if( (short)acktime <=0 ) 94736401Ssklower acktime = 2; 94836401Ssklower break; 94936401Ssklower caseof( CC_TPDU_type, TPP_called_sufx): 95036401Ssklower fsufxloc = (caddr_t) &vbptr(P)->tpv_val; 95136401Ssklower fsufxlen = vbptr(P)->tpv_len; 95236401Ssklower IFDEBUG(D_TPINPUT) 95336401Ssklower printf("CC called (foreign) sufx len %d\n", fsufxlen); 95436401Ssklower ENDDEBUG 95536401Ssklower break; 95636401Ssklower 95736401Ssklower caseof( CC_TPDU_type, TPP_checksum): 95836401Ssklower caseof( DR_TPDU_type, TPP_checksum): 95936401Ssklower caseof( DT_TPDU_type, TPP_checksum): 96036401Ssklower caseof( XPD_TPDU_type, TPP_checksum): 96136401Ssklower if( tpcb->tp_use_checksum ) { 96236401Ssklower CHECK( iso_check_csum(m, tpdu_len), 96336401Ssklower E_TP_INV_PVAL, ts_bad_csum, discard, 0) 96436401Ssklower } 96536401Ssklower break; 96636401Ssklower 96736401Ssklower /* this is different from the above because in the context 96836401Ssklower * of concat/ sep tpdu_len might not be the same as hdr len 96936401Ssklower */ 97036401Ssklower caseof( AK_TPDU_type, TPP_checksum): 97136401Ssklower caseof( XAK_TPDU_type, TPP_checksum): 97236401Ssklower caseof( DC_TPDU_type, TPP_checksum): 97336401Ssklower if( tpcb->tp_use_checksum ) { 97437469Ssklower CHECK( iso_check_csum(m, (int)hdr->tpdu_li + 1), 97536401Ssklower E_TP_INV_PVAL, ts_bad_csum, discard, 0) 97636401Ssklower } 97736401Ssklower break; 97836401Ssklower #ifdef notdef 97936401Ssklower caseof( DR_TPDU_type, TPP_addl_info ): 98036401Ssklower /* ignore - its length and meaning are 98136401Ssklower * user defined and there's no way 98236401Ssklower * to pass this info to the user anyway 98336401Ssklower */ 98436401Ssklower break; 98536401Ssklower #endif notdef 98636401Ssklower 98736401Ssklower caseof( AK_TPDU_type, TPP_subseq ): 98836401Ssklower /* used after reduction of window */ 98936401Ssklower vb_getval(P, u_short, subseq); 99036401Ssklower subseq = ntohs(subseq); 99136401Ssklower IFDEBUG(D_ACKRECV) 99236401Ssklower printf("AK Subsequence # 0x%x\n", subseq); 99336401Ssklower ENDDEBUG 99436401Ssklower break; 99536401Ssklower 99636401Ssklower caseof( AK_TPDU_type, TPP_flow_cntl_conf ): 99736401Ssklower { 99836401Ssklower u_int ylwe; 99936401Ssklower u_short ysubseq, ycredit; 100036401Ssklower 100136401Ssklower fcc_present = TRUE; 100236401Ssklower vb_getval(P, u_int, ylwe); 100336401Ssklower vb_getval(P, u_short, ysubseq); 100436401Ssklower vb_getval(P, u_short, ycredit); 100536401Ssklower ylwe = ntohl(ylwe); 100636401Ssklower ysubseq = ntohs(ysubseq); 100736401Ssklower ycredit = ntohs(ycredit); 100836401Ssklower IFDEBUG(D_ACKRECV) 100936401Ssklower printf("AK FCC lwe 0x%x, subseq 0x%x, cdt 0x%x\n", 101036401Ssklower ylwe, ysubseq, ycredit); 101136401Ssklower ENDDEBUG 101236401Ssklower } 101336401Ssklower break; 101436401Ssklower 101536401Ssklower default: 101636401Ssklower IFDEBUG(D_TPINPUT) 101736401Ssklower printf("param ignored dutype 0x%x, code 0x%x\n", 101836401Ssklower dutype, vbptr(P)->tpv_code); 101936401Ssklower ENDDEBUG 102036401Ssklower IFTRACE(D_TPINPUT) 102136401Ssklower tptrace(TPPTmisc, "param ignored dutype code ", 102236401Ssklower dutype, vbptr(P)->tpv_code ,0,0); 102336401Ssklower ENDTRACE 102436401Ssklower IncStat(ts_param_ignored); 102536401Ssklower break; 102636401Ssklower #undef caseof 102736401Ssklower } 102836401Ssklower /* } */ END_WHILE_OPTIONS(P) 102936401Ssklower 103036401Ssklower /* NOTE: the variable dutype has been shifted left! */ 103136401Ssklower 103236401Ssklower switch( hdr->tpdu_type ) { 103336401Ssklower case CC_TPDU_type: 103436401Ssklower /* If CC comes back with an unacceptable class 103536401Ssklower * respond with a DR or ER 103636401Ssklower */ 103736401Ssklower 103836401Ssklower opt = hdr->tpdu_CCoptions; /* 1 byte */ 103936401Ssklower 104036401Ssklower { 104136401Ssklower tpp = tpcb->_tp_param; 104236401Ssklower tpp.p_class = (1<<hdr->tpdu_CCclass); 104336401Ssklower tpp.p_tpdusize = dusize; 104436401Ssklower tpp.p_dont_change_params = 0; 104536401Ssklower tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT; 104636401Ssklower tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD; 104736401Ssklower tpp.p_use_checksum = (addlopt & TPAO_NO_CSUM) == 0; 104836401Ssklower #ifdef notdef 104936401Ssklower tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC; 105036401Ssklower tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD; 105136401Ssklower tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC; 105236401Ssklower #endif notdef 105336401Ssklower 105436401Ssklower CHECK( 105536401Ssklower tp_consistency(tpcb, TP_FORCE, &tpp) != 0, 105636401Ssklower E_TP_NEGOT_FAILED, ts_negotfailed, respond, 105736401Ssklower (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 105836401Ssklower /* ^ more or less the location of class */ 105936401Ssklower ) 106036401Ssklower IFTRACE(D_CONN) 106136401Ssklower tptrace(TPPTmisc, 106236401Ssklower "after 1 consist class, out, tpconsout", 106336401Ssklower tpcb->tp_class, dgout_routine, tpcons_output, 0 106436401Ssklower ); 106536401Ssklower ENDTRACE 106636401Ssklower CHECK( 106736401Ssklower ((class_to_use == TP_CLASS_0)&& 106836401Ssklower (dgout_routine != tpcons_output)), 106936401Ssklower E_TP_NEGOT_FAILED, ts_negotfailed, respond, 107036401Ssklower (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 107136401Ssklower /* ^ more or less the location of class */ 107236401Ssklower ) 107336401Ssklower } 107436401Ssklower if( ! tpcb->tp_use_checksum) 107536401Ssklower IncStat(ts_csum_off); 107636401Ssklower if(tpcb->tp_xpd_service) 107736401Ssklower IncStat(ts_use_txpd); 107836401Ssklower if(tpcb->tp_xtd_format) 107936401Ssklower IncStat(ts_xtd_fmt); 108036401Ssklower 108136401Ssklower IFTRACE(D_CONN) 108236401Ssklower tptrace(TPPTmisc, "after CC class flags dusize CCclass", 108336401Ssklower tpcb->tp_class, tpcb->tp_flags, tpcb->tp_tpdusize, 108436401Ssklower hdr->tpdu_CCclass); 108536401Ssklower ENDTRACE 108636401Ssklower 108736401Ssklower /* 108836401Ssklower * Get the maximum transmission unit from the lower layer(s) 108936401Ssklower * so we can decide how large a TPDU size to negotiate. 109036401Ssklower * It would be nice if the arguments to this 109136401Ssklower * were more reasonable. 109236401Ssklower */ 109336401Ssklower (tpcb->tp_nlproto->nlp_mtu)(tpcb->tp_sock, tpcb->tp_sock->so_pcb, 109436401Ssklower &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0); 109536401Ssklower 109636401Ssklower #ifdef CONS 109736401Ssklower /* Could be that this CC came in on a NEW vc, in which case 109836401Ssklower * we have to confirm it. 109936401Ssklower */ 110036401Ssklower if( cons_channel ) 110136401Ssklower cons_netcmd( CONN_CONFIRM, tpcb->tp_npcb, cons_channel, 110236401Ssklower tpcb->tp_class == TP_CLASS_4); 110336401Ssklower #endif CONS 110436401Ssklower 110536401Ssklower tpcb->tp_peer_acktime = acktime; 110636401Ssklower 110736401Ssklower /* if called or calling suffices appeared on the CC, 110836401Ssklower * they'd better jive with what's in the pcb 110936401Ssklower */ 111036401Ssklower if( fsufxlen ) { 111136401Ssklower CHECK( ((tpcb->tp_fsuffixlen != fsufxlen) || 111236401Ssklower bcmp(fsufxloc, tpcb->tp_fsuffix, fsufxlen)), 111336401Ssklower E_TP_INV_PVAL,ts_inv_sufx, respond, 111436401Ssklower (1+fsufxloc - (caddr_t)hdr)) 111536401Ssklower } 111636401Ssklower if( lsufxlen ) { 111736401Ssklower CHECK( ((tpcb->tp_lsuffixlen != lsufxlen) || 111836401Ssklower bcmp(lsufxloc, tpcb->tp_lsuffix, lsufxlen)), 111936401Ssklower E_TP_INV_PVAL,ts_inv_sufx, respond, 112036401Ssklower (1+lsufxloc - (caddr_t)hdr)) 112136401Ssklower } 112236401Ssklower 112336401Ssklower #ifdef notdef 112436401Ssklower e.ATTR(CC_TPDU).e_sref = (u_short)hdr->tpdu_CCsref; 112536401Ssklower #else 112636401Ssklower e.ATTR(CC_TPDU).e_sref = sref; 112736401Ssklower #endif notdef 112836401Ssklower e.ATTR(CC_TPDU).e_cdt = hdr->tpdu_CCcdt; 112936401Ssklower takes_data = TRUE; 113036401Ssklower e.ev_number = CC_TPDU; 113136401Ssklower IncStat(ts_CC_rcvd); 113236401Ssklower break; 113336401Ssklower 113436401Ssklower case DC_TPDU_type: 113536401Ssklower #ifdef notdef 113636401Ssklower if (hdr->tpdu_DCsref != tpcb->tp_fref) 113736401Ssklower printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n", 113836401Ssklower hdr->tpdu_DCsref, tpcb->tp_fref); 113936401Ssklower #else 114036401Ssklower if (sref != tpcb->tp_fref) 114136401Ssklower printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n", 114236401Ssklower sref, tpcb->tp_fref); 114336401Ssklower #endif notdef 114436401Ssklower 114536401Ssklower #ifdef notdef 114636401Ssklower CHECK( (hdr->tpdu_DCsref != tpcb->tp_fref), 114736401Ssklower E_TP_MISM_REFS, ts_inv_sufx, respond, 114836401Ssklower (1 + (caddr_t)&hdr->tpdu_DCsref - (caddr_t)hdr)) 114936401Ssklower #else 115036401Ssklower CHECK( (sref != tpcb->tp_fref), 115136401Ssklower E_TP_MISM_REFS, ts_inv_sufx, respond, 115236401Ssklower (1 + (caddr_t)&hdr->tpdu_DCsref - (caddr_t)hdr)) 115336401Ssklower #endif notdef 115436401Ssklower e.ev_number = DC_TPDU; 115536401Ssklower IncStat(ts_DC_rcvd); 115636401Ssklower break; 115736401Ssklower 115836401Ssklower case DR_TPDU_type: 115936401Ssklower IFTRACE(D_TPINPUT) 116036401Ssklower tptrace(TPPTmisc, "DR recvd", hdr->tpdu_DRreason, 0, 0, 0); 116136401Ssklower ENDTRACE 116236401Ssklower #ifdef vax 116336401Ssklower if(sref != tpcb->tp_fref) 116436401Ssklower printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n", 116536401Ssklower sref, tpcb->tp_fref); 116636401Ssklower 116736401Ssklower CHECK( (sref != tpcb->tp_fref), 116836401Ssklower E_TP_MISM_REFS,ts_inv_sufx, respond, 116936401Ssklower (1 + (caddr_t)&hdr->tpdu_DRsref - (caddr_t)hdr)) 117036401Ssklower 117136401Ssklower e.ATTR(DR_TPDU).e_reason = hdr->tpdu_DRreason; 117236401Ssklower e.ATTR(DR_TPDU).e_sref = (u_short)sref; 117336401Ssklower #else 117436401Ssklower if(hdr->tpdu_DRsref != tpcb->tp_fref) 117536401Ssklower printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n", 117636401Ssklower hdr->tpdu_DRsref, tpcb->tp_fref); 117736401Ssklower 117836401Ssklower CHECK( (hdr->tpdu_DRsref != tpcb->tp_fref), 117936401Ssklower 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 = 118336401Ssklower hdr->tpdu_DRreason; 118436401Ssklower e.ATTR(DR_TPDU).e_sref = (u_short)hdr->tpdu_DRsref; 118536401Ssklower #endif vax 118636401Ssklower takes_data = TRUE; 118736401Ssklower e.ev_number = DR_TPDU; 118836401Ssklower IncStat(ts_DR_rcvd); 118936401Ssklower break; 119036401Ssklower 119136401Ssklower case ER_TPDU_type: 119236401Ssklower IFTRACE(D_TPINPUT) 119336401Ssklower tptrace(TPPTmisc, "ER recvd", hdr->tpdu_ERreason,0,0,0); 119436401Ssklower ENDTRACE 119536401Ssklower e.ev_number = ER_TPDU; 119636401Ssklower e.ATTR(ER_TPDU).e_reason = hdr->tpdu_ERreason; 119736401Ssklower IncStat(ts_ER_rcvd); 119836401Ssklower break; 119936401Ssklower 120036401Ssklower case AK_TPDU_type: 120136401Ssklower 120236401Ssklower e.ATTR(AK_TPDU).e_subseq = subseq; 120336401Ssklower e.ATTR(AK_TPDU).e_fcc_present = fcc_present; 120436401Ssklower 120536401Ssklower if (tpcb->tp_xtd_format) { 120636401Ssklower #ifdef BYTE_ORDER 120736401Ssklower union seq_type seqeotX; 120836401Ssklower 120936401Ssklower seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 121036401Ssklower e.ATTR(AK_TPDU).e_seq = seqeotX.s_seq; 121136401Ssklower e.ATTR(AK_TPDU).e_cdt = ntohs(hdr->tpdu_AKcdtX); 121236401Ssklower #else 121336401Ssklower e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdtX; 121436401Ssklower e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseqX; 121536401Ssklower #endif BYTE_ORDER 121636401Ssklower } else { 121736401Ssklower e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdt; 121836401Ssklower e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseq; 121936401Ssklower } 122036401Ssklower IFTRACE(D_TPINPUT) 122136401Ssklower tptrace(TPPTmisc, "AK recvd seq cdt subseq fcc_pres", 122236401Ssklower e.ATTR(AK_TPDU).e_seq, e.ATTR(AK_TPDU).e_cdt, 122336401Ssklower subseq, fcc_present); 122436401Ssklower ENDTRACE 122536401Ssklower 122636401Ssklower e.ev_number = AK_TPDU; 122736401Ssklower IncStat(ts_AK_rcvd); 122836401Ssklower IncPStat(tpcb, tps_AK_rcvd); 122936401Ssklower break; 123036401Ssklower 123136401Ssklower case XAK_TPDU_type: 123236401Ssklower if (tpcb->tp_xtd_format) { 123336401Ssklower #ifdef BYTE_ORDER 123436401Ssklower union seq_type seqeotX; 123536401Ssklower 123636401Ssklower seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 123736401Ssklower e.ATTR(XAK_TPDU).e_seq = seqeotX.s_seq; 123836401Ssklower #else 123936401Ssklower e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseqX; 124036401Ssklower #endif BYTE_ORDER 124136401Ssklower } else { 124236401Ssklower e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseq; 124336401Ssklower } 124436401Ssklower e.ev_number = XAK_TPDU; 124536401Ssklower IncStat(ts_XAK_rcvd); 124636401Ssklower IncPStat(tpcb, tps_XAK_rcvd); 124736401Ssklower break; 124836401Ssklower 124936401Ssklower case XPD_TPDU_type: 125036401Ssklower if (tpcb->tp_xtd_format) { 125136401Ssklower #ifdef BYTE_ORDER 125236401Ssklower union seq_type seqeotX; 125336401Ssklower 125436401Ssklower seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 125536401Ssklower e.ATTR(XPD_TPDU).e_seq = seqeotX.s_seq; 125636401Ssklower #else 125736401Ssklower e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseqX; 125836401Ssklower #endif BYTE_ORDER 125936401Ssklower } else { 126036401Ssklower e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseq; 126136401Ssklower } 126236401Ssklower takes_data = TRUE; 126336401Ssklower e.ev_number = XPD_TPDU; 126436401Ssklower IncStat(ts_XPD_rcvd); 126536401Ssklower IncPStat(tpcb, tps_XPD_rcvd); 126636401Ssklower break; 126736401Ssklower 126836401Ssklower case DT_TPDU_type: 126936401Ssklower { /* the y option will cause occasional packets to be dropped. 127036401Ssklower * A little crude but it works. 127136401Ssklower */ 127236401Ssklower 127336401Ssklower IFDEBUG(D_DROP) 127436401Ssklower if(time.tv_usec & 0x4 && hdr->tpdu_DTseq & 0x1) { 127536401Ssklower IncStat(ts_ydebug); 127636401Ssklower goto discard; 127736401Ssklower } 127836401Ssklower ENDDEBUG 127936401Ssklower } 128036401Ssklower if (tpcb->tp_class == TP_CLASS_0) { 128136401Ssklower e.ATTR(DT_TPDU).e_seq = 0; /* actually don't care */ 128236401Ssklower e.ATTR(DT_TPDU).e_eot = (((struct tp0du *)hdr)->tp0du_eot); 128336401Ssklower } else if (tpcb->tp_xtd_format) { 128436401Ssklower #ifdef BYTE_ORDER 128536401Ssklower union seq_type seqeotX; 128636401Ssklower 128736401Ssklower seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 128836401Ssklower e.ATTR(DT_TPDU).e_seq = seqeotX.s_seq; 128936401Ssklower e.ATTR(DT_TPDU).e_eot = seqeotX.s_eot; 129036401Ssklower #else 129136401Ssklower e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseqX; 129236401Ssklower e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeotX; 129336401Ssklower #endif BYTE_ORDER 129436401Ssklower } else { 129536401Ssklower e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseq; 129636401Ssklower e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeot; 129736401Ssklower } 129836401Ssklower if(e.ATTR(DT_TPDU).e_eot) 129936401Ssklower IncStat(ts_eot_input); 130036401Ssklower takes_data = TRUE; 130136401Ssklower e.ev_number = DT_TPDU; 130236401Ssklower IncStat(ts_DT_rcvd); 130336401Ssklower IncPStat(tpcb, tps_DT_rcvd); 130436401Ssklower break; 130536401Ssklower 130636401Ssklower case GR_TPDU_type: 130736401Ssklower tp_indicate(T_DISCONNECT, tpcb, ECONNABORTED); 130836401Ssklower /* drop through */ 130936401Ssklower default: 131036401Ssklower /* this should NEVER happen because there is a 131136401Ssklower * check for dutype well above here 131236401Ssklower */ 131336401Ssklower error = E_TP_INV_TPDU; /* causes an ER */ 131436401Ssklower IFDEBUG(D_TPINPUT) 131536401Ssklower printf("INVALID dutype 0x%x\n", hdr->tpdu_type); 131636401Ssklower ENDDEBUG 131736401Ssklower IncStat(ts_inv_dutype); 131836401Ssklower goto respond; 131936401Ssklower } 132036401Ssklower } 132136401Ssklower 132236401Ssklower /* peel off the tp header; 132336401Ssklower * remember that the du_li doesn't count itself. 132436401Ssklower * This may leave us w/ an empty mbuf at the front of a chain. 132536401Ssklower * We can't just throw away the empty mbuf because hdr still points 132636401Ssklower * into the mbuf's data area and we're still using hdr (the tpdu header) 132736401Ssklower */ 132836401Ssklower m->m_len -= ((int)hdr->tpdu_li + 1); 132937469Ssklower m->m_data += ((int)hdr->tpdu_li + 1); 133036401Ssklower 133137469Ssklower if (takes_data) { 133237469Ssklower int max = tpdu_info[ hdr->tpdu_type ] [TP_MAX_DATA_INDEX]; 133337469Ssklower int datalen = tpdu_len - hdr->tpdu_li - 1, mbtype = MT_DATA; 1334*42468Ssklower struct cmsghdr c_hdr; 133537469Ssklower struct mbuf *n; 133636401Ssklower 133737469Ssklower CHECK( (max && datalen > max), E_TP_LENGTH_INVAL, 133837469Ssklower ts_inv_length, respond, (max + hdr->tpdu_li + 1) ); 133936401Ssklower switch( hdr->tpdu_type ) { 134037469Ssklower 134136401Ssklower case CR_TPDU_type: 134237469Ssklower c_hdr.cmsg_type = TPOPT_CONN_DATA; 134337469Ssklower goto make_control_msg; 134437469Ssklower 134536401Ssklower case CC_TPDU_type: 134637469Ssklower c_hdr.cmsg_type = TPOPT_CFRM_DATA; 134737469Ssklower goto make_control_msg; 134837469Ssklower 134936401Ssklower case DR_TPDU_type: 135037469Ssklower c_hdr.cmsg_type = TPOPT_DISC_DATA; 135137469Ssklower make_control_msg: 135237469Ssklower c_hdr.cmsg_level = SOL_TRANSPORT; 135337469Ssklower mbtype = MT_CONTROL; 135440015Ssklower datalen += sizeof(c_hdr); 135540015Ssklower m->m_len += sizeof(c_hdr); 135640015Ssklower m->m_data -= sizeof(c_hdr); 135740015Ssklower c_hdr.cmsg_len = datalen; 135840015Ssklower bcopy((caddr_t)&c_hdr, mtod(m, caddr_t), sizeof(c_hdr)); 135937469Ssklower /* FALLTHROUGH */ 136037469Ssklower 136136401Ssklower case XPD_TPDU_type: 136237469Ssklower if (mbtype != MT_CONTROL) 136337469Ssklower mbtype = MT_OOBDATA; 136437469Ssklower m->m_flags |= M_EOR; 136537469Ssklower /* FALLTHROUGH */ 136637469Ssklower 136736401Ssklower case DT_TPDU_type: 136837469Ssklower for (n = m; n; n = n->m_next) { 136937469Ssklower MCHTYPE(n, mbtype); 137037469Ssklower } 137137469Ssklower e.ATTR(DT_TPDU).e_datalen = datalen; 137236401Ssklower e.ATTR(DT_TPDU).e_data = m; 137336401Ssklower break; 137436401Ssklower 137536401Ssklower default: 137636401Ssklower printf( 137736401Ssklower "ERROR in tp_input! hdr->tpdu_type 0x%x takes_data 0x%x m 0x%x\n", 137836401Ssklower hdr->tpdu_type, takes_data, m); 137936401Ssklower break; 138036401Ssklower } 138136401Ssklower /* prevent m_freem() after tp_driver() from throwing it all away */ 138236401Ssklower m = MNULL; 138336401Ssklower } 138436401Ssklower 138536401Ssklower IncStat(ts_tpdu_rcvd); 138636401Ssklower 138736401Ssklower IFDEBUG(D_TPINPUT) 138836401Ssklower printf( "tp_input: before driver, state 0x%x event 0x%x m 0x%x", 138936401Ssklower tpcb->tp_state, e.ev_number, m ); 139036401Ssklower printf(" e.e_data 0x%x\n", e.ATTR(DT_TPDU).e_data); 139136401Ssklower printf("takes_data 0x%x m_len 0x%x, tpdu_len 0x%x\n", 139236401Ssklower takes_data, (m==MNULL)?0:m->m_len, tpdu_len); 139336401Ssklower ENDDEBUG 139436401Ssklower 139536401Ssklower error = tp_driver(tpcb, &e); 139636401Ssklower 139736401Ssklower ASSERT(tpcb != (struct tp_pcb *)0); 139836401Ssklower ASSERT(tpcb->tp_sock != (struct socket *)0); 139936401Ssklower if( tpcb->tp_sock->so_error == 0 ) 140036401Ssklower tpcb->tp_sock->so_error = error; 140136401Ssklower 140236401Ssklower /* Kludge to keep the state tables under control (adding 140336401Ssklower * data on connect & disconnect & freeing the mbuf containing 140436401Ssklower * the data would have exploded the tables and made a big mess ). 140536401Ssklower */ 140636401Ssklower switch(e.ev_number) { 140736401Ssklower case CC_TPDU: 140836401Ssklower case DR_TPDU: 140936401Ssklower case CR_TPDU: 141036401Ssklower m = e.ATTR(CC_TPDU).e_data; /* same field for all three dutypes */ 141136401Ssklower IFDEBUG(D_TPINPUT) 141236401Ssklower printf("after driver, restoring m to 0x%x, takes_data 0x%x\n", 141336401Ssklower m, takes_data); 141436401Ssklower ENDDEBUG 141536401Ssklower break; 141636401Ssklower default: 141736401Ssklower break; 141836401Ssklower } 141936401Ssklower /* Concatenated sequences are terminated by any tpdu that 142036401Ssklower * carries data: CR, CC, DT, XPD, DR. 142136401Ssklower * All other tpdu types may be concatenated: AK, XAK, DC, ER. 142236401Ssklower */ 142336401Ssklower 142436401Ssklower separate: 142536401Ssklower if ( takes_data == 0 ) { 142636401Ssklower ASSERT( m != MNULL ); 142736401Ssklower /* 142836401Ssklower * we already peeled off the prev. tp header so 142936401Ssklower * we can just pull up some more and repeat 143036401Ssklower */ 143136401Ssklower 143237469Ssklower if( m = tp_inputprep(m) ) { 143336401Ssklower IFDEBUG(D_TPINPUT) 143436401Ssklower hdr = mtod(m, struct tpdu *); 143536401Ssklower printf("tp_input @ separate: hdr 0x%x size %d m 0x%x\n", 143636401Ssklower hdr, (int) hdr->tpdu_li + 1, m); 143736401Ssklower dump_mbuf(m, "tp_input after driver, at separate"); 143836401Ssklower ENDDEBUG 143936401Ssklower 144036401Ssklower IncStat(ts_concat_rcvd); 144136401Ssklower goto again; 144236401Ssklower } 144336401Ssklower } 144436401Ssklower if ( m != MNULL ) { 144536401Ssklower IFDEBUG(D_TPINPUT) 144636401Ssklower printf("tp_input : m_freem(0x%x)\n", m); 144736401Ssklower ENDDEBUG 144836401Ssklower m_freem(m); 144936401Ssklower IFDEBUG(D_TPINPUT) 145036401Ssklower printf("tp_input : after m_freem 0x%x\n", m); 145136401Ssklower ENDDEBUG 145236401Ssklower } 145336401Ssklower return (ProtoHook) tpcb; 145436401Ssklower 145536401Ssklower discard: 145636401Ssklower /* class 4: drop the tpdu */ 145736401Ssklower /* class 2,0: Should drop the net connection, if you can figure out 145836401Ssklower * to which connection it applies 145936401Ssklower */ 146036401Ssklower IFDEBUG(D_TPINPUT) 146136401Ssklower printf("tp_input DISCARD\n"); 146236401Ssklower ENDDEBUG 146336401Ssklower IFTRACE(D_TPINPUT) 146436401Ssklower tptrace(TPPTmisc, "tp_input DISCARD m", m,0,0,0); 146536401Ssklower ENDTRACE 146636401Ssklower m_freem(m); 146736401Ssklower IncStat(ts_recv_drop); 146836401Ssklower return (ProtoHook)0; 146936401Ssklower 147036401Ssklower respond: 147136401Ssklower IFDEBUG(D_ERROR_EMIT) 147236401Ssklower printf("RESPOND: error 0x%x, errloc 0x%x\n", error, errloc); 147336401Ssklower ENDDEBUG 147436401Ssklower IFTRACE(D_TPINPUT) 147536401Ssklower tptrace(TPPTmisc, "tp_input RESPOND m error sref", m,error,sref,0); 147636401Ssklower ENDTRACE 147736401Ssklower if( sref == 0 ) 147836401Ssklower goto discard; 147937469Ssklower (void) tp_error_emit(error, (u_long)sref, (struct sockaddr_iso *)faddr, 148037469Ssklower (struct sockaddr_iso *)laddr, m, (int)errloc, tpcb, 148137469Ssklower (int)cons_channel, dgout_routine); 148236401Ssklower IFDEBUG(D_ERROR_EMIT) 148336401Ssklower printf("tp_input after error_emit\n"); 148436401Ssklower ENDDEBUG 148536401Ssklower 148636401Ssklower #ifdef lint 148736401Ssklower printf("",sref,opt); 148836401Ssklower #endif lint 148936401Ssklower IncStat(ts_recv_drop); 149036401Ssklower return (ProtoHook)0; 149136401Ssklower } 149236401Ssklower 149336401Ssklower 149436401Ssklower /* 149536401Ssklower * NAME: tp_headersize() 149636401Ssklower * 149736401Ssklower * CALLED FROM: 149836401Ssklower * tp_emit() and tp_sbsend() 149936401Ssklower * TP needs to know the header size so it can figure out how 150036401Ssklower * much data to put in each tpdu. 150136401Ssklower * 150236401Ssklower * FUNCTION, ARGUMENTS, and RETURN VALUE: 150336401Ssklower * For a given connection, represented by (tpcb), and 150436401Ssklower * tpdu type (dutype), return the size of a tp header. 150536401Ssklower * 150636401Ssklower * RETURNS: the expected size of the heade in bytesr 150736401Ssklower * 150836401Ssklower * SIDE EFFECTS: 150936401Ssklower * 151036401Ssklower * NOTES: It would be nice if it got the network header size as well. 151136401Ssklower */ 151236401Ssklower int 151336401Ssklower tp_headersize(dutype, tpcb) 151436401Ssklower int dutype; 151536401Ssklower struct tp_pcb *tpcb; 151636401Ssklower { 151736401Ssklower register int size = 0; 151836401Ssklower 151936401Ssklower IFTRACE(D_CONN) 152036401Ssklower tptrace(TPPTmisc, "tp_headersize dutype class xtd_format", 152136401Ssklower dutype, tpcb->tp_class, tpcb->tp_xtd_format, 0); 152236401Ssklower ENDTRACE 152336401Ssklower if( !( (tpcb->tp_class == TP_CLASS_0) || 152436401Ssklower (tpcb->tp_class == TP_CLASS_4) || 152536401Ssklower (dutype == DR_TPDU_type) || 152636401Ssklower (dutype == CR_TPDU_type) )) { 152736401Ssklower printf("tp_headersize:dutype 0x%x, class 0x%x", 152836401Ssklower dutype, tpcb->tp_class); 152936401Ssklower /* TODO: identify this and GET RID OF IT */ 153036401Ssklower } 153136401Ssklower ASSERT( (tpcb->tp_class == TP_CLASS_0) || 153236401Ssklower (tpcb->tp_class == TP_CLASS_4) || 153336401Ssklower (dutype == DR_TPDU_type) || 153436401Ssklower (dutype == CR_TPDU_type) ); 153536401Ssklower 153636401Ssklower if( tpcb->tp_class == TP_CLASS_0 ) { 153736401Ssklower size = tpdu_info[ dutype ] [TP_LEN_CLASS_0_INDEX]; 153836401Ssklower } else { 153936401Ssklower size = tpdu_info[ dutype ] [tpcb->tp_xtd_format]; 154036401Ssklower } 154136401Ssklower return size; 154236401Ssklower /* caller must get network level header size separately */ 154336401Ssklower } 1544