📄 tp_input.c
字号:
* * NOTE: * The initial value of acktime is 2 so that we will never * have a 0 value for tp_peer_acktime. It gets used in the * computation of the retransmission timer value, and so it * mustn't be zero. * 2 seems like a reasonable minimum. */ProtoHooktp_input(m, faddr, laddr, cons_channel, dgout_routine, ce_bit) register struct mbuf *m; struct sockaddr *faddr, *laddr; /* NSAP addresses */ caddr_t cons_channel; int (*dgout_routine)(); int ce_bit;{ register struct tp_pcb *tpcb; register struct tpdu *hdr; struct socket *so; struct tp_event e; int error; unsigned dutype; u_short dref, sref, acktime, subseq; u_char preferred_class, class_to_use, pdusize; u_char opt, dusize, addlopt, version;#ifdef TP_PERF_MEAS u_char perf_meas;#endif /* TP_PERF_MEAS */ u_char fsufxlen, lsufxlen; caddr_t fsufxloc, lsufxloc; int tpdu_len; u_int takes_data; u_int fcc_present; int errlen; struct tp_conn_param tpp; int tpcons_output();again: hdr = mtod(m, struct tpdu *); tpcb = 0; error = errlen = tpdu_len = 0; takes_data = fcc_present = FALSE; acktime = 2; sref = subseq = 0; fsufxloc = lsufxloc = NULL; fsufxlen = lsufxlen = preferred_class = class_to_use = pdusize = addlopt = 0; dusize = TP_DFL_TPDUSIZE;#ifdef TP_PERF_MEAS GET_CUR_TIME( &e.e_time ); perf_meas = 0;#endif /* TP_PERF_MEAS */ IFDEBUG(D_TPINPUT) printf("tp_input(0x%x, ... 0x%x)\n", m, cons_channel); ENDDEBUG /* * get the actual tpdu length - necessary for monitoring * and for checksumming * * Also, maybe measure the mbuf chain lengths and sizes. */ { register struct mbuf *n=m;# ifdef ARGO_DEBUG int chain_length = 0;# endif ARGO_DEBUG for(;;) { tpdu_len += n->m_len; IFDEBUG(D_MBUF_MEAS) if( n->m_flags & M_EXT) { IncStat(ts_mb_cluster); } else { IncStat(ts_mb_small); } chain_length ++; ENDDEBUG if (n->m_next == MNULL ) { break; } n = n->m_next; } IFDEBUG(D_MBUF_MEAS) if(chain_length > 16) chain_length = 0; /* zero used for anything > 16 */ tp_stat.ts_mb_len_distr[chain_length] ++; ENDDEBUG } IFTRACE(D_TPINPUT) tptraceTPCB(TPPTtpduin, hdr->tpdu_type, hdr, hdr->tpdu_li+1, tpdu_len, 0); ENDTRACE dref = ntohs((short)hdr->tpdu_dref); sref = ntohs((short)hdr->tpdu_sref); dutype = (int)hdr->tpdu_type; IFDEBUG(D_TPINPUT) printf("input: dutype 0x%x cons_channel 0x%x dref 0x%x\n", dutype, cons_channel, dref); printf("input: dref 0x%x sref 0x%x\n", dref, sref); ENDDEBUG IFTRACE(D_TPINPUT) tptrace(TPPTmisc, "channel dutype dref ", cons_channel, dutype, dref, 0); ENDTRACE#ifdef ARGO_DEBUG if( (dutype < TP_MIN_TPDUTYPE) || (dutype > TP_MAX_TPDUTYPE)) { printf("BAD dutype! 0x%x, channel 0x%x dref 0x%x\n", dutype, cons_channel, dref); dump_buf (m, sizeof( struct mbuf )); IncStat(ts_inv_dutype); goto discard; }#endif /* ARGO_DEBUG */ CHECK( (dutype < TP_MIN_TPDUTYPE || dutype > TP_MAX_TPDUTYPE), E_TP_INV_TPDU, ts_inv_dutype, respond, 2 ); /* unfortunately we can't take the address of the tpdu_type field, * since it's a bit field - so we just use the constant offset 2 */ /* Now this isn't very neat but since you locate a pcb one way * at the beginning of connection establishment, and by * the dref for each tpdu after that, we have to treat CRs differently */ if ( dutype == CR_TPDU_type ) { u_char alt_classes = 0; preferred_class = 1 << hdr->tpdu_CRclass; opt = hdr->tpdu_CRoptions; WHILE_OPTIONS(P, hdr, 1 ) /* { */ switch( vbptr(P)->tpv_code ) { case TPP_tpdu_size: vb_getval(P, u_char, dusize); IFDEBUG(D_TPINPUT) printf("CR dusize 0x%x\n", dusize); ENDDEBUG /* COS tests: NBS IA (Dec. 1987) Sec. 4.5.2.1 */ if (dusize < TP_MIN_TPDUSIZE || dusize > TP_MAX_TPDUSIZE) dusize = TP_DFL_TPDUSIZE; break; case TPP_ptpdu_size: switch (vbptr(P)->tpv_len) { case 1: pdusize = vbval(P, u_char); break; case 2: pdusize = ntohs(vbval(P, u_short)); break; default: ; IFDEBUG(D_TPINPUT) printf("malformed prefered TPDU option\n"); ENDDEBUG } break; case TPP_addl_opt: vb_getval(P, u_char, addlopt); break; case TPP_calling_sufx: /* could use vb_getval, but we want to save the loc & len * for later use */ fsufxloc = (caddr_t) &vbptr(P)->tpv_val; fsufxlen = vbptr(P)->tpv_len; IFDEBUG(D_TPINPUT) printf("CR fsufx:"); { register int j; for(j=0; j<fsufxlen; j++ ) { printf(" 0x%x. ", *((caddr_t)(fsufxloc+j)) ); } printf("\n"); } ENDDEBUG break; case TPP_called_sufx: /* could use vb_getval, but we want to save the loc & len * for later use */ lsufxloc = (caddr_t) &vbptr(P)->tpv_val; lsufxlen = vbptr(P)->tpv_len; IFDEBUG(D_TPINPUT) printf("CR lsufx:"); { register int j; for(j=0; j<lsufxlen; j++ ) { printf(" 0x%x. ", *((u_char *)(lsufxloc+j)) ); } printf("\n"); } ENDDEBUG break;#ifdef TP_PERF_MEAS case TPP_perf_meas: vb_getval(P, u_char, perf_meas); break;#endif /* TP_PERF_MEAS */ case TPP_vers: /* not in class 0; 1 octet; in CR_TPDU only */ /* COS tests says if version wrong, use default version!?XXX */ CHECK( (vbval(P, u_char) != TP_VERSION ), E_TP_INV_PVAL, ts_inv_pval, setversion, (1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) ); setversion: version = vbval(P, u_char); break; case TPP_acktime: vb_getval(P, u_short, acktime); acktime = ntohs(acktime); acktime = acktime/500; /* convert to slowtimo ticks */ if((short)acktime <=0 ) acktime = 2; /* don't allow a bad peer to screw us up */ IFDEBUG(D_TPINPUT) printf("CR acktime 0x%x\n", acktime); ENDDEBUG break; case TPP_alt_class: { u_char *aclass = 0; register int i; static u_char bad_alt_classes[5] = { ~0, ~3, ~5, ~0xf, ~0x1f}; aclass = (u_char *) &(((struct tp_vbp *)P)->tpv_val); for (i = ((struct tp_vbp *)P)->tpv_len; i>0; i--) { alt_classes |= (1<<((*aclass++)>>4)); } CHECK( (bad_alt_classes[hdr->tpdu_CRclass] & alt_classes), E_TP_INV_PVAL, ts_inv_aclass, respond, ((caddr_t)aclass) - (caddr_t)hdr); IFDEBUG(D_TPINPUT) printf("alt_classes 0x%x\n", alt_classes); ENDDEBUG } break; case TPP_security: case TPP_residER: case TPP_priority: case TPP_transdelay: case TPP_throughput: case TPP_addl_info: case TPP_subseq: default: IFDEBUG(D_TPINPUT) printf("param ignored CR_TPDU code= 0x%x\n", vbptr(P)->tpv_code); ENDDEBUG IncStat(ts_param_ignored); break; case TPP_checksum: IFDEBUG(D_TPINPUT) printf("CR before cksum\n"); ENDDEBUG CHECK( iso_check_csum(m, tpdu_len), E_TP_INV_PVAL, ts_bad_csum, discard, 0) IFDEBUG(D_TPINPUT) printf("CR before cksum\n"); ENDDEBUG break; } /* } */ END_WHILE_OPTIONS(P) if (lsufxlen == 0) { /* can't look for a tpcb w/o any called sufx */ error = E_TP_LENGTH_INVAL; IncStat(ts_inv_sufx); goto respond; } else { register struct tp_pcb *t; /* * The intention here is to trap all CR requests * to a given nsap, for constructing transport * service bridges at user level; so these * intercepts should precede the normal listens. * Phrasing the logic in this way also allows for * mop-up listeners, which we don't currently implement. * We also wish to have a single socket be able to * listen over any network service provider, * (cons or clns or ip). */ for (t = tp_listeners; t ; t = t->tp_nextlisten) if ((t->tp_lsuffixlen == 0 || (lsufxlen == t->tp_lsuffixlen && bcmp(lsufxloc, t->tp_lsuffix, lsufxlen) == 0)) && ((t->tp_flags & TPF_GENERAL_ADDR) || (laddr->sa_family == t->tp_domain && (*t->tp_nlproto->nlp_cmpnetaddr) (t->tp_npcb, laddr, TP_LOCAL)))) break; CHECK(t == 0, E_TP_NO_SESSION, ts_inv_sufx, respond, (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) /* _tpduf is the fixed part; add 2 to get the dref bits of * the fixed part (can't take the address of a bit field) */ IFDEBUG(D_TPINPUT) printf("checking if dup CR\n"); ENDDEBUG tpcb = t; for (t = tpcb->tp_next; t != tpcb; t = t->tp_next) { if (sref != t->tp_fref) continue; if ((*tpcb->tp_nlproto->nlp_cmpnetaddr)( t->tp_npcb, faddr, TP_FOREIGN)) { IFDEBUG(D_TPINPUT) printf("duplicate CR discarded\n"); ENDDEBUG goto discard; } } IFTRACE(D_TPINPUT) tptrace(TPPTmisc, "tp_input: tpcb *lsufxloc tpstate", tpcb, *lsufxloc, tpcb->tp_state, 0); ENDTRACE } /* * WE HAVE A TPCB * already know that the classes in the CR match at least * one class implemented, but we don't know yet if they * include any classes permitted by this server. */ IFDEBUG(D_TPINPUT) printf("HAVE A TPCB 1: 0x%x\n", tpcb); ENDDEBUG IFDEBUG(D_CONN) printf("CR: bef CHKS: flags 0x%x class_to_use 0x%x alt 0x%x opt 0x%x tp_class 0x%x\n", tpcb->tp_flags, class_to_use, alt_classes, opt, tpcb->tp_class); ENDDEBUG /* tpcb->tp_class doesn't include any classes not implemented */ class_to_use = (preferred_class & tpcb->tp_class); if( (class_to_use = preferred_class & tpcb->tp_class) == 0 ) class_to_use = alt_classes & tpcb->tp_class; class_to_use = 1 << tp_mask_to_num(class_to_use); { tpp = tpcb->_tp_param; tpp.p_class = class_to_use; tpp.p_tpdusize = dusize; tpp.p_ptpdusize = pdusize; tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT; tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD; tpp.p_use_checksum = (tpp.p_class == TP_CLASS_0)?0: (addlopt & TPAO_NO_CSUM) == 0; tpp.p_version = version;#ifdef notdef tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC; tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD; tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC;#endif /* notdef */ CHECK( tp_consistency(tpcb, 0 /* not force or strict */, &tpp) != 0, E_TP_NEGOT_FAILED, ts_negotfailed, clear_parent_tcb, (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) /* ^ more or less the location of class */ ) } IFTRACE(D_CONN) tptrace(TPPTmisc, "after 1 consist class_to_use class, out, tpconsout", class_to_use, tpcb->tp_class, dgout_routine, tpcons_output ); ENDTRACE CHECK( ((class_to_use == TP_CLASS_0)&&(dgout_routine != tpcons_output)), E_TP_NEGOT_FAILED, ts_negotfailed, clear_parent_tcb, (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) /* ^ more or less the location of class */ ) IFDEBUG(D_CONN) printf("CR: after CRCCCHECKS: tpcb 0x%x, flags 0x%x\n", tpcb, tpcb->tp_flags); ENDDEBUG takes_data = TRUE; e.ATTR(CR_TPDU).e_cdt = hdr->tpdu_CRcdt; e.ev_number = CR_TPDU; so = tpcb->tp_sock; if (so->so_options & SO_ACCEPTCONN) { struct tp_pcb *parent_tpcb = tpcb; /* * Create a socket, tpcb, ll pcb, etc. * for this newborn connection, and fill in all the values. */ IFDEBUG(D_CONN) printf("abt to call tp_newsocket(0x%x, 0x%x, 0x%x, 0x%x)\n", so, laddr, faddr, cons_channel); ENDDEBUG if( (so =
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -