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*42944Ssklower * @(#)tp_input.c 7.10 (Berkeley) 06/06/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 171*42944Ssklower #define CHECK(Phrase, Erval, Stat, Whattodo, Loc)\ 172*42944Ssklower if(Phrase) { error = (Erval); errlen = (int)(Loc); IncStat(Stat); \ 173*42944Ssklower goto Whattodo; } 174*42944Ssklower 17536401Ssklower /* 17636401Ssklower * WHENEVER YOU USE THE FOLLOWING MACRO, 17736401Ssklower * BE SURE THE TPDUTYPE IS A LEGIT VALUE FIRST! 17836401Ssklower */ 17936401Ssklower 180*42944Ssklower #define WHILE_OPTIONS(P, hdr, format)\ 181*42944Ssklower { register caddr_t P = tpdu_info[(hdr)->tpdu_type][(format)] + (caddr_t)hdr;\ 182*42944Ssklower caddr_t PLIM = 1 + hdr->tpdu_li + (caddr_t)hdr;\ 183*42944Ssklower for (;; P += 2 + ((struct tp_vbp *)P)->tpv_len) {\ 184*42944Ssklower CHECK((P > PLIM), E_TP_LENGTH_INVAL, ts_inv_length,\ 185*42944Ssklower respond, P - (caddr_t)hdr);\ 186*42944Ssklower if (P == PLIM) break; 18736401Ssklower 188*42944Ssklower #define END_WHILE_OPTIONS(P) } } 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; 379*42944Ssklower int error = 0; 38036401Ssklower unsigned dutype; 381*42944Ssklower u_short dref, sref = 0, acktime = 2, subseq = 0; /*VAX*/ 382*42944Ssklower u_char preferred_class = 0, class_to_use = 0; 383*42944Ssklower u_char opt, dusize = TP_DFL_TPDUSIZE, addlopt = 0, version; 38436401Ssklower #ifdef TP_PERF_MEAS 38538841Ssklower u_char perf_meas; 38636401Ssklower #endif TP_PERF_MEAS 387*42944Ssklower u_char fsufxlen = 0; 388*42944Ssklower u_char lsufxlen = 0; 389*42944Ssklower caddr_t fsufxloc = 0, lsufxloc = 0; 390*42944Ssklower int tpdu_len = 0; 391*42944Ssklower u_int takes_data = FALSE; 392*42944Ssklower u_int fcc_present = FALSE; 393*42944Ssklower int errlen = 0; 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 /* 40836401Ssklower * get the actual tpdu length - necessary for monitoring 40936401Ssklower * and for checksumming 41036401Ssklower * 41136401Ssklower * Also, maybe measure the mbuf chain lengths and sizes. 41236401Ssklower */ 41336401Ssklower 41436401Ssklower { register struct mbuf *n=m; 41536401Ssklower # ifdef ARGO_DEBUG 41636401Ssklower int chain_length = 0; 41736401Ssklower # endif ARGO_DEBUG 41836401Ssklower 41936401Ssklower for(;;) { 42036401Ssklower tpdu_len += n->m_len; 42136401Ssklower IFDEBUG(D_MBUF_MEAS) 42237469Ssklower if( n->m_flags & M_EXT) { 42336401Ssklower IncStat(ts_mb_cluster); 42436401Ssklower } else { 42536401Ssklower IncStat(ts_mb_small); 42636401Ssklower } 42736401Ssklower chain_length ++; 42836401Ssklower ENDDEBUG 42936401Ssklower if (n->m_next == MNULL ) { 43036401Ssklower break; 43136401Ssklower } 43236401Ssklower n = n->m_next; 43336401Ssklower } 43436401Ssklower IFDEBUG(D_MBUF_MEAS) 43536401Ssklower if(chain_length > 16) 43636401Ssklower chain_length = 0; /* zero used for anything > 16 */ 43736401Ssklower tp_stat.ts_mb_len_distr[chain_length] ++; 43836401Ssklower ENDDEBUG 43936401Ssklower } 44036401Ssklower IFTRACE(D_TPINPUT) 44136401Ssklower tptraceTPCB(TPPTtpduin, hdr->tpdu_type, hdr, hdr->tpdu_li+1, tpdu_len, 44236401Ssklower 0); 44336401Ssklower ENDTRACE 44436401Ssklower 44536401Ssklower dref = ntohs((short)hdr->tpdu_dref); 44636401Ssklower sref = ntohs((short)hdr->tpdu_sref); 44736401Ssklower dutype = (int)hdr->tpdu_type; 44836401Ssklower 44936401Ssklower IFDEBUG(D_TPINPUT) 45036401Ssklower printf("input: dutype 0x%x cons_channel 0x%x dref 0x%x\n", dutype, 45136401Ssklower cons_channel, dref); 45236401Ssklower printf("input: dref 0x%x sref 0x%x\n", dref, sref); 45336401Ssklower ENDDEBUG 45436401Ssklower IFTRACE(D_TPINPUT) 45536401Ssklower tptrace(TPPTmisc, "channel dutype dref ", 45636401Ssklower cons_channel, dutype, dref, 0); 45736401Ssklower ENDTRACE 45836401Ssklower 45936401Ssklower 46036401Ssklower #ifdef ARGO_DEBUG 46136401Ssklower if( (dutype < TP_MIN_TPDUTYPE) || (dutype > TP_MAX_TPDUTYPE)) { 46236401Ssklower printf("BAD dutype! 0x%x, channel 0x%x dref 0x%x\n", 46336401Ssklower dutype, cons_channel, dref); 46436401Ssklower dump_buf (m, sizeof( struct mbuf )); 46536401Ssklower 46636401Ssklower IncStat(ts_inv_dutype); 46736401Ssklower goto discard; 46836401Ssklower } 46936401Ssklower #endif ARGO_DEBUG 47036401Ssklower 47136401Ssklower CHECK( (dutype < TP_MIN_TPDUTYPE || dutype > TP_MAX_TPDUTYPE), 47236401Ssklower E_TP_INV_TPDU, ts_inv_dutype, respond, 47336401Ssklower 2 ); 47436401Ssklower /* unfortunately we can't take the address of the tpdu_type field, 47536401Ssklower * since it's a bit field - so we just use the constant offset 2 47636401Ssklower */ 47736401Ssklower 47836401Ssklower /* Now this isn't very neat but since you locate a pcb one way 47936401Ssklower * at the beginning of connection establishment, and by 48036401Ssklower * the dref for each tpdu after that, we have to treat CRs differently 48136401Ssklower */ 48236401Ssklower if ( dutype == CR_TPDU_type ) { 48336401Ssklower u_char alt_classes = 0; 48436401Ssklower 48537469Ssklower preferred_class = 1 << hdr->tpdu_CRclass; 48636401Ssklower opt = hdr->tpdu_CRoptions; 48736401Ssklower 48836401Ssklower WHILE_OPTIONS(P, hdr, 1 ) /* { */ 48936401Ssklower 49036401Ssklower switch( vbptr(P)->tpv_code ) { 49136401Ssklower 49236401Ssklower case TPP_tpdu_size: 49336401Ssklower vb_getval(P, u_char, dusize); 49436401Ssklower IFDEBUG(D_TPINPUT) 49536401Ssklower printf("CR dusize 0x%x\n", dusize); 49636401Ssklower ENDDEBUG 497*42944Ssklower /* COS tests: NBS IA (Dec. 1987) Sec. 4.5.2.1 */ 498*42944Ssklower if (dusize < TP_MIN_TPDUSIZE || dusize > TP_MAX_TPDUSIZE) 499*42944Ssklower dusize = TP_DFL_TPDUSIZE; 50036401Ssklower break; 50136401Ssklower case TPP_addl_opt: 50236401Ssklower vb_getval(P, u_char, addlopt); 50336401Ssklower break; 50436401Ssklower case TPP_calling_sufx: 50536401Ssklower /* could use vb_getval, but we want to save the loc & len 50636401Ssklower * for later use 50736401Ssklower */ 50836401Ssklower fsufxloc = (caddr_t) &vbptr(P)->tpv_val; 50936401Ssklower fsufxlen = vbptr(P)->tpv_len; 51036401Ssklower IFDEBUG(D_TPINPUT) 51136401Ssklower printf("CR fsufx:"); 51236401Ssklower { register int j; 51336401Ssklower for(j=0; j<fsufxlen; j++ ) { 51436401Ssklower printf(" 0x%x. ", *((caddr_t)(fsufxloc+j)) ); 51536401Ssklower } 51636401Ssklower printf("\n"); 51736401Ssklower } 51836401Ssklower ENDDEBUG 51936401Ssklower break; 52036401Ssklower case TPP_called_sufx: 52136401Ssklower /* could use vb_getval, but we want to save the loc & len 52236401Ssklower * for later use 52336401Ssklower */ 52436401Ssklower lsufxloc = (caddr_t) &vbptr(P)->tpv_val; 52536401Ssklower lsufxlen = vbptr(P)->tpv_len; 52636401Ssklower IFDEBUG(D_TPINPUT) 52736401Ssklower printf("CR lsufx:"); 52836401Ssklower { register int j; 52936401Ssklower for(j=0; j<lsufxlen; j++ ) { 53037469Ssklower printf(" 0x%x. ", *((u_char *)(lsufxloc+j)) ); 53136401Ssklower } 53236401Ssklower printf("\n"); 53336401Ssklower } 53436401Ssklower ENDDEBUG 53536401Ssklower break; 53636401Ssklower 53736401Ssklower #ifdef TP_PERF_MEAS 53836401Ssklower case TPP_perf_meas: 53936401Ssklower vb_getval(P, u_char, perf_meas); 54036401Ssklower break; 54136401Ssklower #endif TP_PERF_MEAS 54236401Ssklower 54336401Ssklower case TPP_vers: 54436401Ssklower /* not in class 0; 1 octet; in CR_TPDU only */ 545*42944Ssklower /* COS tests says if version wrong, use default version!?XXX */ 54636401Ssklower CHECK( (vbval(P, u_char) != TP_VERSION ), 54742491Ssklower E_TP_INV_PVAL, ts_inv_pval, setversion, 548*42944Ssklower (1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) ); 54942491Ssklower setversion: 55042491Ssklower version = vbval(P, u_char); 55136401Ssklower break; 55236401Ssklower case TPP_acktime: 55336401Ssklower vb_getval(P, u_short, acktime); 55436401Ssklower acktime = ntohs(acktime); 55536401Ssklower acktime = acktime/500; /* convert to slowtimo ticks */ 55636401Ssklower if((short)acktime <=0 ) 55736401Ssklower acktime = 2; /* don't allow a bad peer to screw us up */ 55836401Ssklower IFDEBUG(D_TPINPUT) 55936401Ssklower printf("CR acktime 0x%x\n", acktime); 56036401Ssklower ENDDEBUG 56136401Ssklower break; 56236401Ssklower 56336401Ssklower case TPP_alt_class: 56436401Ssklower { 56536401Ssklower u_char *aclass = 0; 56636401Ssklower register int i; 567*42944Ssklower static u_char bad_alt_classes[5] = 568*42944Ssklower { ~0, ~3, ~5, ~0xf, ~0x1f}; 56936401Ssklower 570*42944Ssklower aclass = 571*42944Ssklower (u_char *) &(((struct tp_vbp *)P)->tpv_val); 57236401Ssklower for (i = ((struct tp_vbp *)P)->tpv_len; i>0; i--) { 573*42944Ssklower alt_classes |= (1<<((*aclass++)>>4)); 57436401Ssklower } 575*42944Ssklower CHECK( (bad_alt_classes[hdr->tpdu_CRclass] & alt_classes), 576*42944Ssklower E_TP_INV_PVAL, ts_inv_aclass, respond, 577*42944Ssklower ((caddr_t)aclass) - (caddr_t)hdr); 57836401Ssklower IFDEBUG(D_TPINPUT) 57936401Ssklower printf("alt_classes 0x%x\n", alt_classes); 58036401Ssklower ENDDEBUG 58136401Ssklower } 58236401Ssklower break; 58336401Ssklower 58436401Ssklower case TPP_security: 58536401Ssklower case TPP_residER: 58636401Ssklower case TPP_priority: 58736401Ssklower case TPP_transdelay: 58836401Ssklower case TPP_throughput: 58936401Ssklower case TPP_addl_info: 59036401Ssklower case TPP_subseq: 59136401Ssklower IFDEBUG(D_TPINPUT) 59236401Ssklower printf("param ignored CR_TPDU code= 0x%x\n", 59336401Ssklower vbptr(P)->tpv_code); 59436401Ssklower ENDDEBUG 59536401Ssklower IncStat(ts_param_ignored); 59636401Ssklower break; 59736401Ssklower 59836401Ssklower case TPP_checksum: 59936401Ssklower IFDEBUG(D_TPINPUT) 60036401Ssklower printf("CR before cksum\n"); 60136401Ssklower ENDDEBUG 60236401Ssklower 60336401Ssklower CHECK( iso_check_csum(m, tpdu_len), 60436401Ssklower E_TP_INV_PVAL, ts_bad_csum, discard, 0) 60536401Ssklower 60636401Ssklower IFDEBUG(D_TPINPUT) 60736401Ssklower printf("CR before cksum\n"); 60836401Ssklower ENDDEBUG 60936401Ssklower break; 61036401Ssklower 61136401Ssklower default: 61236401Ssklower IncStat(ts_inv_pcode); 61336401Ssklower error = E_TP_INV_PCODE; 61436401Ssklower goto discard; 61536401Ssklower 61636401Ssklower } 61736401Ssklower 61836401Ssklower /* } */ END_WHILE_OPTIONS(P) 61936401Ssklower 62036401Ssklower if( lsufxlen == 0) { 62136401Ssklower /* can't look for a tpcb w/o any called sufx */ 62236401Ssklower error = E_TP_LENGTH_INVAL; 62336401Ssklower IncStat(ts_inv_sufx); 62436401Ssklower goto respond; 62536401Ssklower } else { 62636401Ssklower register struct tp_ref *rp; 62736401Ssklower register int r; 62836401Ssklower extern int tp_maxrefopen; 62936401Ssklower 63036401Ssklower rp = &tp_ref[1]; /* zero-th one is never open */ 63136401Ssklower for( r=1 ; (r <= tp_maxrefopen) ; r++,rp++ ) { 63236401Ssklower if (rp->tpr_state!=REF_OPENING) 63336401Ssklower continue; 63436401Ssklower if ( bcmp(lsufxloc, rp->tpr_pcb->tp_lsuffix, lsufxlen)==0 ) { 63536401Ssklower tpcb = rp->tpr_pcb; 63636401Ssklower if( laddr->sa_family != 63736401Ssklower tpcb->tp_sock->so_proto->pr_domain->dom_family ) { 63836401Ssklower IFDEBUG(D_CONN) 63936401Ssklower printf( 64036401Ssklower "MISMATCHED AF on CR! laddr.family 0x%x expected 0x%x\n", 64136401Ssklower laddr->sa_family, 64236401Ssklower tpcb->tp_sock->so_proto->pr_domain->dom_family ); 64336401Ssklower ENDDEBUG 64436401Ssklower continue; 64536401Ssklower } 64636401Ssklower IFTRACE(D_TPINPUT) 64736401Ssklower tptrace(TPPTmisc, "tp_input: ref *lsufxloc refstate", 64836401Ssklower r, *lsufxloc, rp->tpr_state, 0); 64936401Ssklower ENDTRACE 65036401Ssklower /* found it */ 65136401Ssklower break; 65236401Ssklower } 65336401Ssklower } 65436401Ssklower 65536401Ssklower CHECK( (r > tp_maxrefopen), E_TP_NO_SESSION, ts_inv_sufx, respond, 65636401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 65736401Ssklower /* _tpduf is the fixed part; add 2 to get the dref bits of 65836401Ssklower * the fixed part (can't take the address of a bit field) 65936401Ssklower */ 66036401Ssklower } 66136401Ssklower 66236401Ssklower /* 66336401Ssklower * WE HAVE A TPCB 66436401Ssklower * already know that the classes in the CR match at least 66536401Ssklower * one class implemented, but we don't know yet if they 66636401Ssklower * include any classes permitted by this server. 66736401Ssklower */ 66836401Ssklower 66936401Ssklower IFDEBUG(D_TPINPUT) 67036401Ssklower printf("HAVE A TPCB 1: 0x%x\n", tpcb); 67136401Ssklower ENDDEBUG 67236401Ssklower IFDEBUG(D_CONN) 67336401Ssklower printf( 67436401Ssklower "CR: bef CHKS: flags 0x%x class_to_use 0x%x alt 0x%x opt 0x%x tp_class 0x%x\n", 67536401Ssklower tpcb->tp_flags, class_to_use, alt_classes, opt, tpcb->tp_class); 67636401Ssklower ENDDEBUG 67736401Ssklower /* tpcb->tp_class doesn't include any classes not implemented */ 67836401Ssklower class_to_use = (preferred_class & tpcb->tp_class); 67936401Ssklower if( (class_to_use = preferred_class & tpcb->tp_class) == 0 ) 68036401Ssklower class_to_use = alt_classes & tpcb->tp_class; 68136401Ssklower 68236401Ssklower class_to_use = 1 << tp_mask_to_num(class_to_use); 68336401Ssklower 68436401Ssklower { 68536401Ssklower tpp = tpcb->_tp_param; 68636401Ssklower tpp.p_class = class_to_use; 68736401Ssklower tpp.p_tpdusize = dusize; 68836401Ssklower tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT; 68936401Ssklower tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD; 69036401Ssklower tpp.p_use_checksum = (tpp.p_class == TP_CLASS_0)?0: 69136401Ssklower (addlopt & TPAO_NO_CSUM) == 0; 69242491Ssklower tpp.p_version = version; 69336401Ssklower #ifdef notdef 69436401Ssklower tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC; 69536401Ssklower tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD; 69636401Ssklower tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC; 69736401Ssklower #endif notdef 69836401Ssklower 69936401Ssklower CHECK( 70036401Ssklower tp_consistency(tpcb, 0 /* not force or strict */, &tpp) != 0, 70136401Ssklower E_TP_NEGOT_FAILED, ts_negotfailed, respond, 70236401Ssklower (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 70336401Ssklower /* ^ more or less the location of class */ 70436401Ssklower ) 70536401Ssklower } 70636401Ssklower IFTRACE(D_CONN) 70736401Ssklower tptrace(TPPTmisc, 70836401Ssklower "after 1 consist class_to_use class, out, tpconsout", 70936401Ssklower class_to_use, 71036401Ssklower tpcb->tp_class, dgout_routine, tpcons_output 71136401Ssklower ); 71236401Ssklower ENDTRACE 71336401Ssklower CHECK( 71436401Ssklower ((class_to_use == TP_CLASS_0)&&(dgout_routine != tpcons_output)), 71536401Ssklower E_TP_NEGOT_FAILED, ts_negotfailed, respond, 71636401Ssklower (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 71736401Ssklower /* ^ more or less the location of class */ 71836401Ssklower ) 71936401Ssklower IFDEBUG(D_CONN) 72036401Ssklower printf("CR: after CRCCCHECKS: tpcb 0x%x, flags 0x%x\n", 72136401Ssklower tpcb, tpcb->tp_flags); 72236401Ssklower ENDDEBUG 72336401Ssklower takes_data = TRUE; 72436401Ssklower e.ATTR(CR_TPDU).e_cdt = hdr->tpdu_CRcdt; 72536401Ssklower e.ev_number = CR_TPDU; 72636401Ssklower 72736401Ssklower so = tpcb->tp_sock; 72836401Ssklower if (so->so_options & SO_ACCEPTCONN) { 72936401Ssklower /* 73036401Ssklower * Create a socket, tpcb, ll pcb, etc. 73136401Ssklower * for this newborn connection, and fill in all the values. 73236401Ssklower */ 73336401Ssklower IFDEBUG(D_CONN) 73436401Ssklower printf("abt to call tp_newsocket(0x%x, 0x%x, 0x%x, 0x%x)\n", 73536401Ssklower so, laddr, faddr, cons_channel); 73636401Ssklower ENDDEBUG 73736401Ssklower if( (so = 73836401Ssklower tp_newsocket(so, faddr, cons_channel, 73936401Ssklower class_to_use, 74037469Ssklower ((tpcb->tp_netservice == IN_CLNS) ? IN_CLNS : 74137469Ssklower (dgout_routine == tpcons_output)?ISO_CONS:ISO_CLNS)) 74236401Ssklower ) == (struct socket *)0 ) { 74336401Ssklower /* note - even if netservice is IN_CLNS, as far as 74436401Ssklower * the tp entity is concerned, the only differences 74537469Ssklower * are CO vs CL 74636401Ssklower */ 74736401Ssklower IFDEBUG(D_CONN) 74836401Ssklower printf("tp_newsocket returns 0\n"); 74936401Ssklower ENDDEBUG 75036401Ssklower goto discard; 75136401Ssklower } 75236401Ssklower tpcb = sototpcb(so); 75336401Ssklower 75436401Ssklower /* 75537469Ssklower * Stash the addresses in the net level pcb 75636401Ssklower * kind of like a pcbconnect() but don't need 75736401Ssklower * or want all those checks. 75836401Ssklower */ 75936401Ssklower (tpcb->tp_nlproto->nlp_putnetaddr)(so->so_pcb, faddr, TP_FOREIGN); 76036401Ssklower (tpcb->tp_nlproto->nlp_putnetaddr)(so->so_pcb, laddr, TP_LOCAL); 76136401Ssklower 76237469Ssklower /* stash the f suffix in the new tpcb */ 76337469Ssklower /* l suffix is already there */ 76438841Ssklower bcopy(fsufxloc, tpcb->tp_fsuffix, fsufxlen); 76536401Ssklower 76637469Ssklower (tpcb->tp_nlproto->nlp_putsufx) 76737469Ssklower (so->so_pcb, fsufxloc, fsufxlen, TP_FOREIGN); 76838841Ssklower (tpcb->tp_nlproto->nlp_putsufx) 76938841Ssklower (so->so_pcb, lsufxloc, lsufxlen, TP_LOCAL); 77037469Ssklower 77136401Ssklower #ifdef TP_PERF_MEAS 77236401Ssklower if( tpcb->tp_perf_on = perf_meas ) { /* assignment */ 77336401Ssklower /* ok, let's create an mbuf for stashing the 77436401Ssklower * statistics if one doesn't already exist 77536401Ssklower */ 77636401Ssklower (void) tp_setup_perf(tpcb); 77736401Ssklower } 77836401Ssklower #endif TP_PERF_MEAS 77936401Ssklower tpcb->tp_fref = sref; 78036401Ssklower 78136401Ssklower /* We've already checked for consistency with the options 78236401Ssklower * set in tpp, but we couldn't set them earlier because 78336401Ssklower * we didn't want to change options in the LISTENING tpcb. 78436401Ssklower * Now we set the options in the new socket's tpcb. 78536401Ssklower */ 78636401Ssklower (void) tp_consistency( tpcb, TP_FORCE, &tpp); 78736401Ssklower 78836401Ssklower if(!tpcb->tp_use_checksum) 78936401Ssklower IncStat(ts_csum_off); 79036401Ssklower if(tpcb->tp_xpd_service) 79136401Ssklower IncStat(ts_use_txpd); 79236401Ssklower if(tpcb->tp_xtd_format) 79336401Ssklower IncStat(ts_xtd_fmt); 79436401Ssklower 79536401Ssklower /* 79636401Ssklower * Get the maximum transmission unit from the lower layer(s) 79736401Ssklower * so we can negotiate a reasonable max TPDU size. 79836401Ssklower */ 79936401Ssklower (tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb, 80036401Ssklower &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0); 80136401Ssklower tpcb->tp_peer_acktime = acktime; 80236401Ssklower 80336401Ssklower /* 80436401Ssklower * The following kludge is used to test retransmissions and 80536401Ssklower * timeout during connection establishment. 80636401Ssklower */ 80736401Ssklower IFDEBUG(D_ZDREF) 80836401Ssklower IncStat(ts_zdebug); 80937469Ssklower /*tpcb->tp_fref = 0;*/ 81036401Ssklower ENDDEBUG 81136401Ssklower } 81236401Ssklower IncStat(ts_CR_rcvd); 81339929Ssklower if (!tpcb->tp_cebit_off) { 81439929Ssklower tpcb->tp_win_recv = tp_start_win << 8; 81539929Ssklower tpcb->tp_cong_sample.cs_size = 0; 81639929Ssklower LOCAL_CREDIT(tpcb); 81739929Ssklower CONG_INIT_SAMPLE(tpcb); 81839929Ssklower CONG_UPDATE_SAMPLE(tpcb, ce_bit); 81939929Ssklower } 82039929Ssklower tpcb->tp_ackrcvd = 0; 82136401Ssklower } else if ( dutype == ER_TPDU_type ) { 82236401Ssklower /* 82336401Ssklower * ER TPDUs have to be recognized separately 82436401Ssklower * because they don't necessarily have a tpcb 82536401Ssklower * with them and we don't want err out looking for such 82636401Ssklower * a beast. 82736401Ssklower * We could put a bunch of little kludges in the 82836401Ssklower * next section of code so it would avoid references to tpcb 82936401Ssklower * if dutype == ER_TPDU_type but we don't want code for ERs to 83036401Ssklower * mess up code for data transfer. 83136401Ssklower */ 83236401Ssklower IncStat(ts_ER_rcvd); 83336401Ssklower e.ev_number = ER_TPDU; 83436401Ssklower e.ATTR(ER_TPDU).e_reason = (u_char)hdr->tpdu_ERreason; 83536401Ssklower takes_data = 1; 83636401Ssklower } else { 83736401Ssklower /* tpdu type is CC, XPD, XAK, GR, AK, DR, DC, or DT */ 83836401Ssklower 83936401Ssklower /* In the next 4 checks, 84036401Ssklower * _tpduf is the fixed part; add 2 to get the dref bits of 84136401Ssklower * the fixed part (can't take the address of a bit field) 84236401Ssklower */ 84336401Ssklower if(cons_channel) { 84436401Ssklower #if NARGOXTWENTYFIVE > 0 84536401Ssklower extern struct tp_pcb *cons_chan_to_tpcb(); 84636401Ssklower 84736401Ssklower tpcb = cons_chan_to_tpcb( cons_channel ); 84836401Ssklower /* Problem: We may have a legit 84936401Ssklower * error situation yet we may or may not have 85036401Ssklower * a correspondence between the tpcb and the vc, 85136401Ssklower * e.g., TP4cr--> <no dice, respond w/ DR on vc> 85236401Ssklower * <--- DR 85336401Ssklower * Now it's up to TP to look at the tpdu and do one of: 85436401Ssklower * confirm(dgm)(cr), confirm(circuit)(cr), reject(cr), or 85536401Ssklower * nothing, if the circuit is already open (any other tpdu). 85636401Ssklower * Sigh. 85736401Ssklower */ 85836401Ssklower 85936401Ssklower /* I don't know about this error value */ 86036401Ssklower CHECK( (tpcb == (struct tp_pcb *)0) , 86136401Ssklower E_TP_NO_CR_ON_NC, ts_inv_dref, respond, 86236401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 86336401Ssklower #else 86436401Ssklower printf("tp_input(): X25 NOT CONFIGURED!!\n"); 86536401Ssklower #endif NARGOXTWENTYFIVE > 0 86636401Ssklower 86736401Ssklower } else { 86836401Ssklower 86936401Ssklower CHECK( ((int)dref <= 0 || dref >= N_TPREF) , 870*42944Ssklower E_TP_MISM_REFS,ts_inv_dref, nonx_dref, 87136401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 87236401Ssklower CHECK( ((tpcb = tp_ref[dref].tpr_pcb ) == (struct tp_pcb *) 0 ), 873*42944Ssklower E_TP_MISM_REFS,ts_inv_dref, nonx_dref, 87436401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 87536401Ssklower CHECK( (tpcb->tp_refp->tpr_state == REF_FREE), 876*42944Ssklower E_TP_MISM_REFS,ts_inv_dref, nonx_dref, 87736401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 87836401Ssklower } 87936401Ssklower 88036401Ssklower IFDEBUG(D_TPINPUT) 88136401Ssklower printf("HAVE A TPCB 2: 0x%x\n", tpcb); 88236401Ssklower ENDDEBUG 88336401Ssklower 88436401Ssklower /* causes a DR to be sent for CC; ER for all else */ 88536401Ssklower CHECK( (tpcb->tp_refp->tpr_state == REF_FROZEN), 88636401Ssklower (dutype == CC_TPDU_type?E_TP_NO_SESSION:E_TP_MISM_REFS), 88736401Ssklower ts_inv_dref, respond, 88836401Ssklower (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 88936401Ssklower 89036401Ssklower IFDEBUG(D_TPINPUT) 89136401Ssklower printf("state of dref %d ok, tpcb 0x%x\n", dref,tpcb); 89236401Ssklower ENDDEBUG 89336401Ssklower /* 89436401Ssklower * At this point the state of the dref could be 89536401Ssklower * FROZEN: tpr_pcb == NULL, has ( reference only) timers 89636401Ssklower * for example, DC may arrive after the close() has detached 89736401Ssklower * the tpcb (e.g., if user turned off SO_LISTEN option) 89836401Ssklower * OPENING : a tpcb exists but no timers yet 89936401Ssklower * OPEN : tpcb exists & timers are outstanding 90036401Ssklower */ 90136401Ssklower 90239929Ssklower if (!tpcb->tp_cebit_off) 90339929Ssklower CONG_UPDATE_SAMPLE(tpcb, ce_bit); 90439929Ssklower 90536401Ssklower dusize = tpcb->tp_tpdusize; 90636401Ssklower 90736401Ssklower dutype = hdr->tpdu_type << 8; /* for the switch below */ 90836401Ssklower 90936401Ssklower WHILE_OPTIONS(P, hdr, tpcb->tp_xtd_format) /* { */ 91036401Ssklower 91137469Ssklower #define caseof(x,y) case (((x)<<8)+(y)) 91236401Ssklower switch( dutype | vbptr(P)->tpv_code ) { 91336401Ssklower 91436401Ssklower caseof( CC_TPDU_type, TPP_addl_opt ): 91536401Ssklower /* not in class 0; 1 octet */ 91636401Ssklower vb_getval(P, u_char, addlopt); 91736401Ssklower break; 91836401Ssklower caseof( CC_TPDU_type, TPP_tpdu_size ): 919*42944Ssklower { 920*42944Ssklower u_char odusize = dusize; 92136401Ssklower vb_getval(P, u_char, dusize); 922*42944Ssklower CHECK( (dusize < TP_MIN_TPDUSIZE || 923*42944Ssklower dusize > TP_MAX_TPDUSIZE || dusize > odusize), 924*42944Ssklower E_TP_INV_PVAL, ts_inv_pval, respond, 925*42944Ssklower (1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) ) 92636401Ssklower IFDEBUG(D_TPINPUT) 92736401Ssklower printf("CC dusize 0x%x\n", dusize); 92836401Ssklower ENDDEBUG 929*42944Ssklower } 93036401Ssklower break; 93136401Ssklower caseof( CC_TPDU_type, TPP_calling_sufx): 93236401Ssklower IFDEBUG(D_TPINPUT) 93336401Ssklower printf("CC calling (local) sufxlen 0x%x\n", lsufxlen); 93436401Ssklower ENDDEBUG 93536401Ssklower lsufxloc = (caddr_t) &vbptr(P)->tpv_val; 93636401Ssklower lsufxlen = vbptr(P)->tpv_len; 93736401Ssklower break; 93836401Ssklower caseof( CC_TPDU_type, TPP_acktime ): 93936401Ssklower /* class 4 only, 2 octets */ 94036401Ssklower vb_getval(P, u_short, acktime); 94136401Ssklower acktime = acktime/500; /* convert to slowtimo ticks */ 94236401Ssklower if( (short)acktime <=0 ) 94336401Ssklower acktime = 2; 94436401Ssklower break; 94536401Ssklower caseof( CC_TPDU_type, TPP_called_sufx): 94636401Ssklower fsufxloc = (caddr_t) &vbptr(P)->tpv_val; 94736401Ssklower fsufxlen = vbptr(P)->tpv_len; 94836401Ssklower IFDEBUG(D_TPINPUT) 94936401Ssklower printf("CC called (foreign) sufx len %d\n", fsufxlen); 95036401Ssklower ENDDEBUG 95136401Ssklower break; 95236401Ssklower 95336401Ssklower caseof( CC_TPDU_type, TPP_checksum): 95436401Ssklower caseof( DR_TPDU_type, TPP_checksum): 95536401Ssklower caseof( DT_TPDU_type, TPP_checksum): 95636401Ssklower caseof( XPD_TPDU_type, TPP_checksum): 95736401Ssklower if( tpcb->tp_use_checksum ) { 95836401Ssklower CHECK( iso_check_csum(m, tpdu_len), 95936401Ssklower E_TP_INV_PVAL, ts_bad_csum, discard, 0) 96036401Ssklower } 96136401Ssklower break; 96236401Ssklower 96336401Ssklower /* this is different from the above because in the context 96436401Ssklower * of concat/ sep tpdu_len might not be the same as hdr len 96536401Ssklower */ 96636401Ssklower caseof( AK_TPDU_type, TPP_checksum): 96736401Ssklower caseof( XAK_TPDU_type, TPP_checksum): 96836401Ssklower caseof( DC_TPDU_type, TPP_checksum): 96936401Ssklower if( tpcb->tp_use_checksum ) { 97037469Ssklower CHECK( iso_check_csum(m, (int)hdr->tpdu_li + 1), 97136401Ssklower E_TP_INV_PVAL, ts_bad_csum, discard, 0) 97236401Ssklower } 97336401Ssklower break; 97436401Ssklower #ifdef notdef 97536401Ssklower caseof( DR_TPDU_type, TPP_addl_info ): 97636401Ssklower /* ignore - its length and meaning are 97736401Ssklower * user defined and there's no way 97836401Ssklower * to pass this info to the user anyway 97936401Ssklower */ 98036401Ssklower break; 98136401Ssklower #endif notdef 98236401Ssklower 98336401Ssklower caseof( AK_TPDU_type, TPP_subseq ): 98436401Ssklower /* used after reduction of window */ 98536401Ssklower vb_getval(P, u_short, subseq); 98636401Ssklower subseq = ntohs(subseq); 98736401Ssklower IFDEBUG(D_ACKRECV) 98836401Ssklower printf("AK Subsequence # 0x%x\n", subseq); 98936401Ssklower ENDDEBUG 99036401Ssklower break; 99136401Ssklower 99236401Ssklower caseof( AK_TPDU_type, TPP_flow_cntl_conf ): 99336401Ssklower { 99436401Ssklower u_int ylwe; 99536401Ssklower u_short ysubseq, ycredit; 99636401Ssklower 99736401Ssklower fcc_present = TRUE; 99836401Ssklower vb_getval(P, u_int, ylwe); 99936401Ssklower vb_getval(P, u_short, ysubseq); 100036401Ssklower vb_getval(P, u_short, ycredit); 100136401Ssklower ylwe = ntohl(ylwe); 100236401Ssklower ysubseq = ntohs(ysubseq); 100336401Ssklower ycredit = ntohs(ycredit); 100436401Ssklower IFDEBUG(D_ACKRECV) 100536401Ssklower printf("AK FCC lwe 0x%x, subseq 0x%x, cdt 0x%x\n", 100636401Ssklower ylwe, ysubseq, ycredit); 100736401Ssklower ENDDEBUG 100836401Ssklower } 100936401Ssklower break; 101036401Ssklower 101136401Ssklower default: 101236401Ssklower IFDEBUG(D_TPINPUT) 101336401Ssklower printf("param ignored dutype 0x%x, code 0x%x\n", 101436401Ssklower dutype, vbptr(P)->tpv_code); 101536401Ssklower ENDDEBUG 101636401Ssklower IFTRACE(D_TPINPUT) 101736401Ssklower tptrace(TPPTmisc, "param ignored dutype code ", 101836401Ssklower dutype, vbptr(P)->tpv_code ,0,0); 101936401Ssklower ENDTRACE 102036401Ssklower IncStat(ts_param_ignored); 102136401Ssklower break; 102236401Ssklower #undef caseof 102336401Ssklower } 102436401Ssklower /* } */ END_WHILE_OPTIONS(P) 102536401Ssklower 102636401Ssklower /* NOTE: the variable dutype has been shifted left! */ 102736401Ssklower 102836401Ssklower switch( hdr->tpdu_type ) { 102936401Ssklower case CC_TPDU_type: 103036401Ssklower /* If CC comes back with an unacceptable class 103136401Ssklower * respond with a DR or ER 103236401Ssklower */ 103336401Ssklower 103436401Ssklower opt = hdr->tpdu_CCoptions; /* 1 byte */ 103536401Ssklower 103636401Ssklower { 103736401Ssklower tpp = tpcb->_tp_param; 103836401Ssklower tpp.p_class = (1<<hdr->tpdu_CCclass); 103936401Ssklower tpp.p_tpdusize = dusize; 104036401Ssklower tpp.p_dont_change_params = 0; 104136401Ssklower tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT; 104236401Ssklower tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD; 104336401Ssklower tpp.p_use_checksum = (addlopt & TPAO_NO_CSUM) == 0; 104436401Ssklower #ifdef notdef 104536401Ssklower tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC; 104636401Ssklower tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD; 104736401Ssklower tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC; 104836401Ssklower #endif notdef 104936401Ssklower 105036401Ssklower CHECK( 105136401Ssklower tp_consistency(tpcb, TP_FORCE, &tpp) != 0, 105236401Ssklower E_TP_NEGOT_FAILED, ts_negotfailed, respond, 105336401Ssklower (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 105436401Ssklower /* ^ more or less the location of class */ 105536401Ssklower ) 105636401Ssklower IFTRACE(D_CONN) 105736401Ssklower tptrace(TPPTmisc, 105836401Ssklower "after 1 consist class, out, tpconsout", 105936401Ssklower tpcb->tp_class, dgout_routine, tpcons_output, 0 106036401Ssklower ); 106136401Ssklower ENDTRACE 106236401Ssklower CHECK( 106336401Ssklower ((class_to_use == TP_CLASS_0)&& 106436401Ssklower (dgout_routine != tpcons_output)), 106536401Ssklower E_TP_NEGOT_FAILED, ts_negotfailed, respond, 106636401Ssklower (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 106736401Ssklower /* ^ more or less the location of class */ 106836401Ssklower ) 106936401Ssklower } 107036401Ssklower if( ! tpcb->tp_use_checksum) 107136401Ssklower IncStat(ts_csum_off); 107236401Ssklower if(tpcb->tp_xpd_service) 107336401Ssklower IncStat(ts_use_txpd); 107436401Ssklower if(tpcb->tp_xtd_format) 107536401Ssklower IncStat(ts_xtd_fmt); 107636401Ssklower 107736401Ssklower IFTRACE(D_CONN) 107836401Ssklower tptrace(TPPTmisc, "after CC class flags dusize CCclass", 107936401Ssklower tpcb->tp_class, tpcb->tp_flags, tpcb->tp_tpdusize, 108036401Ssklower hdr->tpdu_CCclass); 108136401Ssklower ENDTRACE 108236401Ssklower 108336401Ssklower /* 108436401Ssklower * Get the maximum transmission unit from the lower layer(s) 108536401Ssklower * so we can decide how large a TPDU size to negotiate. 108636401Ssklower * It would be nice if the arguments to this 108736401Ssklower * were more reasonable. 108836401Ssklower */ 108936401Ssklower (tpcb->tp_nlproto->nlp_mtu)(tpcb->tp_sock, tpcb->tp_sock->so_pcb, 109036401Ssklower &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0); 109136401Ssklower 109236401Ssklower #ifdef CONS 109336401Ssklower /* Could be that this CC came in on a NEW vc, in which case 109436401Ssklower * we have to confirm it. 109536401Ssklower */ 109636401Ssklower if( cons_channel ) 109736401Ssklower cons_netcmd( CONN_CONFIRM, tpcb->tp_npcb, cons_channel, 109836401Ssklower tpcb->tp_class == TP_CLASS_4); 109936401Ssklower #endif CONS 110036401Ssklower 110136401Ssklower tpcb->tp_peer_acktime = acktime; 110236401Ssklower 110336401Ssklower /* if called or calling suffices appeared on the CC, 110436401Ssklower * they'd better jive with what's in the pcb 110536401Ssklower */ 110636401Ssklower if( fsufxlen ) { 110736401Ssklower CHECK( ((tpcb->tp_fsuffixlen != fsufxlen) || 110836401Ssklower bcmp(fsufxloc, tpcb->tp_fsuffix, fsufxlen)), 110936401Ssklower E_TP_INV_PVAL,ts_inv_sufx, respond, 111036401Ssklower (1+fsufxloc - (caddr_t)hdr)) 111136401Ssklower } 111236401Ssklower if( lsufxlen ) { 111336401Ssklower CHECK( ((tpcb->tp_lsuffixlen != lsufxlen) || 111436401Ssklower bcmp(lsufxloc, tpcb->tp_lsuffix, lsufxlen)), 111536401Ssklower E_TP_INV_PVAL,ts_inv_sufx, respond, 111636401Ssklower (1+lsufxloc - (caddr_t)hdr)) 111736401Ssklower } 111836401Ssklower 111936401Ssklower e.ATTR(CC_TPDU).e_sref = sref; 112036401Ssklower e.ATTR(CC_TPDU).e_cdt = hdr->tpdu_CCcdt; 112136401Ssklower takes_data = TRUE; 112236401Ssklower e.ev_number = CC_TPDU; 112336401Ssklower IncStat(ts_CC_rcvd); 112436401Ssklower break; 112536401Ssklower 112636401Ssklower case DC_TPDU_type: 112736401Ssklower if (sref != tpcb->tp_fref) 112836401Ssklower printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n", 112936401Ssklower sref, tpcb->tp_fref); 113036401Ssklower 113136401Ssklower CHECK( (sref != tpcb->tp_fref), 1132*42944Ssklower E_TP_MISM_REFS, ts_inv_sufx, discard, 113336401Ssklower (1 + (caddr_t)&hdr->tpdu_DCsref - (caddr_t)hdr)) 1134*42944Ssklower 113536401Ssklower e.ev_number = DC_TPDU; 113636401Ssklower IncStat(ts_DC_rcvd); 113736401Ssklower break; 113836401Ssklower 113936401Ssklower case DR_TPDU_type: 114036401Ssklower IFTRACE(D_TPINPUT) 114136401Ssklower tptrace(TPPTmisc, "DR recvd", hdr->tpdu_DRreason, 0, 0, 0); 114236401Ssklower ENDTRACE 1143*42944Ssklower if (sref != tpcb->tp_fref) { 114436401Ssklower printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n", 114536401Ssklower sref, tpcb->tp_fref); 1146*42944Ssklower } 114736401Ssklower 1148*42944Ssklower CHECK( (sref != 0 && sref != tpcb->tp_fref && 1149*42944Ssklower tpcb->tp_state != TP_CRSENT), 1150*42944Ssklower (TP_ERROR_SNDC | E_TP_MISM_REFS),ts_inv_sufx, respond, 115136401Ssklower (1 + (caddr_t)&hdr->tpdu_DRsref - (caddr_t)hdr)) 115236401Ssklower 115336401Ssklower e.ATTR(DR_TPDU).e_reason = hdr->tpdu_DRreason; 115436401Ssklower e.ATTR(DR_TPDU).e_sref = (u_short)sref; 115536401Ssklower takes_data = TRUE; 115636401Ssklower e.ev_number = DR_TPDU; 115736401Ssklower IncStat(ts_DR_rcvd); 115836401Ssklower break; 115936401Ssklower 116036401Ssklower case ER_TPDU_type: 116136401Ssklower IFTRACE(D_TPINPUT) 116236401Ssklower tptrace(TPPTmisc, "ER recvd", hdr->tpdu_ERreason,0,0,0); 116336401Ssklower ENDTRACE 116436401Ssklower e.ev_number = ER_TPDU; 116536401Ssklower e.ATTR(ER_TPDU).e_reason = hdr->tpdu_ERreason; 116636401Ssklower IncStat(ts_ER_rcvd); 116736401Ssklower break; 116836401Ssklower 116936401Ssklower case AK_TPDU_type: 117036401Ssklower 117136401Ssklower e.ATTR(AK_TPDU).e_subseq = subseq; 117236401Ssklower e.ATTR(AK_TPDU).e_fcc_present = fcc_present; 117336401Ssklower 117436401Ssklower if (tpcb->tp_xtd_format) { 117536401Ssklower #ifdef BYTE_ORDER 117636401Ssklower union seq_type seqeotX; 117736401Ssklower 117836401Ssklower seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 117936401Ssklower e.ATTR(AK_TPDU).e_seq = seqeotX.s_seq; 118036401Ssklower e.ATTR(AK_TPDU).e_cdt = ntohs(hdr->tpdu_AKcdtX); 118136401Ssklower #else 118236401Ssklower e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdtX; 118336401Ssklower e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseqX; 118436401Ssklower #endif BYTE_ORDER 118536401Ssklower } else { 118636401Ssklower e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdt; 118736401Ssklower e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseq; 118836401Ssklower } 118936401Ssklower IFTRACE(D_TPINPUT) 119036401Ssklower tptrace(TPPTmisc, "AK recvd seq cdt subseq fcc_pres", 119136401Ssklower e.ATTR(AK_TPDU).e_seq, e.ATTR(AK_TPDU).e_cdt, 119236401Ssklower subseq, fcc_present); 119336401Ssklower ENDTRACE 119436401Ssklower 119536401Ssklower e.ev_number = AK_TPDU; 119636401Ssklower IncStat(ts_AK_rcvd); 119736401Ssklower IncPStat(tpcb, tps_AK_rcvd); 119836401Ssklower break; 119936401Ssklower 120036401Ssklower case XAK_TPDU_type: 120136401Ssklower if (tpcb->tp_xtd_format) { 120236401Ssklower #ifdef BYTE_ORDER 120336401Ssklower union seq_type seqeotX; 120436401Ssklower 120536401Ssklower seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 120636401Ssklower e.ATTR(XAK_TPDU).e_seq = seqeotX.s_seq; 120736401Ssklower #else 120836401Ssklower e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseqX; 120936401Ssklower #endif BYTE_ORDER 121036401Ssklower } else { 121136401Ssklower e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseq; 121236401Ssklower } 121336401Ssklower e.ev_number = XAK_TPDU; 121436401Ssklower IncStat(ts_XAK_rcvd); 121536401Ssklower IncPStat(tpcb, tps_XAK_rcvd); 121636401Ssklower break; 121736401Ssklower 121836401Ssklower case XPD_TPDU_type: 121936401Ssklower if (tpcb->tp_xtd_format) { 122036401Ssklower #ifdef BYTE_ORDER 122136401Ssklower union seq_type seqeotX; 122236401Ssklower 122336401Ssklower seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 122436401Ssklower e.ATTR(XPD_TPDU).e_seq = seqeotX.s_seq; 122536401Ssklower #else 122636401Ssklower e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseqX; 122736401Ssklower #endif BYTE_ORDER 122836401Ssklower } else { 122936401Ssklower e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseq; 123036401Ssklower } 123136401Ssklower takes_data = TRUE; 123236401Ssklower e.ev_number = XPD_TPDU; 123336401Ssklower IncStat(ts_XPD_rcvd); 123436401Ssklower IncPStat(tpcb, tps_XPD_rcvd); 123536401Ssklower break; 123636401Ssklower 123736401Ssklower case DT_TPDU_type: 123836401Ssklower { /* the y option will cause occasional packets to be dropped. 123936401Ssklower * A little crude but it works. 124036401Ssklower */ 124136401Ssklower 124236401Ssklower IFDEBUG(D_DROP) 124336401Ssklower if(time.tv_usec & 0x4 && hdr->tpdu_DTseq & 0x1) { 124436401Ssklower IncStat(ts_ydebug); 124536401Ssklower goto discard; 124636401Ssklower } 124736401Ssklower ENDDEBUG 124836401Ssklower } 124936401Ssklower if (tpcb->tp_class == TP_CLASS_0) { 125036401Ssklower e.ATTR(DT_TPDU).e_seq = 0; /* actually don't care */ 125136401Ssklower e.ATTR(DT_TPDU).e_eot = (((struct tp0du *)hdr)->tp0du_eot); 125236401Ssklower } else if (tpcb->tp_xtd_format) { 125336401Ssklower #ifdef BYTE_ORDER 125436401Ssklower union seq_type seqeotX; 125536401Ssklower 125636401Ssklower seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 125736401Ssklower e.ATTR(DT_TPDU).e_seq = seqeotX.s_seq; 125836401Ssklower e.ATTR(DT_TPDU).e_eot = seqeotX.s_eot; 125936401Ssklower #else 126036401Ssklower e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseqX; 126136401Ssklower e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeotX; 126236401Ssklower #endif BYTE_ORDER 126336401Ssklower } else { 126436401Ssklower e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseq; 126536401Ssklower e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeot; 126636401Ssklower } 126736401Ssklower if(e.ATTR(DT_TPDU).e_eot) 126836401Ssklower IncStat(ts_eot_input); 126936401Ssklower takes_data = TRUE; 127036401Ssklower e.ev_number = DT_TPDU; 127136401Ssklower IncStat(ts_DT_rcvd); 127236401Ssklower IncPStat(tpcb, tps_DT_rcvd); 127336401Ssklower break; 127436401Ssklower 127536401Ssklower case GR_TPDU_type: 127636401Ssklower tp_indicate(T_DISCONNECT, tpcb, ECONNABORTED); 127736401Ssklower /* drop through */ 127836401Ssklower default: 127936401Ssklower /* this should NEVER happen because there is a 128036401Ssklower * check for dutype well above here 128136401Ssklower */ 128236401Ssklower error = E_TP_INV_TPDU; /* causes an ER */ 128336401Ssklower IFDEBUG(D_TPINPUT) 128436401Ssklower printf("INVALID dutype 0x%x\n", hdr->tpdu_type); 128536401Ssklower ENDDEBUG 128636401Ssklower IncStat(ts_inv_dutype); 128736401Ssklower goto respond; 128836401Ssklower } 128936401Ssklower } 129036401Ssklower 129136401Ssklower /* peel off the tp header; 129236401Ssklower * remember that the du_li doesn't count itself. 129336401Ssklower * This may leave us w/ an empty mbuf at the front of a chain. 129436401Ssklower * We can't just throw away the empty mbuf because hdr still points 129536401Ssklower * into the mbuf's data area and we're still using hdr (the tpdu header) 129636401Ssklower */ 129736401Ssklower m->m_len -= ((int)hdr->tpdu_li + 1); 129837469Ssklower m->m_data += ((int)hdr->tpdu_li + 1); 129936401Ssklower 130037469Ssklower if (takes_data) { 130137469Ssklower int max = tpdu_info[ hdr->tpdu_type ] [TP_MAX_DATA_INDEX]; 130237469Ssklower int datalen = tpdu_len - hdr->tpdu_li - 1, mbtype = MT_DATA; 130342468Ssklower struct cmsghdr c_hdr; 130437469Ssklower struct mbuf *n; 130536401Ssklower 130637469Ssklower CHECK( (max && datalen > max), E_TP_LENGTH_INVAL, 130737469Ssklower ts_inv_length, respond, (max + hdr->tpdu_li + 1) ); 130836401Ssklower switch( hdr->tpdu_type ) { 130937469Ssklower 131036401Ssklower case CR_TPDU_type: 131137469Ssklower c_hdr.cmsg_type = TPOPT_CONN_DATA; 131237469Ssklower goto make_control_msg; 131337469Ssklower 131436401Ssklower case CC_TPDU_type: 131537469Ssklower c_hdr.cmsg_type = TPOPT_CFRM_DATA; 131637469Ssklower goto make_control_msg; 131737469Ssklower 131836401Ssklower case DR_TPDU_type: 131937469Ssklower c_hdr.cmsg_type = TPOPT_DISC_DATA; 132037469Ssklower make_control_msg: 132137469Ssklower c_hdr.cmsg_level = SOL_TRANSPORT; 132237469Ssklower mbtype = MT_CONTROL; 132340015Ssklower datalen += sizeof(c_hdr); 132440015Ssklower m->m_len += sizeof(c_hdr); 132540015Ssklower m->m_data -= sizeof(c_hdr); 132640015Ssklower c_hdr.cmsg_len = datalen; 132740015Ssklower bcopy((caddr_t)&c_hdr, mtod(m, caddr_t), sizeof(c_hdr)); 132837469Ssklower /* FALLTHROUGH */ 132937469Ssklower 133036401Ssklower case XPD_TPDU_type: 133137469Ssklower if (mbtype != MT_CONTROL) 133237469Ssklower mbtype = MT_OOBDATA; 133337469Ssklower m->m_flags |= M_EOR; 133437469Ssklower /* FALLTHROUGH */ 133537469Ssklower 133636401Ssklower case DT_TPDU_type: 133737469Ssklower for (n = m; n; n = n->m_next) { 133837469Ssklower MCHTYPE(n, mbtype); 133937469Ssklower } 134037469Ssklower e.ATTR(DT_TPDU).e_datalen = datalen; 134136401Ssklower e.ATTR(DT_TPDU).e_data = m; 134236401Ssklower break; 134336401Ssklower 134436401Ssklower default: 134536401Ssklower printf( 134636401Ssklower "ERROR in tp_input! hdr->tpdu_type 0x%x takes_data 0x%x m 0x%x\n", 134736401Ssklower hdr->tpdu_type, takes_data, m); 134836401Ssklower break; 134936401Ssklower } 135036401Ssklower /* prevent m_freem() after tp_driver() from throwing it all away */ 135136401Ssklower m = MNULL; 135236401Ssklower } 135336401Ssklower 135436401Ssklower IncStat(ts_tpdu_rcvd); 135536401Ssklower 135636401Ssklower IFDEBUG(D_TPINPUT) 135736401Ssklower printf( "tp_input: before driver, state 0x%x event 0x%x m 0x%x", 135836401Ssklower tpcb->tp_state, e.ev_number, m ); 135936401Ssklower printf(" e.e_data 0x%x\n", e.ATTR(DT_TPDU).e_data); 136036401Ssklower printf("takes_data 0x%x m_len 0x%x, tpdu_len 0x%x\n", 136136401Ssklower takes_data, (m==MNULL)?0:m->m_len, tpdu_len); 136236401Ssklower ENDDEBUG 136336401Ssklower 136436401Ssklower error = tp_driver(tpcb, &e); 136536401Ssklower 136636401Ssklower ASSERT(tpcb != (struct tp_pcb *)0); 136736401Ssklower ASSERT(tpcb->tp_sock != (struct socket *)0); 136836401Ssklower if( tpcb->tp_sock->so_error == 0 ) 136936401Ssklower tpcb->tp_sock->so_error = error; 137036401Ssklower 137136401Ssklower /* Kludge to keep the state tables under control (adding 137236401Ssklower * data on connect & disconnect & freeing the mbuf containing 137336401Ssklower * the data would have exploded the tables and made a big mess ). 137436401Ssklower */ 137536401Ssklower switch(e.ev_number) { 137636401Ssklower case CC_TPDU: 137736401Ssklower case DR_TPDU: 137836401Ssklower case CR_TPDU: 137936401Ssklower m = e.ATTR(CC_TPDU).e_data; /* same field for all three dutypes */ 138036401Ssklower IFDEBUG(D_TPINPUT) 138136401Ssklower printf("after driver, restoring m to 0x%x, takes_data 0x%x\n", 138236401Ssklower m, takes_data); 138336401Ssklower ENDDEBUG 138436401Ssklower break; 138536401Ssklower default: 138636401Ssklower break; 138736401Ssklower } 138836401Ssklower /* Concatenated sequences are terminated by any tpdu that 138936401Ssklower * carries data: CR, CC, DT, XPD, DR. 139036401Ssklower * All other tpdu types may be concatenated: AK, XAK, DC, ER. 139136401Ssklower */ 139236401Ssklower 139336401Ssklower separate: 139436401Ssklower if ( takes_data == 0 ) { 139536401Ssklower ASSERT( m != MNULL ); 139636401Ssklower /* 139736401Ssklower * we already peeled off the prev. tp header so 139836401Ssklower * we can just pull up some more and repeat 139936401Ssklower */ 140036401Ssklower 140137469Ssklower if( m = tp_inputprep(m) ) { 140236401Ssklower IFDEBUG(D_TPINPUT) 140336401Ssklower hdr = mtod(m, struct tpdu *); 140436401Ssklower printf("tp_input @ separate: hdr 0x%x size %d m 0x%x\n", 140536401Ssklower hdr, (int) hdr->tpdu_li + 1, m); 140636401Ssklower dump_mbuf(m, "tp_input after driver, at separate"); 140736401Ssklower ENDDEBUG 140836401Ssklower 140936401Ssklower IncStat(ts_concat_rcvd); 141036401Ssklower goto again; 141136401Ssklower } 141236401Ssklower } 141336401Ssklower if ( m != MNULL ) { 141436401Ssklower IFDEBUG(D_TPINPUT) 141536401Ssklower printf("tp_input : m_freem(0x%x)\n", m); 141636401Ssklower ENDDEBUG 141736401Ssklower m_freem(m); 141836401Ssklower IFDEBUG(D_TPINPUT) 141936401Ssklower printf("tp_input : after m_freem 0x%x\n", m); 142036401Ssklower ENDDEBUG 142136401Ssklower } 142236401Ssklower return (ProtoHook) tpcb; 142336401Ssklower 142436401Ssklower discard: 142536401Ssklower /* class 4: drop the tpdu */ 142636401Ssklower /* class 2,0: Should drop the net connection, if you can figure out 142736401Ssklower * to which connection it applies 142836401Ssklower */ 142936401Ssklower IFDEBUG(D_TPINPUT) 143036401Ssklower printf("tp_input DISCARD\n"); 143136401Ssklower ENDDEBUG 143236401Ssklower IFTRACE(D_TPINPUT) 143336401Ssklower tptrace(TPPTmisc, "tp_input DISCARD m", m,0,0,0); 143436401Ssklower ENDTRACE 143536401Ssklower m_freem(m); 143636401Ssklower IncStat(ts_recv_drop); 143736401Ssklower return (ProtoHook)0; 143836401Ssklower 1439*42944Ssklower nonx_dref: 1440*42944Ssklower switch (dutype) { 1441*42944Ssklower default: 1442*42944Ssklower goto discard; 1443*42944Ssklower case CC_TPDU_type: 1444*42944Ssklower /* error = E_TP_MISM_REFS; */ 1445*42944Ssklower break; 1446*42944Ssklower case DR_TPDU_type: 1447*42944Ssklower error |= TP_ERROR_SNDC; 1448*42944Ssklower } 144936401Ssklower respond: 145036401Ssklower IFDEBUG(D_ERROR_EMIT) 1451*42944Ssklower printf("RESPOND: error 0x%x, errlen 0x%x\n", error, errlen); 145236401Ssklower ENDDEBUG 145336401Ssklower IFTRACE(D_TPINPUT) 1454*42944Ssklower tptrace(TPPTmisc, "tp_input RESPOND m error sref", m, error, sref, 0); 145536401Ssklower ENDTRACE 1456*42944Ssklower if (sref == 0) 145736401Ssklower goto discard; 145837469Ssklower (void) tp_error_emit(error, (u_long)sref, (struct sockaddr_iso *)faddr, 1459*42944Ssklower (struct sockaddr_iso *)laddr, m, errlen, tpcb, 146037469Ssklower (int)cons_channel, dgout_routine); 146136401Ssklower IFDEBUG(D_ERROR_EMIT) 146236401Ssklower printf("tp_input after error_emit\n"); 146336401Ssklower ENDDEBUG 146436401Ssklower 146536401Ssklower #ifdef lint 146636401Ssklower printf("",sref,opt); 146736401Ssklower #endif lint 146836401Ssklower IncStat(ts_recv_drop); 146936401Ssklower return (ProtoHook)0; 147036401Ssklower } 147136401Ssklower 147236401Ssklower 147336401Ssklower /* 147436401Ssklower * NAME: tp_headersize() 147536401Ssklower * 147636401Ssklower * CALLED FROM: 147736401Ssklower * tp_emit() and tp_sbsend() 147836401Ssklower * TP needs to know the header size so it can figure out how 147936401Ssklower * much data to put in each tpdu. 148036401Ssklower * 148136401Ssklower * FUNCTION, ARGUMENTS, and RETURN VALUE: 148236401Ssklower * For a given connection, represented by (tpcb), and 148336401Ssklower * tpdu type (dutype), return the size of a tp header. 148436401Ssklower * 148536401Ssklower * RETURNS: the expected size of the heade in bytesr 148636401Ssklower * 148736401Ssklower * SIDE EFFECTS: 148836401Ssklower * 148936401Ssklower * NOTES: It would be nice if it got the network header size as well. 149036401Ssklower */ 149136401Ssklower int 149236401Ssklower tp_headersize(dutype, tpcb) 149336401Ssklower int dutype; 149436401Ssklower struct tp_pcb *tpcb; 149536401Ssklower { 149636401Ssklower register int size = 0; 149736401Ssklower 149836401Ssklower IFTRACE(D_CONN) 149936401Ssklower tptrace(TPPTmisc, "tp_headersize dutype class xtd_format", 150036401Ssklower dutype, tpcb->tp_class, tpcb->tp_xtd_format, 0); 150136401Ssklower ENDTRACE 150236401Ssklower if( !( (tpcb->tp_class == TP_CLASS_0) || 150336401Ssklower (tpcb->tp_class == TP_CLASS_4) || 150436401Ssklower (dutype == DR_TPDU_type) || 150536401Ssklower (dutype == CR_TPDU_type) )) { 150636401Ssklower printf("tp_headersize:dutype 0x%x, class 0x%x", 150736401Ssklower dutype, tpcb->tp_class); 150836401Ssklower /* TODO: identify this and GET RID OF IT */ 150936401Ssklower } 151036401Ssklower ASSERT( (tpcb->tp_class == TP_CLASS_0) || 151136401Ssklower (tpcb->tp_class == TP_CLASS_4) || 151236401Ssklower (dutype == DR_TPDU_type) || 151336401Ssklower (dutype == CR_TPDU_type) ); 151436401Ssklower 151536401Ssklower if( tpcb->tp_class == TP_CLASS_0 ) { 151636401Ssklower size = tpdu_info[ dutype ] [TP_LEN_CLASS_0_INDEX]; 151736401Ssklower } else { 151836401Ssklower size = tpdu_info[ dutype ] [tpcb->tp_xtd_format]; 151936401Ssklower } 152036401Ssklower return size; 152136401Ssklower /* caller must get network level header size separately */ 152236401Ssklower } 1523