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*42491Ssklower * @(#)tp_input.c 7.9 (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; 383*42491Ssklower u_char opt, dusize, addlopt, version; 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 */ 562*42491Ssklower /* Iso says if version wrong, use default version????? */ 56336401Ssklower CHECK( (vbval(P, u_char) != TP_VERSION ), 564*42491Ssklower E_TP_INV_PVAL, ts_inv_pval, setversion, 565*42491Ssklower (1 + (caddr_t)&vbptr(P)->tpv_val - P) ); 566*42491Ssklower setversion: 567*42491Ssklower version = vbval(P, u_char); 568*42491Ssklower 56936401Ssklower break; 57036401Ssklower case TPP_acktime: 57136401Ssklower vb_getval(P, u_short, acktime); 57236401Ssklower acktime = ntohs(acktime); 57336401Ssklower acktime = acktime/500; /* convert to slowtimo ticks */ 57436401Ssklower if((short)acktime <=0 ) 57536401Ssklower acktime = 2; /* don't allow a bad peer to screw us up */ 57636401Ssklower IFDEBUG(D_TPINPUT) 57736401Ssklower printf("CR acktime 0x%x\n", acktime); 57836401Ssklower ENDDEBUG 57936401Ssklower break; 58036401Ssklower 58136401Ssklower case TPP_alt_class: 58236401Ssklower { 58336401Ssklower u_char *aclass = 0; 58436401Ssklower register int i; 58536401Ssklower 58636401Ssklower for (i = ((struct tp_vbp *)P)->tpv_len; i>0; i--) { 58736401Ssklower aclass = 58836401Ssklower (u_char *) &(((struct tp_vbp *)P)->tpv_val); 58937469Ssklower alt_classes |= (1<<((*aclass)>>4)); 59036401Ssklower } 59136401Ssklower IFDEBUG(D_TPINPUT) 59236401Ssklower printf("alt_classes 0x%x\n", alt_classes); 59336401Ssklower ENDDEBUG 59436401Ssklower } 59536401Ssklower break; 59636401Ssklower 59736401Ssklower case TPP_security: 59836401Ssklower case TPP_residER: 59936401Ssklower case TPP_priority: 60036401Ssklower case TPP_transdelay: 60136401Ssklower case TPP_throughput: 60236401Ssklower case TPP_addl_info: 60336401Ssklower case TPP_subseq: 60436401Ssklower IFDEBUG(D_TPINPUT) 60536401Ssklower printf("param ignored CR_TPDU code= 0x%x\n", 60636401Ssklower vbptr(P)->tpv_code); 60736401Ssklower ENDDEBUG 60836401Ssklower IncStat(ts_param_ignored); 60936401Ssklower break; 61036401Ssklower 61136401Ssklower case TPP_checksum: 61236401Ssklower IFDEBUG(D_TPINPUT) 61336401Ssklower printf("CR before cksum\n"); 61436401Ssklower ENDDEBUG 61536401Ssklower 61636401Ssklower CHECK( iso_check_csum(m, tpdu_len), 61736401Ssklower E_TP_INV_PVAL, ts_bad_csum, discard, 0) 61836401Ssklower 61936401Ssklower IFDEBUG(D_TPINPUT) 62036401Ssklower printf("CR before cksum\n"); 62136401Ssklower ENDDEBUG 62236401Ssklower break; 62336401Ssklower 62436401Ssklower default: 62536401Ssklower IncStat(ts_inv_pcode); 62636401Ssklower error = E_TP_INV_PCODE; 62736401Ssklower goto discard; 62836401Ssklower 62936401Ssklower } 63036401Ssklower 63136401Ssklower /* } */ END_WHILE_OPTIONS(P) 63236401Ssklower 63336401Ssklower if( lsufxlen == 0) { 63436401Ssklower /* can't look for a tpcb w/o any called sufx */ 63536401Ssklower error = E_TP_LENGTH_INVAL; 63636401Ssklower IncStat(ts_inv_sufx); 63736401Ssklower goto respond; 63836401Ssklower } else { 63936401Ssklower register struct tp_ref *rp; 64036401Ssklower register int r; 64136401Ssklower extern int tp_maxrefopen; 64236401Ssklower 64336401Ssklower rp = &tp_ref[1]; /* zero-th one is never open */ 64436401Ssklower for( r=1 ; (r <= tp_maxrefopen) ; r++,rp++ ) { 64536401Ssklower if (rp->tpr_state!=REF_OPENING) 64636401Ssklower continue; 64736401Ssklower if ( bcmp(lsufxloc, rp->tpr_pcb->tp_lsuffix, lsufxlen)==0 ) { 64836401Ssklower tpcb = rp->tpr_pcb; 64936401Ssklower if( laddr->sa_family != 65036401Ssklower tpcb->tp_sock->so_proto->pr_domain->dom_family ) { 65136401Ssklower IFDEBUG(D_CONN) 65236401Ssklower printf( 65336401Ssklower "MISMATCHED AF on CR! laddr.family 0x%x expected 0x%x\n", 65436401Ssklower laddr->sa_family, 65536401Ssklower tpcb->tp_sock->so_proto->pr_domain->dom_family ); 65636401Ssklower ENDDEBUG 65736401Ssklower continue; 65836401Ssklower } 65936401Ssklower IFTRACE(D_TPINPUT) 66036401Ssklower tptrace(TPPTmisc, "tp_input: ref *lsufxloc refstate", 66136401Ssklower r, *lsufxloc, rp->tpr_state, 0); 66236401Ssklower ENDTRACE 66336401Ssklower /* found it */ 66436401Ssklower break; 66536401Ssklower } 66636401Ssklower } 66736401Ssklower 66836401Ssklower CHECK( (r > tp_maxrefopen), E_TP_NO_SESSION, ts_inv_sufx, respond, 66936401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 67036401Ssklower /* _tpduf is the fixed part; add 2 to get the dref bits of 67136401Ssklower * the fixed part (can't take the address of a bit field) 67236401Ssklower */ 67336401Ssklower } 67436401Ssklower 67536401Ssklower /* 67636401Ssklower * WE HAVE A TPCB 67736401Ssklower * already know that the classes in the CR match at least 67836401Ssklower * one class implemented, but we don't know yet if they 67936401Ssklower * include any classes permitted by this server. 68036401Ssklower */ 68136401Ssklower 68236401Ssklower IFDEBUG(D_TPINPUT) 68336401Ssklower printf("HAVE A TPCB 1: 0x%x\n", tpcb); 68436401Ssklower ENDDEBUG 68536401Ssklower IFDEBUG(D_CONN) 68636401Ssklower printf( 68736401Ssklower "CR: bef CHKS: flags 0x%x class_to_use 0x%x alt 0x%x opt 0x%x tp_class 0x%x\n", 68836401Ssklower tpcb->tp_flags, class_to_use, alt_classes, opt, tpcb->tp_class); 68936401Ssklower ENDDEBUG 69036401Ssklower /* tpcb->tp_class doesn't include any classes not implemented */ 69136401Ssklower class_to_use = (preferred_class & tpcb->tp_class); 69236401Ssklower if( (class_to_use = preferred_class & tpcb->tp_class) == 0 ) 69336401Ssklower class_to_use = alt_classes & tpcb->tp_class; 69436401Ssklower 69536401Ssklower class_to_use = 1 << tp_mask_to_num(class_to_use); 69636401Ssklower 69736401Ssklower { 69836401Ssklower tpp = tpcb->_tp_param; 69936401Ssklower tpp.p_class = class_to_use; 70036401Ssklower tpp.p_tpdusize = dusize; 70136401Ssklower tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT; 70236401Ssklower tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD; 70336401Ssklower tpp.p_use_checksum = (tpp.p_class == TP_CLASS_0)?0: 70436401Ssklower (addlopt & TPAO_NO_CSUM) == 0; 705*42491Ssklower tpp.p_version = version; 70636401Ssklower #ifdef notdef 70736401Ssklower tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC; 70836401Ssklower tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD; 70936401Ssklower tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC; 71036401Ssklower #endif notdef 71136401Ssklower 71236401Ssklower CHECK( 71336401Ssklower tp_consistency(tpcb, 0 /* not force or strict */, &tpp) != 0, 71436401Ssklower E_TP_NEGOT_FAILED, ts_negotfailed, respond, 71536401Ssklower (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 71636401Ssklower /* ^ more or less the location of class */ 71736401Ssklower ) 71836401Ssklower } 71936401Ssklower IFTRACE(D_CONN) 72036401Ssklower tptrace(TPPTmisc, 72136401Ssklower "after 1 consist class_to_use class, out, tpconsout", 72236401Ssklower class_to_use, 72336401Ssklower tpcb->tp_class, dgout_routine, tpcons_output 72436401Ssklower ); 72536401Ssklower ENDTRACE 72636401Ssklower CHECK( 72736401Ssklower ((class_to_use == TP_CLASS_0)&&(dgout_routine != tpcons_output)), 72836401Ssklower E_TP_NEGOT_FAILED, ts_negotfailed, respond, 72936401Ssklower (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 73036401Ssklower /* ^ more or less the location of class */ 73136401Ssklower ) 73236401Ssklower IFDEBUG(D_CONN) 73336401Ssklower printf("CR: after CRCCCHECKS: tpcb 0x%x, flags 0x%x\n", 73436401Ssklower tpcb, tpcb->tp_flags); 73536401Ssklower ENDDEBUG 73636401Ssklower takes_data = TRUE; 73736401Ssklower e.ATTR(CR_TPDU).e_cdt = hdr->tpdu_CRcdt; 73836401Ssklower e.ev_number = CR_TPDU; 73936401Ssklower 74036401Ssklower so = tpcb->tp_sock; 74136401Ssklower if (so->so_options & SO_ACCEPTCONN) { 74236401Ssklower /* 74336401Ssklower * Create a socket, tpcb, ll pcb, etc. 74436401Ssklower * for this newborn connection, and fill in all the values. 74536401Ssklower */ 74636401Ssklower IFDEBUG(D_CONN) 74736401Ssklower printf("abt to call tp_newsocket(0x%x, 0x%x, 0x%x, 0x%x)\n", 74836401Ssklower so, laddr, faddr, cons_channel); 74936401Ssklower ENDDEBUG 75036401Ssklower if( (so = 75136401Ssklower tp_newsocket(so, faddr, cons_channel, 75236401Ssklower class_to_use, 75337469Ssklower ((tpcb->tp_netservice == IN_CLNS) ? IN_CLNS : 75437469Ssklower (dgout_routine == tpcons_output)?ISO_CONS:ISO_CLNS)) 75536401Ssklower ) == (struct socket *)0 ) { 75636401Ssklower /* note - even if netservice is IN_CLNS, as far as 75736401Ssklower * the tp entity is concerned, the only differences 75837469Ssklower * are CO vs CL 75936401Ssklower */ 76036401Ssklower IFDEBUG(D_CONN) 76136401Ssklower printf("tp_newsocket returns 0\n"); 76236401Ssklower ENDDEBUG 76336401Ssklower goto discard; 76436401Ssklower } 76536401Ssklower tpcb = sototpcb(so); 76636401Ssklower 76736401Ssklower /* 76837469Ssklower * Stash the addresses in the net level pcb 76936401Ssklower * kind of like a pcbconnect() but don't need 77036401Ssklower * or want all those checks. 77136401Ssklower */ 77236401Ssklower (tpcb->tp_nlproto->nlp_putnetaddr)(so->so_pcb, faddr, TP_FOREIGN); 77336401Ssklower (tpcb->tp_nlproto->nlp_putnetaddr)(so->so_pcb, laddr, TP_LOCAL); 77436401Ssklower 77537469Ssklower /* stash the f suffix in the new tpcb */ 77637469Ssklower /* l suffix is already there */ 77738841Ssklower bcopy(fsufxloc, tpcb->tp_fsuffix, fsufxlen); 77836401Ssklower 77937469Ssklower (tpcb->tp_nlproto->nlp_putsufx) 78037469Ssklower (so->so_pcb, fsufxloc, fsufxlen, TP_FOREIGN); 78138841Ssklower (tpcb->tp_nlproto->nlp_putsufx) 78238841Ssklower (so->so_pcb, lsufxloc, lsufxlen, TP_LOCAL); 78337469Ssklower 78436401Ssklower #ifdef TP_PERF_MEAS 78536401Ssklower if( tpcb->tp_perf_on = perf_meas ) { /* assignment */ 78636401Ssklower /* ok, let's create an mbuf for stashing the 78736401Ssklower * statistics if one doesn't already exist 78836401Ssklower */ 78936401Ssklower (void) tp_setup_perf(tpcb); 79036401Ssklower } 79136401Ssklower #endif TP_PERF_MEAS 79236401Ssklower tpcb->tp_fref = sref; 79336401Ssklower 79436401Ssklower /* We've already checked for consistency with the options 79536401Ssklower * set in tpp, but we couldn't set them earlier because 79636401Ssklower * we didn't want to change options in the LISTENING tpcb. 79736401Ssklower * Now we set the options in the new socket's tpcb. 79836401Ssklower */ 79936401Ssklower (void) tp_consistency( tpcb, TP_FORCE, &tpp); 80036401Ssklower 80136401Ssklower if(!tpcb->tp_use_checksum) 80236401Ssklower IncStat(ts_csum_off); 80336401Ssklower if(tpcb->tp_xpd_service) 80436401Ssklower IncStat(ts_use_txpd); 80536401Ssklower if(tpcb->tp_xtd_format) 80636401Ssklower IncStat(ts_xtd_fmt); 80736401Ssklower 80836401Ssklower /* 80936401Ssklower * Get the maximum transmission unit from the lower layer(s) 81036401Ssklower * so we can negotiate a reasonable max TPDU size. 81136401Ssklower */ 81236401Ssklower (tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb, 81336401Ssklower &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0); 81436401Ssklower tpcb->tp_peer_acktime = acktime; 81536401Ssklower 81636401Ssklower /* 81736401Ssklower * The following kludge is used to test retransmissions and 81836401Ssklower * timeout during connection establishment. 81936401Ssklower */ 82036401Ssklower IFDEBUG(D_ZDREF) 82136401Ssklower IncStat(ts_zdebug); 82237469Ssklower /*tpcb->tp_fref = 0;*/ 82336401Ssklower ENDDEBUG 82436401Ssklower } 82536401Ssklower IncStat(ts_CR_rcvd); 82639929Ssklower if (!tpcb->tp_cebit_off) { 82739929Ssklower tpcb->tp_win_recv = tp_start_win << 8; 82839929Ssklower tpcb->tp_cong_sample.cs_size = 0; 82939929Ssklower LOCAL_CREDIT(tpcb); 83039929Ssklower CONG_INIT_SAMPLE(tpcb); 83139929Ssklower CONG_UPDATE_SAMPLE(tpcb, ce_bit); 83239929Ssklower } 83339929Ssklower tpcb->tp_ackrcvd = 0; 83436401Ssklower } else if ( dutype == ER_TPDU_type ) { 83536401Ssklower /* 83636401Ssklower * ER TPDUs have to be recognized separately 83736401Ssklower * because they don't necessarily have a tpcb 83836401Ssklower * with them and we don't want err out looking for such 83936401Ssklower * a beast. 84036401Ssklower * We could put a bunch of little kludges in the 84136401Ssklower * next section of code so it would avoid references to tpcb 84236401Ssklower * if dutype == ER_TPDU_type but we don't want code for ERs to 84336401Ssklower * mess up code for data transfer. 84436401Ssklower */ 84536401Ssklower IncStat(ts_ER_rcvd); 84636401Ssklower e.ev_number = ER_TPDU; 84736401Ssklower e.ATTR(ER_TPDU).e_reason = (u_char)hdr->tpdu_ERreason; 84836401Ssklower takes_data = 1; 84936401Ssklower } else { 85036401Ssklower /* tpdu type is CC, XPD, XAK, GR, AK, DR, DC, or DT */ 85136401Ssklower 85236401Ssklower /* In the next 4 checks, 85336401Ssklower * _tpduf is the fixed part; add 2 to get the dref bits of 85436401Ssklower * the fixed part (can't take the address of a bit field) 85536401Ssklower */ 85636401Ssklower if(cons_channel) { 85736401Ssklower #if NARGOXTWENTYFIVE > 0 85836401Ssklower extern struct tp_pcb *cons_chan_to_tpcb(); 85936401Ssklower 86036401Ssklower tpcb = cons_chan_to_tpcb( cons_channel ); 86136401Ssklower /* Problem: We may have a legit 86236401Ssklower * error situation yet we may or may not have 86336401Ssklower * a correspondence between the tpcb and the vc, 86436401Ssklower * e.g., TP4cr--> <no dice, respond w/ DR on vc> 86536401Ssklower * <--- DR 86636401Ssklower * Now it's up to TP to look at the tpdu and do one of: 86736401Ssklower * confirm(dgm)(cr), confirm(circuit)(cr), reject(cr), or 86836401Ssklower * nothing, if the circuit is already open (any other tpdu). 86936401Ssklower * Sigh. 87036401Ssklower */ 87136401Ssklower 87236401Ssklower /* I don't know about this error value */ 87336401Ssklower CHECK( (tpcb == (struct tp_pcb *)0) , 87436401Ssklower E_TP_NO_CR_ON_NC, ts_inv_dref, respond, 87536401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 87636401Ssklower #else 87736401Ssklower printf("tp_input(): X25 NOT CONFIGURED!!\n"); 87836401Ssklower #endif NARGOXTWENTYFIVE > 0 87936401Ssklower 88036401Ssklower } else { 88136401Ssklower 88236401Ssklower CHECK( ((int)dref <= 0 || dref >= N_TPREF) , 88336401Ssklower E_TP_MISM_REFS,ts_inv_dref, respond, 88436401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 88536401Ssklower CHECK( ((tpcb = tp_ref[dref].tpr_pcb ) == (struct tp_pcb *) 0 ), 88636401Ssklower E_TP_MISM_REFS,ts_inv_dref, respond, 88736401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 88836401Ssklower CHECK( (tpcb->tp_refp->tpr_state == REF_FREE), 88936401Ssklower E_TP_MISM_REFS,ts_inv_dref, respond, 89036401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 89136401Ssklower } 89236401Ssklower 89336401Ssklower IFDEBUG(D_TPINPUT) 89436401Ssklower printf("HAVE A TPCB 2: 0x%x\n", tpcb); 89536401Ssklower ENDDEBUG 89636401Ssklower 89736401Ssklower /* causes a DR to be sent for CC; ER for all else */ 89836401Ssklower CHECK( (tpcb->tp_refp->tpr_state == REF_FROZEN), 89936401Ssklower (dutype == CC_TPDU_type?E_TP_NO_SESSION:E_TP_MISM_REFS), 90036401Ssklower ts_inv_dref, respond, 90136401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 90236401Ssklower 90336401Ssklower IFDEBUG(D_TPINPUT) 90436401Ssklower printf("state of dref %d ok, tpcb 0x%x\n", dref,tpcb); 90536401Ssklower ENDDEBUG 90636401Ssklower /* 90736401Ssklower * At this point the state of the dref could be 90836401Ssklower * FROZEN: tpr_pcb == NULL, has ( reference only) timers 90936401Ssklower * for example, DC may arrive after the close() has detached 91036401Ssklower * the tpcb (e.g., if user turned off SO_LISTEN option) 91136401Ssklower * OPENING : a tpcb exists but no timers yet 91236401Ssklower * OPEN : tpcb exists & timers are outstanding 91336401Ssklower */ 91436401Ssklower 91539929Ssklower if (!tpcb->tp_cebit_off) 91639929Ssklower CONG_UPDATE_SAMPLE(tpcb, ce_bit); 91739929Ssklower 91836401Ssklower dusize = tpcb->tp_tpdusize; 91936401Ssklower 92036401Ssklower dutype = hdr->tpdu_type << 8; /* for the switch below */ 92136401Ssklower 92236401Ssklower WHILE_OPTIONS(P, hdr, tpcb->tp_xtd_format) /* { */ 92336401Ssklower 92437469Ssklower #define caseof(x,y) case (((x)<<8)+(y)) 92536401Ssklower switch( dutype | vbptr(P)->tpv_code ) { 92636401Ssklower 92736401Ssklower caseof( CC_TPDU_type, TPP_addl_opt ): 92836401Ssklower /* not in class 0; 1 octet */ 92936401Ssklower vb_getval(P, u_char, addlopt); 93036401Ssklower break; 93136401Ssklower caseof( CC_TPDU_type, TPP_tpdu_size ): 93236401Ssklower vb_getval(P, u_char, dusize); 93336401Ssklower CHECK( (dusize < TP_MIN_TPDUSIZE || dusize > 93436401Ssklower TP_MAX_TPDUSIZE), E_TP_INV_PVAL, ts_inv_pval, respond, 93536401Ssklower (1 + (caddr_t)&vbptr(P)->tpv_val - P) ) 93636401Ssklower IFDEBUG(D_TPINPUT) 93736401Ssklower printf("CC dusize 0x%x\n", dusize); 93836401Ssklower ENDDEBUG 93936401Ssklower break; 94036401Ssklower caseof( CC_TPDU_type, TPP_calling_sufx): 94136401Ssklower IFDEBUG(D_TPINPUT) 94236401Ssklower printf("CC calling (local) sufxlen 0x%x\n", lsufxlen); 94336401Ssklower ENDDEBUG 94436401Ssklower lsufxloc = (caddr_t) &vbptr(P)->tpv_val; 94536401Ssklower lsufxlen = vbptr(P)->tpv_len; 94636401Ssklower break; 94736401Ssklower caseof( CC_TPDU_type, TPP_acktime ): 94836401Ssklower /* class 4 only, 2 octets */ 94936401Ssklower vb_getval(P, u_short, acktime); 95036401Ssklower acktime = acktime/500; /* convert to slowtimo ticks */ 95136401Ssklower if( (short)acktime <=0 ) 95236401Ssklower acktime = 2; 95336401Ssklower break; 95436401Ssklower caseof( CC_TPDU_type, TPP_called_sufx): 95536401Ssklower fsufxloc = (caddr_t) &vbptr(P)->tpv_val; 95636401Ssklower fsufxlen = vbptr(P)->tpv_len; 95736401Ssklower IFDEBUG(D_TPINPUT) 95836401Ssklower printf("CC called (foreign) sufx len %d\n", fsufxlen); 95936401Ssklower ENDDEBUG 96036401Ssklower break; 96136401Ssklower 96236401Ssklower caseof( CC_TPDU_type, TPP_checksum): 96336401Ssklower caseof( DR_TPDU_type, TPP_checksum): 96436401Ssklower caseof( DT_TPDU_type, TPP_checksum): 96536401Ssklower caseof( XPD_TPDU_type, TPP_checksum): 96636401Ssklower if( tpcb->tp_use_checksum ) { 96736401Ssklower CHECK( iso_check_csum(m, tpdu_len), 96836401Ssklower E_TP_INV_PVAL, ts_bad_csum, discard, 0) 96936401Ssklower } 97036401Ssklower break; 97136401Ssklower 97236401Ssklower /* this is different from the above because in the context 97336401Ssklower * of concat/ sep tpdu_len might not be the same as hdr len 97436401Ssklower */ 97536401Ssklower caseof( AK_TPDU_type, TPP_checksum): 97636401Ssklower caseof( XAK_TPDU_type, TPP_checksum): 97736401Ssklower caseof( DC_TPDU_type, TPP_checksum): 97836401Ssklower if( tpcb->tp_use_checksum ) { 97937469Ssklower CHECK( iso_check_csum(m, (int)hdr->tpdu_li + 1), 98036401Ssklower E_TP_INV_PVAL, ts_bad_csum, discard, 0) 98136401Ssklower } 98236401Ssklower break; 98336401Ssklower #ifdef notdef 98436401Ssklower caseof( DR_TPDU_type, TPP_addl_info ): 98536401Ssklower /* ignore - its length and meaning are 98636401Ssklower * user defined and there's no way 98736401Ssklower * to pass this info to the user anyway 98836401Ssklower */ 98936401Ssklower break; 99036401Ssklower #endif notdef 99136401Ssklower 99236401Ssklower caseof( AK_TPDU_type, TPP_subseq ): 99336401Ssklower /* used after reduction of window */ 99436401Ssklower vb_getval(P, u_short, subseq); 99536401Ssklower subseq = ntohs(subseq); 99636401Ssklower IFDEBUG(D_ACKRECV) 99736401Ssklower printf("AK Subsequence # 0x%x\n", subseq); 99836401Ssklower ENDDEBUG 99936401Ssklower break; 100036401Ssklower 100136401Ssklower caseof( AK_TPDU_type, TPP_flow_cntl_conf ): 100236401Ssklower { 100336401Ssklower u_int ylwe; 100436401Ssklower u_short ysubseq, ycredit; 100536401Ssklower 100636401Ssklower fcc_present = TRUE; 100736401Ssklower vb_getval(P, u_int, ylwe); 100836401Ssklower vb_getval(P, u_short, ysubseq); 100936401Ssklower vb_getval(P, u_short, ycredit); 101036401Ssklower ylwe = ntohl(ylwe); 101136401Ssklower ysubseq = ntohs(ysubseq); 101236401Ssklower ycredit = ntohs(ycredit); 101336401Ssklower IFDEBUG(D_ACKRECV) 101436401Ssklower printf("AK FCC lwe 0x%x, subseq 0x%x, cdt 0x%x\n", 101536401Ssklower ylwe, ysubseq, ycredit); 101636401Ssklower ENDDEBUG 101736401Ssklower } 101836401Ssklower break; 101936401Ssklower 102036401Ssklower default: 102136401Ssklower IFDEBUG(D_TPINPUT) 102236401Ssklower printf("param ignored dutype 0x%x, code 0x%x\n", 102336401Ssklower dutype, vbptr(P)->tpv_code); 102436401Ssklower ENDDEBUG 102536401Ssklower IFTRACE(D_TPINPUT) 102636401Ssklower tptrace(TPPTmisc, "param ignored dutype code ", 102736401Ssklower dutype, vbptr(P)->tpv_code ,0,0); 102836401Ssklower ENDTRACE 102936401Ssklower IncStat(ts_param_ignored); 103036401Ssklower break; 103136401Ssklower #undef caseof 103236401Ssklower } 103336401Ssklower /* } */ END_WHILE_OPTIONS(P) 103436401Ssklower 103536401Ssklower /* NOTE: the variable dutype has been shifted left! */ 103636401Ssklower 103736401Ssklower switch( hdr->tpdu_type ) { 103836401Ssklower case CC_TPDU_type: 103936401Ssklower /* If CC comes back with an unacceptable class 104036401Ssklower * respond with a DR or ER 104136401Ssklower */ 104236401Ssklower 104336401Ssklower opt = hdr->tpdu_CCoptions; /* 1 byte */ 104436401Ssklower 104536401Ssklower { 104636401Ssklower tpp = tpcb->_tp_param; 104736401Ssklower tpp.p_class = (1<<hdr->tpdu_CCclass); 104836401Ssklower tpp.p_tpdusize = dusize; 104936401Ssklower tpp.p_dont_change_params = 0; 105036401Ssklower tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT; 105136401Ssklower tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD; 105236401Ssklower tpp.p_use_checksum = (addlopt & TPAO_NO_CSUM) == 0; 105336401Ssklower #ifdef notdef 105436401Ssklower tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC; 105536401Ssklower tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD; 105636401Ssklower tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC; 105736401Ssklower #endif notdef 105836401Ssklower 105936401Ssklower CHECK( 106036401Ssklower tp_consistency(tpcb, TP_FORCE, &tpp) != 0, 106136401Ssklower E_TP_NEGOT_FAILED, ts_negotfailed, respond, 106236401Ssklower (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 106336401Ssklower /* ^ more or less the location of class */ 106436401Ssklower ) 106536401Ssklower IFTRACE(D_CONN) 106636401Ssklower tptrace(TPPTmisc, 106736401Ssklower "after 1 consist class, out, tpconsout", 106836401Ssklower tpcb->tp_class, dgout_routine, tpcons_output, 0 106936401Ssklower ); 107036401Ssklower ENDTRACE 107136401Ssklower CHECK( 107236401Ssklower ((class_to_use == TP_CLASS_0)&& 107336401Ssklower (dgout_routine != tpcons_output)), 107436401Ssklower E_TP_NEGOT_FAILED, ts_negotfailed, respond, 107536401Ssklower (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 107636401Ssklower /* ^ more or less the location of class */ 107736401Ssklower ) 107836401Ssklower } 107936401Ssklower if( ! tpcb->tp_use_checksum) 108036401Ssklower IncStat(ts_csum_off); 108136401Ssklower if(tpcb->tp_xpd_service) 108236401Ssklower IncStat(ts_use_txpd); 108336401Ssklower if(tpcb->tp_xtd_format) 108436401Ssklower IncStat(ts_xtd_fmt); 108536401Ssklower 108636401Ssklower IFTRACE(D_CONN) 108736401Ssklower tptrace(TPPTmisc, "after CC class flags dusize CCclass", 108836401Ssklower tpcb->tp_class, tpcb->tp_flags, tpcb->tp_tpdusize, 108936401Ssklower hdr->tpdu_CCclass); 109036401Ssklower ENDTRACE 109136401Ssklower 109236401Ssklower /* 109336401Ssklower * Get the maximum transmission unit from the lower layer(s) 109436401Ssklower * so we can decide how large a TPDU size to negotiate. 109536401Ssklower * It would be nice if the arguments to this 109636401Ssklower * were more reasonable. 109736401Ssklower */ 109836401Ssklower (tpcb->tp_nlproto->nlp_mtu)(tpcb->tp_sock, tpcb->tp_sock->so_pcb, 109936401Ssklower &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0); 110036401Ssklower 110136401Ssklower #ifdef CONS 110236401Ssklower /* Could be that this CC came in on a NEW vc, in which case 110336401Ssklower * we have to confirm it. 110436401Ssklower */ 110536401Ssklower if( cons_channel ) 110636401Ssklower cons_netcmd( CONN_CONFIRM, tpcb->tp_npcb, cons_channel, 110736401Ssklower tpcb->tp_class == TP_CLASS_4); 110836401Ssklower #endif CONS 110936401Ssklower 111036401Ssklower tpcb->tp_peer_acktime = acktime; 111136401Ssklower 111236401Ssklower /* if called or calling suffices appeared on the CC, 111336401Ssklower * they'd better jive with what's in the pcb 111436401Ssklower */ 111536401Ssklower if( fsufxlen ) { 111636401Ssklower CHECK( ((tpcb->tp_fsuffixlen != fsufxlen) || 111736401Ssklower bcmp(fsufxloc, tpcb->tp_fsuffix, fsufxlen)), 111836401Ssklower E_TP_INV_PVAL,ts_inv_sufx, respond, 111936401Ssklower (1+fsufxloc - (caddr_t)hdr)) 112036401Ssklower } 112136401Ssklower if( lsufxlen ) { 112236401Ssklower CHECK( ((tpcb->tp_lsuffixlen != lsufxlen) || 112336401Ssklower bcmp(lsufxloc, tpcb->tp_lsuffix, lsufxlen)), 112436401Ssklower E_TP_INV_PVAL,ts_inv_sufx, respond, 112536401Ssklower (1+lsufxloc - (caddr_t)hdr)) 112636401Ssklower } 112736401Ssklower 112836401Ssklower #ifdef notdef 112936401Ssklower e.ATTR(CC_TPDU).e_sref = (u_short)hdr->tpdu_CCsref; 113036401Ssklower #else 113136401Ssklower e.ATTR(CC_TPDU).e_sref = sref; 113236401Ssklower #endif notdef 113336401Ssklower e.ATTR(CC_TPDU).e_cdt = hdr->tpdu_CCcdt; 113436401Ssklower takes_data = TRUE; 113536401Ssklower e.ev_number = CC_TPDU; 113636401Ssklower IncStat(ts_CC_rcvd); 113736401Ssklower break; 113836401Ssklower 113936401Ssklower case DC_TPDU_type: 114036401Ssklower #ifdef notdef 114136401Ssklower if (hdr->tpdu_DCsref != tpcb->tp_fref) 114236401Ssklower printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n", 114336401Ssklower hdr->tpdu_DCsref, tpcb->tp_fref); 114436401Ssklower #else 114536401Ssklower if (sref != tpcb->tp_fref) 114636401Ssklower printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n", 114736401Ssklower sref, tpcb->tp_fref); 114836401Ssklower #endif notdef 114936401Ssklower 115036401Ssklower #ifdef notdef 115136401Ssklower CHECK( (hdr->tpdu_DCsref != tpcb->tp_fref), 115236401Ssklower E_TP_MISM_REFS, ts_inv_sufx, respond, 115336401Ssklower (1 + (caddr_t)&hdr->tpdu_DCsref - (caddr_t)hdr)) 115436401Ssklower #else 115536401Ssklower CHECK( (sref != tpcb->tp_fref), 115636401Ssklower E_TP_MISM_REFS, ts_inv_sufx, respond, 115736401Ssklower (1 + (caddr_t)&hdr->tpdu_DCsref - (caddr_t)hdr)) 115836401Ssklower #endif notdef 115936401Ssklower e.ev_number = DC_TPDU; 116036401Ssklower IncStat(ts_DC_rcvd); 116136401Ssklower break; 116236401Ssklower 116336401Ssklower case DR_TPDU_type: 116436401Ssklower IFTRACE(D_TPINPUT) 116536401Ssklower tptrace(TPPTmisc, "DR recvd", hdr->tpdu_DRreason, 0, 0, 0); 116636401Ssklower ENDTRACE 116736401Ssklower #ifdef vax 116836401Ssklower if(sref != tpcb->tp_fref) 116936401Ssklower printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n", 117036401Ssklower sref, tpcb->tp_fref); 117136401Ssklower 117236401Ssklower CHECK( (sref != tpcb->tp_fref), 117336401Ssklower E_TP_MISM_REFS,ts_inv_sufx, respond, 117436401Ssklower (1 + (caddr_t)&hdr->tpdu_DRsref - (caddr_t)hdr)) 117536401Ssklower 117636401Ssklower e.ATTR(DR_TPDU).e_reason = hdr->tpdu_DRreason; 117736401Ssklower e.ATTR(DR_TPDU).e_sref = (u_short)sref; 117836401Ssklower #else 117936401Ssklower if(hdr->tpdu_DRsref != tpcb->tp_fref) 118036401Ssklower printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n", 118136401Ssklower hdr->tpdu_DRsref, tpcb->tp_fref); 118236401Ssklower 118336401Ssklower CHECK( (hdr->tpdu_DRsref != tpcb->tp_fref), 118436401Ssklower E_TP_MISM_REFS,ts_inv_sufx, respond, 118536401Ssklower (1 + (caddr_t)&hdr->tpdu_DRsref - (caddr_t)hdr)) 118636401Ssklower 118736401Ssklower e.ATTR(DR_TPDU).e_reason = 118836401Ssklower hdr->tpdu_DRreason; 118936401Ssklower e.ATTR(DR_TPDU).e_sref = (u_short)hdr->tpdu_DRsref; 119036401Ssklower #endif vax 119136401Ssklower takes_data = TRUE; 119236401Ssklower e.ev_number = DR_TPDU; 119336401Ssklower IncStat(ts_DR_rcvd); 119436401Ssklower break; 119536401Ssklower 119636401Ssklower case ER_TPDU_type: 119736401Ssklower IFTRACE(D_TPINPUT) 119836401Ssklower tptrace(TPPTmisc, "ER recvd", hdr->tpdu_ERreason,0,0,0); 119936401Ssklower ENDTRACE 120036401Ssklower e.ev_number = ER_TPDU; 120136401Ssklower e.ATTR(ER_TPDU).e_reason = hdr->tpdu_ERreason; 120236401Ssklower IncStat(ts_ER_rcvd); 120336401Ssklower break; 120436401Ssklower 120536401Ssklower case AK_TPDU_type: 120636401Ssklower 120736401Ssklower e.ATTR(AK_TPDU).e_subseq = subseq; 120836401Ssklower e.ATTR(AK_TPDU).e_fcc_present = fcc_present; 120936401Ssklower 121036401Ssklower if (tpcb->tp_xtd_format) { 121136401Ssklower #ifdef BYTE_ORDER 121236401Ssklower union seq_type seqeotX; 121336401Ssklower 121436401Ssklower seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 121536401Ssklower e.ATTR(AK_TPDU).e_seq = seqeotX.s_seq; 121636401Ssklower e.ATTR(AK_TPDU).e_cdt = ntohs(hdr->tpdu_AKcdtX); 121736401Ssklower #else 121836401Ssklower e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdtX; 121936401Ssklower e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseqX; 122036401Ssklower #endif BYTE_ORDER 122136401Ssklower } else { 122236401Ssklower e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdt; 122336401Ssklower e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseq; 122436401Ssklower } 122536401Ssklower IFTRACE(D_TPINPUT) 122636401Ssklower tptrace(TPPTmisc, "AK recvd seq cdt subseq fcc_pres", 122736401Ssklower e.ATTR(AK_TPDU).e_seq, e.ATTR(AK_TPDU).e_cdt, 122836401Ssklower subseq, fcc_present); 122936401Ssklower ENDTRACE 123036401Ssklower 123136401Ssklower e.ev_number = AK_TPDU; 123236401Ssklower IncStat(ts_AK_rcvd); 123336401Ssklower IncPStat(tpcb, tps_AK_rcvd); 123436401Ssklower break; 123536401Ssklower 123636401Ssklower case XAK_TPDU_type: 123736401Ssklower if (tpcb->tp_xtd_format) { 123836401Ssklower #ifdef BYTE_ORDER 123936401Ssklower union seq_type seqeotX; 124036401Ssklower 124136401Ssklower seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 124236401Ssklower e.ATTR(XAK_TPDU).e_seq = seqeotX.s_seq; 124336401Ssklower #else 124436401Ssklower e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseqX; 124536401Ssklower #endif BYTE_ORDER 124636401Ssklower } else { 124736401Ssklower e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseq; 124836401Ssklower } 124936401Ssklower e.ev_number = XAK_TPDU; 125036401Ssklower IncStat(ts_XAK_rcvd); 125136401Ssklower IncPStat(tpcb, tps_XAK_rcvd); 125236401Ssklower break; 125336401Ssklower 125436401Ssklower case XPD_TPDU_type: 125536401Ssklower if (tpcb->tp_xtd_format) { 125636401Ssklower #ifdef BYTE_ORDER 125736401Ssklower union seq_type seqeotX; 125836401Ssklower 125936401Ssklower seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 126036401Ssklower e.ATTR(XPD_TPDU).e_seq = seqeotX.s_seq; 126136401Ssklower #else 126236401Ssklower e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseqX; 126336401Ssklower #endif BYTE_ORDER 126436401Ssklower } else { 126536401Ssklower e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseq; 126636401Ssklower } 126736401Ssklower takes_data = TRUE; 126836401Ssklower e.ev_number = XPD_TPDU; 126936401Ssklower IncStat(ts_XPD_rcvd); 127036401Ssklower IncPStat(tpcb, tps_XPD_rcvd); 127136401Ssklower break; 127236401Ssklower 127336401Ssklower case DT_TPDU_type: 127436401Ssklower { /* the y option will cause occasional packets to be dropped. 127536401Ssklower * A little crude but it works. 127636401Ssklower */ 127736401Ssklower 127836401Ssklower IFDEBUG(D_DROP) 127936401Ssklower if(time.tv_usec & 0x4 && hdr->tpdu_DTseq & 0x1) { 128036401Ssklower IncStat(ts_ydebug); 128136401Ssklower goto discard; 128236401Ssklower } 128336401Ssklower ENDDEBUG 128436401Ssklower } 128536401Ssklower if (tpcb->tp_class == TP_CLASS_0) { 128636401Ssklower e.ATTR(DT_TPDU).e_seq = 0; /* actually don't care */ 128736401Ssklower e.ATTR(DT_TPDU).e_eot = (((struct tp0du *)hdr)->tp0du_eot); 128836401Ssklower } else if (tpcb->tp_xtd_format) { 128936401Ssklower #ifdef BYTE_ORDER 129036401Ssklower union seq_type seqeotX; 129136401Ssklower 129236401Ssklower seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 129336401Ssklower e.ATTR(DT_TPDU).e_seq = seqeotX.s_seq; 129436401Ssklower e.ATTR(DT_TPDU).e_eot = seqeotX.s_eot; 129536401Ssklower #else 129636401Ssklower e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseqX; 129736401Ssklower e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeotX; 129836401Ssklower #endif BYTE_ORDER 129936401Ssklower } else { 130036401Ssklower e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseq; 130136401Ssklower e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeot; 130236401Ssklower } 130336401Ssklower if(e.ATTR(DT_TPDU).e_eot) 130436401Ssklower IncStat(ts_eot_input); 130536401Ssklower takes_data = TRUE; 130636401Ssklower e.ev_number = DT_TPDU; 130736401Ssklower IncStat(ts_DT_rcvd); 130836401Ssklower IncPStat(tpcb, tps_DT_rcvd); 130936401Ssklower break; 131036401Ssklower 131136401Ssklower case GR_TPDU_type: 131236401Ssklower tp_indicate(T_DISCONNECT, tpcb, ECONNABORTED); 131336401Ssklower /* drop through */ 131436401Ssklower default: 131536401Ssklower /* this should NEVER happen because there is a 131636401Ssklower * check for dutype well above here 131736401Ssklower */ 131836401Ssklower error = E_TP_INV_TPDU; /* causes an ER */ 131936401Ssklower IFDEBUG(D_TPINPUT) 132036401Ssklower printf("INVALID dutype 0x%x\n", hdr->tpdu_type); 132136401Ssklower ENDDEBUG 132236401Ssklower IncStat(ts_inv_dutype); 132336401Ssklower goto respond; 132436401Ssklower } 132536401Ssklower } 132636401Ssklower 132736401Ssklower /* peel off the tp header; 132836401Ssklower * remember that the du_li doesn't count itself. 132936401Ssklower * This may leave us w/ an empty mbuf at the front of a chain. 133036401Ssklower * We can't just throw away the empty mbuf because hdr still points 133136401Ssklower * into the mbuf's data area and we're still using hdr (the tpdu header) 133236401Ssklower */ 133336401Ssklower m->m_len -= ((int)hdr->tpdu_li + 1); 133437469Ssklower m->m_data += ((int)hdr->tpdu_li + 1); 133536401Ssklower 133637469Ssklower if (takes_data) { 133737469Ssklower int max = tpdu_info[ hdr->tpdu_type ] [TP_MAX_DATA_INDEX]; 133837469Ssklower int datalen = tpdu_len - hdr->tpdu_li - 1, mbtype = MT_DATA; 133942468Ssklower struct cmsghdr c_hdr; 134037469Ssklower struct mbuf *n; 134136401Ssklower 134237469Ssklower CHECK( (max && datalen > max), E_TP_LENGTH_INVAL, 134337469Ssklower ts_inv_length, respond, (max + hdr->tpdu_li + 1) ); 134436401Ssklower switch( hdr->tpdu_type ) { 134537469Ssklower 134636401Ssklower case CR_TPDU_type: 134737469Ssklower c_hdr.cmsg_type = TPOPT_CONN_DATA; 134837469Ssklower goto make_control_msg; 134937469Ssklower 135036401Ssklower case CC_TPDU_type: 135137469Ssklower c_hdr.cmsg_type = TPOPT_CFRM_DATA; 135237469Ssklower goto make_control_msg; 135337469Ssklower 135436401Ssklower case DR_TPDU_type: 135537469Ssklower c_hdr.cmsg_type = TPOPT_DISC_DATA; 135637469Ssklower make_control_msg: 135737469Ssklower c_hdr.cmsg_level = SOL_TRANSPORT; 135837469Ssklower mbtype = MT_CONTROL; 135940015Ssklower datalen += sizeof(c_hdr); 136040015Ssklower m->m_len += sizeof(c_hdr); 136140015Ssklower m->m_data -= sizeof(c_hdr); 136240015Ssklower c_hdr.cmsg_len = datalen; 136340015Ssklower bcopy((caddr_t)&c_hdr, mtod(m, caddr_t), sizeof(c_hdr)); 136437469Ssklower /* FALLTHROUGH */ 136537469Ssklower 136636401Ssklower case XPD_TPDU_type: 136737469Ssklower if (mbtype != MT_CONTROL) 136837469Ssklower mbtype = MT_OOBDATA; 136937469Ssklower m->m_flags |= M_EOR; 137037469Ssklower /* FALLTHROUGH */ 137137469Ssklower 137236401Ssklower case DT_TPDU_type: 137337469Ssklower for (n = m; n; n = n->m_next) { 137437469Ssklower MCHTYPE(n, mbtype); 137537469Ssklower } 137637469Ssklower e.ATTR(DT_TPDU).e_datalen = datalen; 137736401Ssklower e.ATTR(DT_TPDU).e_data = m; 137836401Ssklower break; 137936401Ssklower 138036401Ssklower default: 138136401Ssklower printf( 138236401Ssklower "ERROR in tp_input! hdr->tpdu_type 0x%x takes_data 0x%x m 0x%x\n", 138336401Ssklower hdr->tpdu_type, takes_data, m); 138436401Ssklower break; 138536401Ssklower } 138636401Ssklower /* prevent m_freem() after tp_driver() from throwing it all away */ 138736401Ssklower m = MNULL; 138836401Ssklower } 138936401Ssklower 139036401Ssklower IncStat(ts_tpdu_rcvd); 139136401Ssklower 139236401Ssklower IFDEBUG(D_TPINPUT) 139336401Ssklower printf( "tp_input: before driver, state 0x%x event 0x%x m 0x%x", 139436401Ssklower tpcb->tp_state, e.ev_number, m ); 139536401Ssklower printf(" e.e_data 0x%x\n", e.ATTR(DT_TPDU).e_data); 139636401Ssklower printf("takes_data 0x%x m_len 0x%x, tpdu_len 0x%x\n", 139736401Ssklower takes_data, (m==MNULL)?0:m->m_len, tpdu_len); 139836401Ssklower ENDDEBUG 139936401Ssklower 140036401Ssklower error = tp_driver(tpcb, &e); 140136401Ssklower 140236401Ssklower ASSERT(tpcb != (struct tp_pcb *)0); 140336401Ssklower ASSERT(tpcb->tp_sock != (struct socket *)0); 140436401Ssklower if( tpcb->tp_sock->so_error == 0 ) 140536401Ssklower tpcb->tp_sock->so_error = error; 140636401Ssklower 140736401Ssklower /* Kludge to keep the state tables under control (adding 140836401Ssklower * data on connect & disconnect & freeing the mbuf containing 140936401Ssklower * the data would have exploded the tables and made a big mess ). 141036401Ssklower */ 141136401Ssklower switch(e.ev_number) { 141236401Ssklower case CC_TPDU: 141336401Ssklower case DR_TPDU: 141436401Ssklower case CR_TPDU: 141536401Ssklower m = e.ATTR(CC_TPDU).e_data; /* same field for all three dutypes */ 141636401Ssklower IFDEBUG(D_TPINPUT) 141736401Ssklower printf("after driver, restoring m to 0x%x, takes_data 0x%x\n", 141836401Ssklower m, takes_data); 141936401Ssklower ENDDEBUG 142036401Ssklower break; 142136401Ssklower default: 142236401Ssklower break; 142336401Ssklower } 142436401Ssklower /* Concatenated sequences are terminated by any tpdu that 142536401Ssklower * carries data: CR, CC, DT, XPD, DR. 142636401Ssklower * All other tpdu types may be concatenated: AK, XAK, DC, ER. 142736401Ssklower */ 142836401Ssklower 142936401Ssklower separate: 143036401Ssklower if ( takes_data == 0 ) { 143136401Ssklower ASSERT( m != MNULL ); 143236401Ssklower /* 143336401Ssklower * we already peeled off the prev. tp header so 143436401Ssklower * we can just pull up some more and repeat 143536401Ssklower */ 143636401Ssklower 143737469Ssklower if( m = tp_inputprep(m) ) { 143836401Ssklower IFDEBUG(D_TPINPUT) 143936401Ssklower hdr = mtod(m, struct tpdu *); 144036401Ssklower printf("tp_input @ separate: hdr 0x%x size %d m 0x%x\n", 144136401Ssklower hdr, (int) hdr->tpdu_li + 1, m); 144236401Ssklower dump_mbuf(m, "tp_input after driver, at separate"); 144336401Ssklower ENDDEBUG 144436401Ssklower 144536401Ssklower IncStat(ts_concat_rcvd); 144636401Ssklower goto again; 144736401Ssklower } 144836401Ssklower } 144936401Ssklower if ( m != MNULL ) { 145036401Ssklower IFDEBUG(D_TPINPUT) 145136401Ssklower printf("tp_input : m_freem(0x%x)\n", m); 145236401Ssklower ENDDEBUG 145336401Ssklower m_freem(m); 145436401Ssklower IFDEBUG(D_TPINPUT) 145536401Ssklower printf("tp_input : after m_freem 0x%x\n", m); 145636401Ssklower ENDDEBUG 145736401Ssklower } 145836401Ssklower return (ProtoHook) tpcb; 145936401Ssklower 146036401Ssklower discard: 146136401Ssklower /* class 4: drop the tpdu */ 146236401Ssklower /* class 2,0: Should drop the net connection, if you can figure out 146336401Ssklower * to which connection it applies 146436401Ssklower */ 146536401Ssklower IFDEBUG(D_TPINPUT) 146636401Ssklower printf("tp_input DISCARD\n"); 146736401Ssklower ENDDEBUG 146836401Ssklower IFTRACE(D_TPINPUT) 146936401Ssklower tptrace(TPPTmisc, "tp_input DISCARD m", m,0,0,0); 147036401Ssklower ENDTRACE 147136401Ssklower m_freem(m); 147236401Ssklower IncStat(ts_recv_drop); 147336401Ssklower return (ProtoHook)0; 147436401Ssklower 147536401Ssklower respond: 147636401Ssklower IFDEBUG(D_ERROR_EMIT) 147736401Ssklower printf("RESPOND: error 0x%x, errloc 0x%x\n", error, errloc); 147836401Ssklower ENDDEBUG 147936401Ssklower IFTRACE(D_TPINPUT) 148036401Ssklower tptrace(TPPTmisc, "tp_input RESPOND m error sref", m,error,sref,0); 148136401Ssklower ENDTRACE 148236401Ssklower if( sref == 0 ) 148336401Ssklower goto discard; 148437469Ssklower (void) tp_error_emit(error, (u_long)sref, (struct sockaddr_iso *)faddr, 148537469Ssklower (struct sockaddr_iso *)laddr, m, (int)errloc, tpcb, 148637469Ssklower (int)cons_channel, dgout_routine); 148736401Ssklower IFDEBUG(D_ERROR_EMIT) 148836401Ssklower printf("tp_input after error_emit\n"); 148936401Ssklower ENDDEBUG 149036401Ssklower 149136401Ssklower #ifdef lint 149236401Ssklower printf("",sref,opt); 149336401Ssklower #endif lint 149436401Ssklower IncStat(ts_recv_drop); 149536401Ssklower return (ProtoHook)0; 149636401Ssklower } 149736401Ssklower 149836401Ssklower 149936401Ssklower /* 150036401Ssklower * NAME: tp_headersize() 150136401Ssklower * 150236401Ssklower * CALLED FROM: 150336401Ssklower * tp_emit() and tp_sbsend() 150436401Ssklower * TP needs to know the header size so it can figure out how 150536401Ssklower * much data to put in each tpdu. 150636401Ssklower * 150736401Ssklower * FUNCTION, ARGUMENTS, and RETURN VALUE: 150836401Ssklower * For a given connection, represented by (tpcb), and 150936401Ssklower * tpdu type (dutype), return the size of a tp header. 151036401Ssklower * 151136401Ssklower * RETURNS: the expected size of the heade in bytesr 151236401Ssklower * 151336401Ssklower * SIDE EFFECTS: 151436401Ssklower * 151536401Ssklower * NOTES: It would be nice if it got the network header size as well. 151636401Ssklower */ 151736401Ssklower int 151836401Ssklower tp_headersize(dutype, tpcb) 151936401Ssklower int dutype; 152036401Ssklower struct tp_pcb *tpcb; 152136401Ssklower { 152236401Ssklower register int size = 0; 152336401Ssklower 152436401Ssklower IFTRACE(D_CONN) 152536401Ssklower tptrace(TPPTmisc, "tp_headersize dutype class xtd_format", 152636401Ssklower dutype, tpcb->tp_class, tpcb->tp_xtd_format, 0); 152736401Ssklower ENDTRACE 152836401Ssklower if( !( (tpcb->tp_class == TP_CLASS_0) || 152936401Ssklower (tpcb->tp_class == TP_CLASS_4) || 153036401Ssklower (dutype == DR_TPDU_type) || 153136401Ssklower (dutype == CR_TPDU_type) )) { 153236401Ssklower printf("tp_headersize:dutype 0x%x, class 0x%x", 153336401Ssklower dutype, tpcb->tp_class); 153436401Ssklower /* TODO: identify this and GET RID OF IT */ 153536401Ssklower } 153636401Ssklower ASSERT( (tpcb->tp_class == TP_CLASS_0) || 153736401Ssklower (tpcb->tp_class == TP_CLASS_4) || 153836401Ssklower (dutype == DR_TPDU_type) || 153936401Ssklower (dutype == CR_TPDU_type) ); 154036401Ssklower 154136401Ssklower if( tpcb->tp_class == TP_CLASS_0 ) { 154236401Ssklower size = tpdu_info[ dutype ] [TP_LEN_CLASS_0_INDEX]; 154336401Ssklower } else { 154436401Ssklower size = tpdu_info[ dutype ] [tpcb->tp_xtd_format]; 154536401Ssklower } 154636401Ssklower return size; 154736401Ssklower /* caller must get network level header size separately */ 154836401Ssklower } 1549