|
|
1.1 ! root 1: /*********************************************************** ! 2: Copyright IBM Corporation 1987 ! 3: ! 4: All Rights Reserved ! 5: ! 6: Permission to use, copy, modify, and distribute this software and its ! 7: documentation for any purpose and without fee is hereby granted, ! 8: provided that the above copyright notice appear in all copies and that ! 9: both that copyright notice and this permission notice appear in ! 10: supporting documentation, and that the name of IBM not be ! 11: used in advertising or publicity pertaining to distribution of the ! 12: software without specific, written prior permission. ! 13: ! 14: IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ! 15: ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL ! 16: IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ! 17: ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, ! 18: WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ! 19: ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS ! 20: SOFTWARE. ! 21: ! 22: ******************************************************************/ ! 23: ! 24: /* ! 25: * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison ! 26: */ ! 27: /* ! 28: * ARGO TP ! 29: * ! 30: * $Header: tp_input.c,v 5.6 88/11/18 17:27:38 nhall Exp $ ! 31: * $Source: /usr/argo/sys/netiso/RCS/tp_input.c,v $ ! 32: * @(#)tp_input.c 7.14 (Berkeley) 7/24/90 * ! 33: * ! 34: * tp_input() gets an mbuf chain from ip. Actually, not directly ! 35: * from ip, because ip calls a net-level routine that strips off ! 36: * the net header and then calls tp_input(), passing the proper type ! 37: * of addresses for the address family in use (how it figures out ! 38: * which AF is not yet determined. ! 39: * ! 40: * Decomposing the tpdu is some of the most laughable code. The variable-length ! 41: * parameters and the problem of non-aligned memory references ! 42: * necessitates such abominations as the macros WHILE_OPTIONS (q.v. below) ! 43: * to loop through the header and decompose it. ! 44: * ! 45: * The routine tp_newsocket() is called when a CR comes in for a listening ! 46: * socket. tp_input calls sonewconn() and tp_newsocket() to set up the ! 47: * "child" socket. Most tpcb values are copied from the parent tpcb into ! 48: * the child. ! 49: * ! 50: * Also in here is tp_headersize() (grot) which tells the expected size ! 51: * of a tp header, to be used by other layers. It's in here because it ! 52: * uses the static structure tpdu_info. ! 53: */ ! 54: ! 55: #ifndef lint ! 56: static char *rcsid = "$Header: tp_input.c,v 5.6 88/11/18 17:27:38 nhall Exp $"; ! 57: #endif lint ! 58: ! 59: #include "argoxtwentyfive.h" ! 60: #include "param.h" ! 61: #include "systm.h" ! 62: #include "mbuf.h" ! 63: #include "socket.h" ! 64: #include "socketvar.h" ! 65: #include "domain.h" ! 66: #include "protosw.h" ! 67: #include "errno.h" ! 68: #include "time.h" ! 69: #include "kernel.h" ! 70: #include "types.h" ! 71: #include "iso_errno.h" ! 72: #include "tp_param.h" ! 73: #include "tp_timer.h" ! 74: #include "tp_stat.h" ! 75: #include "tp_pcb.h" ! 76: #include "argo_debug.h" ! 77: #include "tp_trace.h" ! 78: #include "tp_tpdu.h" ! 79: #include "iso.h" ! 80: #include "cons.h" ! 81: ! 82: int iso_check_csum(), tp_driver(), tp_headersize(), tp_error_emit(); ! 83: ! 84: /* ! 85: #ifdef lint ! 86: #undef ATTR ! 87: #define ATTR(X)ev_number ! 88: #endif lint ! 89: */ ! 90: ! 91: struct mbuf * ! 92: tp_inputprep(m) ! 93: register struct mbuf *m; ! 94: { ! 95: int hdrlen; ! 96: ! 97: IFDEBUG(D_TPINPUT) ! 98: printf("tp_inputprep: m 0x%x\n", m) ; ! 99: ENDDEBUG ! 100: ! 101: while( m->m_len < 1 ) { ! 102: if( (m = m_free(m)) == MNULL ) { ! 103: return (struct mbuf *)0; ! 104: } ! 105: } ! 106: if(((int)m->m_data) & 0x3) { ! 107: /* If we are not 4-byte aligned, we have to be ! 108: * above the beginning of the mbuf, and it is ok just ! 109: * to slide it back. ! 110: */ ! 111: caddr_t ocp = m->m_data; ! 112: ! 113: m->m_data = (caddr_t)(((int)m->m_data) & ~0x3); ! 114: ovbcopy(ocp, m->m_data, (unsigned)m->m_len); ! 115: } ! 116: CHANGE_MTYPE(m, TPMT_DATA); ! 117: ! 118: /* we KNOW that there is at least 1 byte in this mbuf ! 119: and that it is hdr->tpdu_li XXXXXXX! */ ! 120: ! 121: hdrlen = 1 + *mtod( m, u_char *); ! 122: ! 123: /* ! 124: * now pull up the whole tp header ! 125: */ ! 126: if ( m->m_len < hdrlen) { ! 127: if ((m = m_pullup(m, hdrlen)) == MNULL ) { ! 128: IncStat(ts_recv_drop); ! 129: return (struct mbuf *)0; ! 130: } ! 131: } ! 132: IFDEBUG(D_INPUT) ! 133: printf( ! 134: " at end: m 0x%x hdr->tpdu_li 0x%x m_len 0x%x\n",m, ! 135: hdrlen, m->m_len); ! 136: ENDDEBUG ! 137: return m; ! 138: } ! 139: ! 140: /* begin groan ! 141: * -- this array and the following macros allow you to step through the ! 142: * parameters of the variable part of a header ! 143: * note that if for any reason the values of the **_TPDU macros (in tp_events.h) ! 144: * should change, this array has to be rearranged ! 145: */ ! 146: ! 147: #define TP_LEN_CLASS_0_INDEX 2 ! 148: #define TP_MAX_DATA_INDEX 3 ! 149: ! 150: static u_char tpdu_info[][4] = ! 151: { ! 152: /* length max data len */ ! 153: /* reg fmt xtd fmt class 0 */ ! 154: /* UNUSED 0x0 */ 0x0 , 0x0, 0x0, 0x0, ! 155: /* XPD_TPDU_type 0x1 */ 0x5, 0x8, 0x0, TP_MAX_XPD_DATA, ! 156: /* XAK_TPDU_type 0x2 */ 0x5 , 0x8, 0x0, 0x0, ! 157: /* GR_TPDU_type 0x3 */ 0x0 , 0x0, 0x0, 0x0, ! 158: /* UNUSED 0x4 */ 0x0 , 0x0, 0x0, 0x0, ! 159: /* UNUSED 0x5 */ 0x0 , 0x0, 0x0, 0x0, ! 160: /* AK_TPDU_type 0x6 */ 0x5, 0xa, 0x0, 0x0, ! 161: /* ER_TPDU_type 0x7 */ 0x5, 0x5, 0x0, 0x0, ! 162: /* DR_TPDU_type 0x8 */ 0x7, 0x7, 0x7, TP_MAX_DR_DATA, ! 163: /* UNUSED 0x9 */ 0x0 , 0x0, 0x0, 0x0, ! 164: /* UNUSED 0xa */ 0x0 , 0x0, 0x0, 0x0, ! 165: /* UNUSED 0xb */ 0x0 , 0x0, 0x0, 0x0, ! 166: /* DC_TPDU_type 0xc */ 0x6, 0x6, 0x0, 0x0, ! 167: /* CC_TPDU_type 0xd */ 0x7, 0x7, 0x7, TP_MAX_CC_DATA, ! 168: /* CR_TPDU_type 0xe */ 0x7, 0x7, 0x7, TP_MAX_CR_DATA, ! 169: /* DT_TPDU_type 0xf */ 0x5, 0x8, 0x3, 0x0, ! 170: }; ! 171: ! 172: #define CHECK(Phrase, Erval, Stat, Whattodo, Loc)\ ! 173: if (Phrase) {error = (Erval); errlen = (int)(Loc); IncStat(Stat); tpibrk();\ ! 174: goto Whattodo; } ! 175: ! 176: tpibrk() {} ! 177: ! 178: /* ! 179: * WHENEVER YOU USE THE FOLLOWING MACRO, ! 180: * BE SURE THE TPDUTYPE IS A LEGIT VALUE FIRST! ! 181: */ ! 182: ! 183: #define WHILE_OPTIONS(P, hdr, format)\ ! 184: { register caddr_t P = tpdu_info[(hdr)->tpdu_type][(format)] + (caddr_t)hdr;\ ! 185: caddr_t PLIM = 1 + hdr->tpdu_li + (caddr_t)hdr;\ ! 186: for (;; P += 2 + ((struct tp_vbp *)P)->tpv_len) {\ ! 187: CHECK((P > PLIM), E_TP_LENGTH_INVAL, ts_inv_length,\ ! 188: respond, P - (caddr_t)hdr);\ ! 189: if (P == PLIM) break; ! 190: ! 191: #define END_WHILE_OPTIONS(P) } } ! 192: ! 193: /* end groan */ ! 194: ! 195: /* ! 196: * NAME: tp_newsocket() ! 197: * ! 198: * CALLED FROM: ! 199: * tp_input() on incoming CR, when a socket w/ the called suffix ! 200: * is awaiting a connection request ! 201: * ! 202: * FUNCTION and ARGUMENTS: ! 203: * Create a new socket structure, attach to it a new transport pcb, ! 204: * using a copy of the net level pcb for the parent socket. ! 205: * (so) is the parent socket. ! 206: * (fname) is the foreign address (all that's used is the nsap portion) ! 207: * ! 208: * RETURN VALUE: ! 209: * a new socket structure, being this end of the newly formed connection. ! 210: * ! 211: * SIDE EFFECTS: ! 212: * Sets a few things in the tpcb and net level pcb ! 213: * ! 214: * NOTES: ! 215: */ ! 216: static struct socket * ! 217: tp_newsocket(so, fname, cons_channel, class_to_use, netservice) ! 218: struct socket *so; ! 219: struct sockaddr *fname; ! 220: u_int cons_channel; ! 221: u_char class_to_use; ! 222: u_int netservice; ! 223: { ! 224: register struct tp_pcb *tpcb = sototpcb(so); /* old tpcb, needed below */ ! 225: struct tp_pcb * newtpcb; ! 226: ! 227: /* ! 228: * sonewconn() gets a new socket structure, ! 229: * a new lower layer pcb and a new tpcb, ! 230: * but the pcbs are unnamed (not bound) ! 231: */ ! 232: IFTRACE(D_NEWSOCK) ! 233: tptraceTPCB(TPPTmisc, "newsock: listg_so, _tpcb, so_head", ! 234: so, tpcb, so->so_head, 0); ! 235: ENDTRACE ! 236: ! 237: if ((so = sonewconn(so, SS_ISCONFIRMING)) == (struct socket *)0) ! 238: return so; ! 239: IFTRACE(D_NEWSOCK) ! 240: tptraceTPCB(TPPTmisc, "newsock: after newconn so, so_head", ! 241: so, so->so_head, 0, 0); ! 242: ENDTRACE ! 243: ! 244: IFDEBUG(D_NEWSOCK) ! 245: printf("tp_newsocket(channel 0x%x) after sonewconn so 0x%x \n", ! 246: cons_channel, so); ! 247: dump_addr(fname); ! 248: { ! 249: struct socket *t, *head ; ! 250: ! 251: head = so->so_head; ! 252: t = so; ! 253: printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n", ! 254: t, t->so_head, t->so_q0, t->so_q0len); ! 255: while( (t=t->so_q0) && t!= so && t!= head) ! 256: printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n", ! 257: t, t->so_head, t->so_q0, t->so_q0len); ! 258: } ! 259: ENDDEBUG ! 260: ! 261: /* ! 262: * before we clobber the old tpcb ptr, get these items from the parent pcb ! 263: */ ! 264: newtpcb = sototpcb(so); ! 265: newtpcb->_tp_param = tpcb->_tp_param; ! 266: newtpcb->tp_flags = tpcb->tp_flags; ! 267: newtpcb->tp_lcredit = tpcb->tp_lcredit; ! 268: newtpcb->tp_l_tpdusize = tpcb->tp_l_tpdusize; ! 269: newtpcb->tp_lsuffixlen = tpcb->tp_lsuffixlen; ! 270: bcopy( tpcb->tp_lsuffix, newtpcb->tp_lsuffix, newtpcb->tp_lsuffixlen); ! 271: soreserve(so, (u_long)tpcb->tp_winsize, (u_long)tpcb->tp_winsize); ! 272: ! 273: if( /* old */ tpcb->tp_ucddata) { ! 274: /* ! 275: * These data are the connect- , confirm- or disconnect- data. ! 276: */ ! 277: struct mbuf *conndata; ! 278: ! 279: conndata = m_copy(tpcb->tp_ucddata, 0, (int)M_COPYALL); ! 280: IFDEBUG(D_CONN) ! 281: dump_mbuf(conndata, "conndata after mcopy"); ! 282: ENDDEBUG ! 283: newtpcb->tp_ucddata = conndata; ! 284: } ! 285: ! 286: tpcb = newtpcb; ! 287: tpcb->tp_state = TP_LISTENING; ! 288: tpcb->tp_class = class_to_use; ! 289: tpcb->tp_netservice = netservice; ! 290: ! 291: ! 292: ASSERT( fname != 0 ) ; /* just checking */ ! 293: if ( fname ) { ! 294: /* ! 295: * tp_route_to takes its address argument in the form of an mbuf. ! 296: */ ! 297: struct mbuf *m; ! 298: int err; ! 299: ! 300: MGET(m, M_DONTWAIT, MT_SONAME); /* mbuf type used is confusing */ ! 301: if (m) { ! 302: /* ! 303: * this seems a bit grotesque, but tp_route_to expects ! 304: * an mbuf * instead of simply a sockaddr; it calls the ll ! 305: * pcb_connect, which expects the name/addr in an mbuf as well. ! 306: * sigh. ! 307: */ ! 308: bcopy((caddr_t)fname, mtod(m, caddr_t), fname->sa_len); ! 309: m->m_len = fname->sa_len; ! 310: ! 311: /* grot : have to say the kernel can override params in ! 312: * the passive open case ! 313: */ ! 314: tpcb->tp_dont_change_params = 0; ! 315: err = tp_route_to( m, tpcb, cons_channel); ! 316: m_free(m); ! 317: ! 318: if (!err) ! 319: goto ok; ! 320: } ! 321: IFDEBUG(D_CONN) ! 322: printf("tp_route_to FAILED! detaching tpcb 0x%x, so 0x%x\n", ! 323: tpcb, so); ! 324: ENDDEBUG ! 325: (void) tp_detach(tpcb); ! 326: return 0; ! 327: } ! 328: ok: ! 329: IFDEBUG(D_TPINPUT) ! 330: printf("tp_newsocket returning so 0x%x, sototpcb(so) 0x%x\n", ! 331: so, sototpcb(so)); ! 332: ENDDEBUG ! 333: return so; ! 334: } ! 335: ! 336: #ifndef CONS ! 337: tpcons_output() ! 338: { ! 339: return(0); ! 340: } ! 341: #endif !CONS ! 342: ! 343: /* ! 344: * NAME: tp_input() ! 345: * ! 346: * CALLED FROM: ! 347: * net layer input routine ! 348: * ! 349: * FUNCTION and ARGUMENTS: ! 350: * Process an incoming TPDU (m), finding the associated tpcb if there ! 351: * is one. Create the appropriate type of event and call the driver. ! 352: * (faddr) and (laddr) are the foreign and local addresses. ! 353: * ! 354: * When tp_input() is called we KNOW that the ENTIRE TP HEADER ! 355: * has been m_pullup-ed. ! 356: * ! 357: * RETURN VALUE: Nada ! 358: * ! 359: * SIDE EFFECTS: ! 360: * When using COSNS it may affect the state of the net-level pcb ! 361: * ! 362: * NOTE: ! 363: * The initial value of acktime is 2 so that we will never ! 364: * have a 0 value for tp_peer_acktime. It gets used in the ! 365: * computation of the retransmission timer value, and so it ! 366: * mustn't be zero. ! 367: * 2 seems like a reasonable minimum. ! 368: */ ! 369: ProtoHook ! 370: tp_input(m, faddr, laddr, cons_channel, dgout_routine, ce_bit) ! 371: register struct mbuf *m; ! 372: struct sockaddr *faddr, *laddr; /* NSAP addresses */ ! 373: u_int cons_channel; ! 374: int (*dgout_routine)(); ! 375: int ce_bit; ! 376: ! 377: { ! 378: register struct tp_pcb *tpcb = (struct tp_pcb *)0; ! 379: register struct tpdu *hdr; ! 380: struct socket *so; ! 381: struct tp_event e; ! 382: int error = 0; ! 383: unsigned dutype; ! 384: u_short dref, sref = 0, acktime = 2, subseq = 0; /*VAX*/ ! 385: u_char preferred_class = 0, class_to_use = 0; ! 386: u_char opt, dusize = TP_DFL_TPDUSIZE, addlopt = 0, version; ! 387: #ifdef TP_PERF_MEAS ! 388: u_char perf_meas; ! 389: #endif TP_PERF_MEAS ! 390: u_char fsufxlen = 0, lsufxlen = 0, intercepted = 0; ! 391: caddr_t fsufxloc = 0, lsufxloc = 0; ! 392: int tpdu_len = 0; ! 393: u_int takes_data = FALSE; ! 394: u_int fcc_present = FALSE; ! 395: int errlen = 0; ! 396: struct tp_conn_param tpp; ! 397: int tpcons_output(); ! 398: ! 399: again: ! 400: hdr = mtod(m, struct tpdu *); ! 401: #ifdef TP_PERF_MEAS ! 402: GET_CUR_TIME( &e.e_time ); perf_meas = 0; ! 403: #endif TP_PERF_MEAS ! 404: ! 405: IFDEBUG(D_TPINPUT) ! 406: printf("tp_input(0x%x, ... 0x%x)\n", m, cons_channel); ! 407: ENDDEBUG ! 408: ! 409: ! 410: /* ! 411: * get the actual tpdu length - necessary for monitoring ! 412: * and for checksumming ! 413: * ! 414: * Also, maybe measure the mbuf chain lengths and sizes. ! 415: */ ! 416: ! 417: { register struct mbuf *n=m; ! 418: # ifdef ARGO_DEBUG ! 419: int chain_length = 0; ! 420: # endif ARGO_DEBUG ! 421: ! 422: for(;;) { ! 423: tpdu_len += n->m_len; ! 424: IFDEBUG(D_MBUF_MEAS) ! 425: if( n->m_flags & M_EXT) { ! 426: IncStat(ts_mb_cluster); ! 427: } else { ! 428: IncStat(ts_mb_small); ! 429: } ! 430: chain_length ++; ! 431: ENDDEBUG ! 432: if (n->m_next == MNULL ) { ! 433: break; ! 434: } ! 435: n = n->m_next; ! 436: } ! 437: IFDEBUG(D_MBUF_MEAS) ! 438: if(chain_length > 16) ! 439: chain_length = 0; /* zero used for anything > 16 */ ! 440: tp_stat.ts_mb_len_distr[chain_length] ++; ! 441: ENDDEBUG ! 442: } ! 443: IFTRACE(D_TPINPUT) ! 444: tptraceTPCB(TPPTtpduin, hdr->tpdu_type, hdr, hdr->tpdu_li+1, tpdu_len, ! 445: 0); ! 446: ENDTRACE ! 447: ! 448: dref = ntohs((short)hdr->tpdu_dref); ! 449: sref = ntohs((short)hdr->tpdu_sref); ! 450: dutype = (int)hdr->tpdu_type; ! 451: ! 452: IFDEBUG(D_TPINPUT) ! 453: printf("input: dutype 0x%x cons_channel 0x%x dref 0x%x\n", dutype, ! 454: cons_channel, dref); ! 455: printf("input: dref 0x%x sref 0x%x\n", dref, sref); ! 456: ENDDEBUG ! 457: IFTRACE(D_TPINPUT) ! 458: tptrace(TPPTmisc, "channel dutype dref ", ! 459: cons_channel, dutype, dref, 0); ! 460: ENDTRACE ! 461: ! 462: ! 463: #ifdef ARGO_DEBUG ! 464: if( (dutype < TP_MIN_TPDUTYPE) || (dutype > TP_MAX_TPDUTYPE)) { ! 465: printf("BAD dutype! 0x%x, channel 0x%x dref 0x%x\n", ! 466: dutype, cons_channel, dref); ! 467: dump_buf (m, sizeof( struct mbuf )); ! 468: ! 469: IncStat(ts_inv_dutype); ! 470: goto discard; ! 471: } ! 472: #endif ARGO_DEBUG ! 473: ! 474: CHECK( (dutype < TP_MIN_TPDUTYPE || dutype > TP_MAX_TPDUTYPE), ! 475: E_TP_INV_TPDU, ts_inv_dutype, respond, ! 476: 2 ); ! 477: /* unfortunately we can't take the address of the tpdu_type field, ! 478: * since it's a bit field - so we just use the constant offset 2 ! 479: */ ! 480: ! 481: /* Now this isn't very neat but since you locate a pcb one way ! 482: * at the beginning of connection establishment, and by ! 483: * the dref for each tpdu after that, we have to treat CRs differently ! 484: */ ! 485: if ( dutype == CR_TPDU_type ) { ! 486: u_char alt_classes = 0; ! 487: ! 488: preferred_class = 1 << hdr->tpdu_CRclass; ! 489: opt = hdr->tpdu_CRoptions; ! 490: ! 491: WHILE_OPTIONS(P, hdr, 1 ) /* { */ ! 492: ! 493: switch( vbptr(P)->tpv_code ) { ! 494: ! 495: case TPP_tpdu_size: ! 496: vb_getval(P, u_char, dusize); ! 497: IFDEBUG(D_TPINPUT) ! 498: printf("CR dusize 0x%x\n", dusize); ! 499: ENDDEBUG ! 500: /* COS tests: NBS IA (Dec. 1987) Sec. 4.5.2.1 */ ! 501: if (dusize < TP_MIN_TPDUSIZE || dusize > TP_MAX_TPDUSIZE) ! 502: dusize = TP_DFL_TPDUSIZE; ! 503: break; ! 504: case TPP_addl_opt: ! 505: vb_getval(P, u_char, addlopt); ! 506: break; ! 507: case TPP_calling_sufx: ! 508: /* could use vb_getval, but we want to save the loc & len ! 509: * for later use ! 510: */ ! 511: fsufxloc = (caddr_t) &vbptr(P)->tpv_val; ! 512: fsufxlen = vbptr(P)->tpv_len; ! 513: IFDEBUG(D_TPINPUT) ! 514: printf("CR fsufx:"); ! 515: { register int j; ! 516: for(j=0; j<fsufxlen; j++ ) { ! 517: printf(" 0x%x. ", *((caddr_t)(fsufxloc+j)) ); ! 518: } ! 519: printf("\n"); ! 520: } ! 521: ENDDEBUG ! 522: break; ! 523: case TPP_called_sufx: ! 524: /* could use vb_getval, but we want to save the loc & len ! 525: * for later use ! 526: */ ! 527: lsufxloc = (caddr_t) &vbptr(P)->tpv_val; ! 528: lsufxlen = vbptr(P)->tpv_len; ! 529: IFDEBUG(D_TPINPUT) ! 530: printf("CR lsufx:"); ! 531: { register int j; ! 532: for(j=0; j<lsufxlen; j++ ) { ! 533: printf(" 0x%x. ", *((u_char *)(lsufxloc+j)) ); ! 534: } ! 535: printf("\n"); ! 536: } ! 537: ENDDEBUG ! 538: break; ! 539: ! 540: #ifdef TP_PERF_MEAS ! 541: case TPP_perf_meas: ! 542: vb_getval(P, u_char, perf_meas); ! 543: break; ! 544: #endif TP_PERF_MEAS ! 545: ! 546: case TPP_vers: ! 547: /* not in class 0; 1 octet; in CR_TPDU only */ ! 548: /* COS tests says if version wrong, use default version!?XXX */ ! 549: CHECK( (vbval(P, u_char) != TP_VERSION ), ! 550: E_TP_INV_PVAL, ts_inv_pval, setversion, ! 551: (1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) ); ! 552: setversion: ! 553: version = vbval(P, u_char); ! 554: break; ! 555: case TPP_acktime: ! 556: vb_getval(P, u_short, acktime); ! 557: acktime = ntohs(acktime); ! 558: acktime = acktime/500; /* convert to slowtimo ticks */ ! 559: if((short)acktime <=0 ) ! 560: acktime = 2; /* don't allow a bad peer to screw us up */ ! 561: IFDEBUG(D_TPINPUT) ! 562: printf("CR acktime 0x%x\n", acktime); ! 563: ENDDEBUG ! 564: break; ! 565: ! 566: case TPP_alt_class: ! 567: { ! 568: u_char *aclass = 0; ! 569: register int i; ! 570: static u_char bad_alt_classes[5] = ! 571: { ~0, ~3, ~5, ~0xf, ~0x1f}; ! 572: ! 573: aclass = ! 574: (u_char *) &(((struct tp_vbp *)P)->tpv_val); ! 575: for (i = ((struct tp_vbp *)P)->tpv_len; i>0; i--) { ! 576: alt_classes |= (1<<((*aclass++)>>4)); ! 577: } ! 578: CHECK( (bad_alt_classes[hdr->tpdu_CRclass] & alt_classes), ! 579: E_TP_INV_PVAL, ts_inv_aclass, respond, ! 580: ((caddr_t)aclass) - (caddr_t)hdr); ! 581: IFDEBUG(D_TPINPUT) ! 582: printf("alt_classes 0x%x\n", alt_classes); ! 583: ENDDEBUG ! 584: } ! 585: break; ! 586: ! 587: case TPP_security: ! 588: case TPP_residER: ! 589: case TPP_priority: ! 590: case TPP_transdelay: ! 591: case TPP_throughput: ! 592: case TPP_addl_info: ! 593: case TPP_subseq: ! 594: default: ! 595: IFDEBUG(D_TPINPUT) ! 596: printf("param ignored CR_TPDU code= 0x%x\n", ! 597: vbptr(P)->tpv_code); ! 598: ENDDEBUG ! 599: IncStat(ts_param_ignored); ! 600: break; ! 601: ! 602: case TPP_checksum: ! 603: IFDEBUG(D_TPINPUT) ! 604: printf("CR before cksum\n"); ! 605: ENDDEBUG ! 606: ! 607: CHECK( iso_check_csum(m, tpdu_len), ! 608: E_TP_INV_PVAL, ts_bad_csum, discard, 0) ! 609: ! 610: IFDEBUG(D_TPINPUT) ! 611: printf("CR before cksum\n"); ! 612: ENDDEBUG ! 613: break; ! 614: } ! 615: ! 616: /* } */ END_WHILE_OPTIONS(P) ! 617: ! 618: if (lsufxlen == 0) { ! 619: /* can't look for a tpcb w/o any called sufx */ ! 620: error = E_TP_LENGTH_INVAL; ! 621: IncStat(ts_inv_sufx); ! 622: goto respond; ! 623: } else { ! 624: register struct tp_pcb *t; ! 625: ! 626: for (t = tp_intercepts; t ; t = t->tp_nextlisten) { ! 627: if (laddr->sa_family != t->tp_nlproto->nlp_afamily) ! 628: continue; ! 629: if ((*t->tp_nlproto->nlp_cmpnetaddr)( ! 630: t->tp_npcb, laddr, TP_LOCAL)) { ! 631: intercepted = 1; ! 632: goto check_duplicate_cr; ! 633: } ! 634: } ! 635: for (t = tp_listeners; t ; t = t->tp_nextlisten) ! 636: if (bcmp(lsufxloc, t->tp_lsuffix, lsufxlen) == 0 && ! 637: laddr->sa_family == t->tp_nlproto->nlp_afamily) ! 638: break; ! 639: CHECK(t == 0, E_TP_NO_SESSION, ts_inv_sufx, respond, ! 640: (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) ! 641: /* _tpduf is the fixed part; add 2 to get the dref bits of ! 642: * the fixed part (can't take the address of a bit field) ! 643: */ ! 644: IFDEBUG(D_TPINPUT) ! 645: printf("checking if dup CR\n"); ! 646: ENDDEBUG ! 647: check_duplicate_cr: ! 648: tpcb = t; ! 649: for (t = tpcb->tp_next; t != tpcb; t = t->tp_next) { ! 650: if (sref != t->tp_fref) ! 651: continue; ! 652: if ((*tpcb->tp_nlproto->nlp_cmpnetaddr)( ! 653: t->tp_npcb, faddr, TP_FOREIGN)) { ! 654: IFDEBUG(D_TPINPUT) ! 655: printf("duplicate CR discarded\n"); ! 656: ENDDEBUG ! 657: goto discard; ! 658: } ! 659: } ! 660: IFTRACE(D_TPINPUT) ! 661: tptrace(TPPTmisc, "tp_input: tpcb *lsufxloc tpstate", ! 662: tpcb, *lsufxloc, tpcb->tp_state, 0); ! 663: ENDTRACE ! 664: } ! 665: ! 666: /* ! 667: * WE HAVE A TPCB ! 668: * already know that the classes in the CR match at least ! 669: * one class implemented, but we don't know yet if they ! 670: * include any classes permitted by this server. ! 671: */ ! 672: ! 673: IFDEBUG(D_TPINPUT) ! 674: printf("HAVE A TPCB 1: 0x%x\n", tpcb); ! 675: ENDDEBUG ! 676: IFDEBUG(D_CONN) ! 677: printf( ! 678: "CR: bef CHKS: flags 0x%x class_to_use 0x%x alt 0x%x opt 0x%x tp_class 0x%x\n", ! 679: tpcb->tp_flags, class_to_use, alt_classes, opt, tpcb->tp_class); ! 680: ENDDEBUG ! 681: /* tpcb->tp_class doesn't include any classes not implemented */ ! 682: class_to_use = (preferred_class & tpcb->tp_class); ! 683: if( (class_to_use = preferred_class & tpcb->tp_class) == 0 ) ! 684: class_to_use = alt_classes & tpcb->tp_class; ! 685: ! 686: class_to_use = 1 << tp_mask_to_num(class_to_use); ! 687: ! 688: { ! 689: tpp = tpcb->_tp_param; ! 690: tpp.p_class = class_to_use; ! 691: tpp.p_tpdusize = dusize; ! 692: tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT; ! 693: tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD; ! 694: tpp.p_use_checksum = (tpp.p_class == TP_CLASS_0)?0: ! 695: (addlopt & TPAO_NO_CSUM) == 0; ! 696: tpp.p_version = version; ! 697: #ifdef notdef ! 698: tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC; ! 699: tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD; ! 700: tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC; ! 701: #endif notdef ! 702: ! 703: CHECK( ! 704: tp_consistency(tpcb, 0 /* not force or strict */, &tpp) != 0, ! 705: E_TP_NEGOT_FAILED, ts_negotfailed, respond, ! 706: (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) ! 707: /* ^ more or less the location of class */ ! 708: ) ! 709: } ! 710: IFTRACE(D_CONN) ! 711: tptrace(TPPTmisc, ! 712: "after 1 consist class_to_use class, out, tpconsout", ! 713: class_to_use, ! 714: tpcb->tp_class, dgout_routine, tpcons_output ! 715: ); ! 716: ENDTRACE ! 717: CHECK( ! 718: ((class_to_use == TP_CLASS_0)&&(dgout_routine != tpcons_output)), ! 719: E_TP_NEGOT_FAILED, ts_negotfailed, respond, ! 720: (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) ! 721: /* ^ more or less the location of class */ ! 722: ) ! 723: IFDEBUG(D_CONN) ! 724: printf("CR: after CRCCCHECKS: tpcb 0x%x, flags 0x%x\n", ! 725: tpcb, tpcb->tp_flags); ! 726: ENDDEBUG ! 727: takes_data = TRUE; ! 728: e.ATTR(CR_TPDU).e_cdt = hdr->tpdu_CRcdt; ! 729: e.ev_number = CR_TPDU; ! 730: ! 731: so = tpcb->tp_sock; ! 732: if (so->so_options & SO_ACCEPTCONN) { ! 733: struct tp_pcb *parent_tpcb = tpcb; ! 734: /* ! 735: * Create a socket, tpcb, ll pcb, etc. ! 736: * for this newborn connection, and fill in all the values. ! 737: */ ! 738: IFDEBUG(D_CONN) ! 739: printf("abt to call tp_newsocket(0x%x, 0x%x, 0x%x, 0x%x)\n", ! 740: so, laddr, faddr, cons_channel); ! 741: ENDDEBUG ! 742: if( (so = ! 743: tp_newsocket(so, faddr, cons_channel, ! 744: class_to_use, ! 745: ((tpcb->tp_netservice == IN_CLNS) ? IN_CLNS : ! 746: (dgout_routine == tpcons_output)?ISO_CONS:ISO_CLNS)) ! 747: ) == (struct socket *)0 ) { ! 748: /* note - even if netservice is IN_CLNS, as far as ! 749: * the tp entity is concerned, the only differences ! 750: * are CO vs CL ! 751: */ ! 752: IFDEBUG(D_CONN) ! 753: printf("tp_newsocket returns 0\n"); ! 754: ENDDEBUG ! 755: goto discard; ! 756: } ! 757: tpcb = sototpcb(so); ! 758: insque(tpcb, parent_tpcb); ! 759: ! 760: /* ! 761: * Stash the addresses in the net level pcb ! 762: * kind of like a pcbconnect() but don't need ! 763: * or want all those checks. ! 764: */ ! 765: (tpcb->tp_nlproto->nlp_putnetaddr)(so->so_pcb, faddr, TP_FOREIGN); ! 766: (tpcb->tp_nlproto->nlp_putnetaddr)(so->so_pcb, laddr, TP_LOCAL); ! 767: ! 768: /* stash the f suffix in the new tpcb */ ! 769: bcopy(fsufxloc, tpcb->tp_fsuffix, fsufxlen); ! 770: /* l suffix is already there, unless this is an intercept case */ ! 771: if (intercepted) ! 772: bcopy(lsufxloc, tpcb->tp_lsuffix, lsufxlen); ! 773: (tpcb->tp_nlproto->nlp_putsufx) ! 774: (so->so_pcb, fsufxloc, fsufxlen, TP_FOREIGN); ! 775: (tpcb->tp_nlproto->nlp_putsufx) ! 776: (so->so_pcb, lsufxloc, lsufxlen, TP_LOCAL); ! 777: #ifdef TP_PERF_MEAS ! 778: if( tpcb->tp_perf_on = perf_meas ) { /* assignment */ ! 779: /* ok, let's create an mbuf for stashing the ! 780: * statistics if one doesn't already exist ! 781: */ ! 782: (void) tp_setup_perf(tpcb); ! 783: } ! 784: #endif TP_PERF_MEAS ! 785: tpcb->tp_fref = sref; ! 786: ! 787: /* We've already checked for consistency with the options ! 788: * set in tpp, but we couldn't set them earlier because ! 789: * we didn't want to change options in the LISTENING tpcb. ! 790: * Now we set the options in the new socket's tpcb. ! 791: */ ! 792: (void) tp_consistency( tpcb, TP_FORCE, &tpp); ! 793: ! 794: if(!tpcb->tp_use_checksum) ! 795: IncStat(ts_csum_off); ! 796: if(tpcb->tp_xpd_service) ! 797: IncStat(ts_use_txpd); ! 798: if(tpcb->tp_xtd_format) ! 799: IncStat(ts_xtd_fmt); ! 800: ! 801: /* ! 802: * Get the maximum transmission unit from the lower layer(s) ! 803: * so we can negotiate a reasonable max TPDU size. ! 804: */ ! 805: (tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb, ! 806: &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0); ! 807: tpcb->tp_peer_acktime = acktime; ! 808: ! 809: /* ! 810: * The following kludge is used to test retransmissions and ! 811: * timeout during connection establishment. ! 812: */ ! 813: IFDEBUG(D_ZDREF) ! 814: IncStat(ts_zdebug); ! 815: /*tpcb->tp_fref = 0;*/ ! 816: ENDDEBUG ! 817: } ! 818: IncStat(ts_CR_rcvd); ! 819: if (!tpcb->tp_cebit_off) { ! 820: tpcb->tp_win_recv = tp_start_win << 8; ! 821: tpcb->tp_cong_sample.cs_size = 0; ! 822: LOCAL_CREDIT(tpcb); ! 823: CONG_INIT_SAMPLE(tpcb); ! 824: CONG_UPDATE_SAMPLE(tpcb, ce_bit); ! 825: } ! 826: tpcb->tp_ackrcvd = 0; ! 827: } else if ( dutype == ER_TPDU_type ) { ! 828: /* ! 829: * ER TPDUs have to be recognized separately ! 830: * because they don't necessarily have a tpcb ! 831: * with them and we don't want err out looking for such ! 832: * a beast. ! 833: * We could put a bunch of little kludges in the ! 834: * next section of code so it would avoid references to tpcb ! 835: * if dutype == ER_TPDU_type but we don't want code for ERs to ! 836: * mess up code for data transfer. ! 837: */ ! 838: IncStat(ts_ER_rcvd); ! 839: e.ev_number = ER_TPDU; ! 840: e.ATTR(ER_TPDU).e_reason = (u_char)hdr->tpdu_ERreason; ! 841: takes_data = 1; ! 842: } else { ! 843: /* tpdu type is CC, XPD, XAK, GR, AK, DR, DC, or DT */ ! 844: ! 845: /* In the next 4 checks, ! 846: * _tpduf is the fixed part; add 2 to get the dref bits of ! 847: * the fixed part (can't take the address of a bit field) ! 848: */ ! 849: if(cons_channel) { ! 850: #if NARGOXTWENTYFIVE > 0 ! 851: extern struct tp_pcb *cons_chan_to_tpcb(); ! 852: ! 853: tpcb = cons_chan_to_tpcb( cons_channel ); ! 854: /* Problem: We may have a legit ! 855: * error situation yet we may or may not have ! 856: * a correspondence between the tpcb and the vc, ! 857: * e.g., TP4cr--> <no dice, respond w/ DR on vc> ! 858: * <--- DR ! 859: * Now it's up to TP to look at the tpdu and do one of: ! 860: * confirm(dgm)(cr), confirm(circuit)(cr), reject(cr), or ! 861: * nothing, if the circuit is already open (any other tpdu). ! 862: * Sigh. ! 863: */ ! 864: ! 865: /* I don't know about this error value */ ! 866: CHECK( (tpcb == (struct tp_pcb *)0) , ! 867: E_TP_NO_CR_ON_NC, ts_inv_dref, respond, ! 868: (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) ! 869: #else ! 870: printf("tp_input(): X25 NOT CONFIGURED!!\n"); ! 871: #endif NARGOXTWENTYFIVE > 0 ! 872: ! 873: } else { ! 874: ! 875: CHECK( ((int)dref <= 0 || dref >= N_TPREF) , ! 876: E_TP_MISM_REFS,ts_inv_dref, nonx_dref, ! 877: (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) ! 878: CHECK( ((tpcb = tp_ref[dref].tpr_pcb ) == (struct tp_pcb *) 0 ), ! 879: E_TP_MISM_REFS,ts_inv_dref, nonx_dref, ! 880: (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) ! 881: CHECK( (tpcb->tp_refp->tpr_state == REF_FREE), ! 882: E_TP_MISM_REFS,ts_inv_dref, nonx_dref, ! 883: (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) ! 884: } ! 885: ! 886: IFDEBUG(D_TPINPUT) ! 887: printf("HAVE A TPCB 2: 0x%x\n", tpcb); ! 888: ENDDEBUG ! 889: ! 890: /* causes a DR to be sent for CC; ER for all else */ ! 891: CHECK( (tpcb->tp_refp->tpr_state == REF_FROZEN), ! 892: (dutype == CC_TPDU_type?E_TP_NO_SESSION:E_TP_MISM_REFS), ! 893: ts_inv_dref, respond, ! 894: (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) ! 895: ! 896: IFDEBUG(D_TPINPUT) ! 897: printf("state of dref %d ok, tpcb 0x%x\n", dref,tpcb); ! 898: ENDDEBUG ! 899: /* ! 900: * At this point the state of the dref could be ! 901: * FROZEN: tpr_pcb == NULL, has ( reference only) timers ! 902: * for example, DC may arrive after the close() has detached ! 903: * the tpcb (e.g., if user turned off SO_LISTEN option) ! 904: * OPENING : a tpcb exists but no timers yet ! 905: * OPEN : tpcb exists & timers are outstanding ! 906: */ ! 907: ! 908: if (!tpcb->tp_cebit_off) ! 909: CONG_UPDATE_SAMPLE(tpcb, ce_bit); ! 910: ! 911: dusize = tpcb->tp_tpdusize; ! 912: ! 913: dutype = hdr->tpdu_type << 8; /* for the switch below */ ! 914: ! 915: WHILE_OPTIONS(P, hdr, tpcb->tp_xtd_format) /* { */ ! 916: ! 917: #define caseof(x,y) case (((x)<<8)+(y)) ! 918: switch( dutype | vbptr(P)->tpv_code ) { ! 919: ! 920: caseof( CC_TPDU_type, TPP_addl_opt ): ! 921: /* not in class 0; 1 octet */ ! 922: vb_getval(P, u_char, addlopt); ! 923: break; ! 924: caseof( CC_TPDU_type, TPP_tpdu_size ): ! 925: { ! 926: u_char odusize = dusize; ! 927: vb_getval(P, u_char, dusize); ! 928: CHECK( (dusize < TP_MIN_TPDUSIZE || ! 929: dusize > TP_MAX_TPDUSIZE || dusize > odusize), ! 930: E_TP_INV_PVAL, ts_inv_pval, respond, ! 931: (1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) ) ! 932: IFDEBUG(D_TPINPUT) ! 933: printf("CC dusize 0x%x\n", dusize); ! 934: ENDDEBUG ! 935: } ! 936: break; ! 937: caseof( CC_TPDU_type, TPP_calling_sufx): ! 938: IFDEBUG(D_TPINPUT) ! 939: printf("CC calling (local) sufxlen 0x%x\n", lsufxlen); ! 940: ENDDEBUG ! 941: lsufxloc = (caddr_t) &vbptr(P)->tpv_val; ! 942: lsufxlen = vbptr(P)->tpv_len; ! 943: break; ! 944: caseof( CC_TPDU_type, TPP_acktime ): ! 945: /* class 4 only, 2 octets */ ! 946: vb_getval(P, u_short, acktime); ! 947: acktime = ntohs(acktime); ! 948: acktime = acktime/500; /* convert to slowtimo ticks */ ! 949: if( (short)acktime <=0 ) ! 950: acktime = 2; ! 951: break; ! 952: caseof( CC_TPDU_type, TPP_called_sufx): ! 953: fsufxloc = (caddr_t) &vbptr(P)->tpv_val; ! 954: fsufxlen = vbptr(P)->tpv_len; ! 955: IFDEBUG(D_TPINPUT) ! 956: printf("CC called (foreign) sufx len %d\n", fsufxlen); ! 957: ENDDEBUG ! 958: break; ! 959: ! 960: caseof( CC_TPDU_type, TPP_checksum): ! 961: caseof( DR_TPDU_type, TPP_checksum): ! 962: caseof( DT_TPDU_type, TPP_checksum): ! 963: caseof( XPD_TPDU_type, TPP_checksum): ! 964: if( tpcb->tp_use_checksum ) { ! 965: CHECK( iso_check_csum(m, tpdu_len), ! 966: E_TP_INV_PVAL, ts_bad_csum, discard, 0) ! 967: } ! 968: break; ! 969: ! 970: /* this is different from the above because in the context ! 971: * of concat/ sep tpdu_len might not be the same as hdr len ! 972: */ ! 973: caseof( AK_TPDU_type, TPP_checksum): ! 974: caseof( XAK_TPDU_type, TPP_checksum): ! 975: caseof( DC_TPDU_type, TPP_checksum): ! 976: if( tpcb->tp_use_checksum ) { ! 977: CHECK( iso_check_csum(m, (int)hdr->tpdu_li + 1), ! 978: E_TP_INV_PVAL, ts_bad_csum, discard, 0) ! 979: } ! 980: break; ! 981: #ifdef notdef ! 982: caseof( DR_TPDU_type, TPP_addl_info ): ! 983: /* ignore - its length and meaning are ! 984: * user defined and there's no way ! 985: * to pass this info to the user anyway ! 986: */ ! 987: break; ! 988: #endif notdef ! 989: ! 990: caseof( AK_TPDU_type, TPP_subseq ): ! 991: /* used after reduction of window */ ! 992: vb_getval(P, u_short, subseq); ! 993: subseq = ntohs(subseq); ! 994: IFDEBUG(D_ACKRECV) ! 995: printf("AK Subsequence # 0x%x\n", subseq); ! 996: ENDDEBUG ! 997: break; ! 998: ! 999: caseof( AK_TPDU_type, TPP_flow_cntl_conf ): ! 1000: { ! 1001: u_int ylwe; ! 1002: u_short ysubseq, ycredit; ! 1003: ! 1004: fcc_present = TRUE; ! 1005: vb_getval(P, u_int, ylwe); ! 1006: vb_getval(P, u_short, ysubseq); ! 1007: vb_getval(P, u_short, ycredit); ! 1008: ylwe = ntohl(ylwe); ! 1009: ysubseq = ntohs(ysubseq); ! 1010: ycredit = ntohs(ycredit); ! 1011: IFDEBUG(D_ACKRECV) ! 1012: printf("AK FCC lwe 0x%x, subseq 0x%x, cdt 0x%x\n", ! 1013: ylwe, ysubseq, ycredit); ! 1014: ENDDEBUG ! 1015: } ! 1016: break; ! 1017: ! 1018: default: ! 1019: IFDEBUG(D_TPINPUT) ! 1020: printf("param ignored dutype 0x%x, code 0x%x\n", ! 1021: dutype, vbptr(P)->tpv_code); ! 1022: ENDDEBUG ! 1023: IFTRACE(D_TPINPUT) ! 1024: tptrace(TPPTmisc, "param ignored dutype code ", ! 1025: dutype, vbptr(P)->tpv_code ,0,0); ! 1026: ENDTRACE ! 1027: IncStat(ts_param_ignored); ! 1028: break; ! 1029: #undef caseof ! 1030: } ! 1031: /* } */ END_WHILE_OPTIONS(P) ! 1032: ! 1033: /* NOTE: the variable dutype has been shifted left! */ ! 1034: ! 1035: switch( hdr->tpdu_type ) { ! 1036: case CC_TPDU_type: ! 1037: /* If CC comes back with an unacceptable class ! 1038: * respond with a DR or ER ! 1039: */ ! 1040: ! 1041: opt = hdr->tpdu_CCoptions; /* 1 byte */ ! 1042: ! 1043: { ! 1044: tpp = tpcb->_tp_param; ! 1045: tpp.p_class = (1<<hdr->tpdu_CCclass); ! 1046: tpp.p_tpdusize = dusize; ! 1047: tpp.p_dont_change_params = 0; ! 1048: tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT; ! 1049: tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD; ! 1050: tpp.p_use_checksum = (addlopt & TPAO_NO_CSUM) == 0; ! 1051: #ifdef notdef ! 1052: tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC; ! 1053: tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD; ! 1054: tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC; ! 1055: #endif notdef ! 1056: ! 1057: CHECK( ! 1058: tp_consistency(tpcb, TP_FORCE, &tpp) != 0, ! 1059: E_TP_NEGOT_FAILED, ts_negotfailed, respond, ! 1060: (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) ! 1061: /* ^ more or less the location of class */ ! 1062: ) ! 1063: IFTRACE(D_CONN) ! 1064: tptrace(TPPTmisc, ! 1065: "after 1 consist class, out, tpconsout", ! 1066: tpcb->tp_class, dgout_routine, tpcons_output, 0 ! 1067: ); ! 1068: ENDTRACE ! 1069: CHECK( ! 1070: ((class_to_use == TP_CLASS_0)&& ! 1071: (dgout_routine != tpcons_output)), ! 1072: E_TP_NEGOT_FAILED, ts_negotfailed, respond, ! 1073: (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) ! 1074: /* ^ more or less the location of class */ ! 1075: ) ! 1076: } ! 1077: if( ! tpcb->tp_use_checksum) ! 1078: IncStat(ts_csum_off); ! 1079: if(tpcb->tp_xpd_service) ! 1080: IncStat(ts_use_txpd); ! 1081: if(tpcb->tp_xtd_format) ! 1082: IncStat(ts_xtd_fmt); ! 1083: ! 1084: IFTRACE(D_CONN) ! 1085: tptrace(TPPTmisc, "after CC class flags dusize CCclass", ! 1086: tpcb->tp_class, tpcb->tp_flags, tpcb->tp_tpdusize, ! 1087: hdr->tpdu_CCclass); ! 1088: ENDTRACE ! 1089: ! 1090: /* ! 1091: * Get the maximum transmission unit from the lower layer(s) ! 1092: * so we can decide how large a TPDU size to negotiate. ! 1093: * It would be nice if the arguments to this ! 1094: * were more reasonable. ! 1095: */ ! 1096: (tpcb->tp_nlproto->nlp_mtu)(tpcb->tp_sock, tpcb->tp_sock->so_pcb, ! 1097: &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0); ! 1098: ! 1099: #ifdef CONS ! 1100: /* Could be that this CC came in on a NEW vc, in which case ! 1101: * we have to confirm it. ! 1102: */ ! 1103: if( cons_channel ) ! 1104: cons_netcmd( CONN_CONFIRM, tpcb->tp_npcb, cons_channel, ! 1105: tpcb->tp_class == TP_CLASS_4); ! 1106: #endif CONS ! 1107: ! 1108: tpcb->tp_peer_acktime = acktime; ! 1109: ! 1110: /* if called or calling suffices appeared on the CC, ! 1111: * they'd better jive with what's in the pcb ! 1112: */ ! 1113: if( fsufxlen ) { ! 1114: CHECK( ((tpcb->tp_fsuffixlen != fsufxlen) || ! 1115: bcmp(fsufxloc, tpcb->tp_fsuffix, fsufxlen)), ! 1116: E_TP_INV_PVAL,ts_inv_sufx, respond, ! 1117: (1+fsufxloc - (caddr_t)hdr)) ! 1118: } ! 1119: if( lsufxlen ) { ! 1120: CHECK( ((tpcb->tp_lsuffixlen != lsufxlen) || ! 1121: bcmp(lsufxloc, tpcb->tp_lsuffix, lsufxlen)), ! 1122: E_TP_INV_PVAL,ts_inv_sufx, respond, ! 1123: (1+lsufxloc - (caddr_t)hdr)) ! 1124: } ! 1125: ! 1126: e.ATTR(CC_TPDU).e_sref = sref; ! 1127: e.ATTR(CC_TPDU).e_cdt = hdr->tpdu_CCcdt; ! 1128: takes_data = TRUE; ! 1129: e.ev_number = CC_TPDU; ! 1130: IncStat(ts_CC_rcvd); ! 1131: break; ! 1132: ! 1133: case DC_TPDU_type: ! 1134: if (sref != tpcb->tp_fref) ! 1135: printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n", ! 1136: sref, tpcb->tp_fref); ! 1137: ! 1138: CHECK( (sref != tpcb->tp_fref), ! 1139: E_TP_MISM_REFS, ts_inv_sufx, discard, ! 1140: (1 + (caddr_t)&hdr->tpdu_DCsref - (caddr_t)hdr)) ! 1141: ! 1142: e.ev_number = DC_TPDU; ! 1143: IncStat(ts_DC_rcvd); ! 1144: break; ! 1145: ! 1146: case DR_TPDU_type: ! 1147: IFTRACE(D_TPINPUT) ! 1148: tptrace(TPPTmisc, "DR recvd", hdr->tpdu_DRreason, 0, 0, 0); ! 1149: ENDTRACE ! 1150: if (sref != tpcb->tp_fref) { ! 1151: printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n", ! 1152: sref, tpcb->tp_fref); ! 1153: } ! 1154: ! 1155: CHECK( (sref != 0 && sref != tpcb->tp_fref && ! 1156: tpcb->tp_state != TP_CRSENT), ! 1157: (TP_ERROR_SNDC | E_TP_MISM_REFS),ts_inv_sufx, respond, ! 1158: (1 + (caddr_t)&hdr->tpdu_DRsref - (caddr_t)hdr)) ! 1159: ! 1160: e.ATTR(DR_TPDU).e_reason = hdr->tpdu_DRreason; ! 1161: e.ATTR(DR_TPDU).e_sref = (u_short)sref; ! 1162: takes_data = TRUE; ! 1163: e.ev_number = DR_TPDU; ! 1164: IncStat(ts_DR_rcvd); ! 1165: break; ! 1166: ! 1167: case ER_TPDU_type: ! 1168: IFTRACE(D_TPINPUT) ! 1169: tptrace(TPPTmisc, "ER recvd", hdr->tpdu_ERreason,0,0,0); ! 1170: ENDTRACE ! 1171: e.ev_number = ER_TPDU; ! 1172: e.ATTR(ER_TPDU).e_reason = hdr->tpdu_ERreason; ! 1173: IncStat(ts_ER_rcvd); ! 1174: break; ! 1175: ! 1176: case AK_TPDU_type: ! 1177: ! 1178: e.ATTR(AK_TPDU).e_subseq = subseq; ! 1179: e.ATTR(AK_TPDU).e_fcc_present = fcc_present; ! 1180: ! 1181: if (tpcb->tp_xtd_format) { ! 1182: #ifdef BYTE_ORDER ! 1183: union seq_type seqeotX; ! 1184: ! 1185: seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); ! 1186: e.ATTR(AK_TPDU).e_seq = seqeotX.s_seq; ! 1187: e.ATTR(AK_TPDU).e_cdt = ntohs(hdr->tpdu_AKcdtX); ! 1188: #else ! 1189: e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdtX; ! 1190: e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseqX; ! 1191: #endif BYTE_ORDER ! 1192: } else { ! 1193: e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdt; ! 1194: e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseq; ! 1195: } ! 1196: IFTRACE(D_TPINPUT) ! 1197: tptrace(TPPTmisc, "AK recvd seq cdt subseq fcc_pres", ! 1198: e.ATTR(AK_TPDU).e_seq, e.ATTR(AK_TPDU).e_cdt, ! 1199: subseq, fcc_present); ! 1200: ENDTRACE ! 1201: ! 1202: e.ev_number = AK_TPDU; ! 1203: IncStat(ts_AK_rcvd); ! 1204: IncPStat(tpcb, tps_AK_rcvd); ! 1205: break; ! 1206: ! 1207: case XAK_TPDU_type: ! 1208: if (tpcb->tp_xtd_format) { ! 1209: #ifdef BYTE_ORDER ! 1210: union seq_type seqeotX; ! 1211: ! 1212: seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); ! 1213: e.ATTR(XAK_TPDU).e_seq = seqeotX.s_seq; ! 1214: #else ! 1215: e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseqX; ! 1216: #endif BYTE_ORDER ! 1217: } else { ! 1218: e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseq; ! 1219: } ! 1220: e.ev_number = XAK_TPDU; ! 1221: IncStat(ts_XAK_rcvd); ! 1222: IncPStat(tpcb, tps_XAK_rcvd); ! 1223: break; ! 1224: ! 1225: case XPD_TPDU_type: ! 1226: if (tpcb->tp_xtd_format) { ! 1227: #ifdef BYTE_ORDER ! 1228: union seq_type seqeotX; ! 1229: ! 1230: seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); ! 1231: e.ATTR(XPD_TPDU).e_seq = seqeotX.s_seq; ! 1232: #else ! 1233: e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseqX; ! 1234: #endif BYTE_ORDER ! 1235: } else { ! 1236: e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseq; ! 1237: } ! 1238: takes_data = TRUE; ! 1239: e.ev_number = XPD_TPDU; ! 1240: IncStat(ts_XPD_rcvd); ! 1241: IncPStat(tpcb, tps_XPD_rcvd); ! 1242: break; ! 1243: ! 1244: case DT_TPDU_type: ! 1245: { /* the y option will cause occasional packets to be dropped. ! 1246: * A little crude but it works. ! 1247: */ ! 1248: ! 1249: IFDEBUG(D_DROP) ! 1250: if(time.tv_usec & 0x4 && hdr->tpdu_DTseq & 0x1) { ! 1251: IncStat(ts_ydebug); ! 1252: goto discard; ! 1253: } ! 1254: ENDDEBUG ! 1255: } ! 1256: if (tpcb->tp_class == TP_CLASS_0) { ! 1257: e.ATTR(DT_TPDU).e_seq = 0; /* actually don't care */ ! 1258: e.ATTR(DT_TPDU).e_eot = (((struct tp0du *)hdr)->tp0du_eot); ! 1259: } else if (tpcb->tp_xtd_format) { ! 1260: #ifdef BYTE_ORDER ! 1261: union seq_type seqeotX; ! 1262: ! 1263: seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); ! 1264: e.ATTR(DT_TPDU).e_seq = seqeotX.s_seq; ! 1265: e.ATTR(DT_TPDU).e_eot = seqeotX.s_eot; ! 1266: #else ! 1267: e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseqX; ! 1268: e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeotX; ! 1269: #endif BYTE_ORDER ! 1270: } else { ! 1271: e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseq; ! 1272: e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeot; ! 1273: } ! 1274: if(e.ATTR(DT_TPDU).e_eot) ! 1275: IncStat(ts_eot_input); ! 1276: takes_data = TRUE; ! 1277: e.ev_number = DT_TPDU; ! 1278: IncStat(ts_DT_rcvd); ! 1279: IncPStat(tpcb, tps_DT_rcvd); ! 1280: break; ! 1281: ! 1282: case GR_TPDU_type: ! 1283: tp_indicate(T_DISCONNECT, tpcb, ECONNABORTED); ! 1284: /* drop through */ ! 1285: default: ! 1286: /* this should NEVER happen because there is a ! 1287: * check for dutype well above here ! 1288: */ ! 1289: error = E_TP_INV_TPDU; /* causes an ER */ ! 1290: IFDEBUG(D_TPINPUT) ! 1291: printf("INVALID dutype 0x%x\n", hdr->tpdu_type); ! 1292: ENDDEBUG ! 1293: IncStat(ts_inv_dutype); ! 1294: goto respond; ! 1295: } ! 1296: } ! 1297: /* peel off the tp header; ! 1298: * remember that the du_li doesn't count itself. ! 1299: * This may leave us w/ an empty mbuf at the front of a chain. ! 1300: * We can't just throw away the empty mbuf because hdr still points ! 1301: * into the mbuf's data area and we're still using hdr (the tpdu header) ! 1302: */ ! 1303: m->m_len -= ((int)hdr->tpdu_li + 1); ! 1304: m->m_data += ((int)hdr->tpdu_li + 1); ! 1305: ! 1306: if (takes_data) { ! 1307: int max = tpdu_info[ hdr->tpdu_type ] [TP_MAX_DATA_INDEX]; ! 1308: int datalen = tpdu_len - hdr->tpdu_li - 1, mbtype = MT_DATA; ! 1309: struct cmsghdr c_hdr; ! 1310: struct mbuf *n; ! 1311: ! 1312: CHECK( (max && datalen > max), E_TP_LENGTH_INVAL, ! 1313: ts_inv_length, respond, (max + hdr->tpdu_li + 1) ); ! 1314: switch( hdr->tpdu_type ) { ! 1315: ! 1316: case CR_TPDU_type: ! 1317: c_hdr.cmsg_type = TPOPT_CONN_DATA; ! 1318: goto make_control_msg; ! 1319: ! 1320: case CC_TPDU_type: ! 1321: c_hdr.cmsg_type = TPOPT_CFRM_DATA; ! 1322: goto make_control_msg; ! 1323: ! 1324: case DR_TPDU_type: ! 1325: c_hdr.cmsg_type = TPOPT_DISC_DATA; ! 1326: make_control_msg: ! 1327: c_hdr.cmsg_level = SOL_TRANSPORT; ! 1328: mbtype = MT_CONTROL; ! 1329: MGET(n, M_DONTWAIT, MT_DATA); ! 1330: if (n) { ! 1331: datalen += sizeof(c_hdr); ! 1332: n->m_len = sizeof(c_hdr); ! 1333: c_hdr.cmsg_len = datalen; ! 1334: *mtod(n, struct cmsghdr *) = c_hdr; ! 1335: n->m_next = m; ! 1336: m = n; ! 1337: } else {m_freem(m); m = 0; goto invoke;} ! 1338: /* FALLTHROUGH */ ! 1339: ! 1340: case XPD_TPDU_type: ! 1341: if (mbtype != MT_CONTROL) ! 1342: mbtype = MT_OOBDATA; ! 1343: m->m_flags |= M_EOR; ! 1344: /* FALLTHROUGH */ ! 1345: ! 1346: case DT_TPDU_type: ! 1347: for (n = m; n; n = n->m_next) { ! 1348: MCHTYPE(n, mbtype); ! 1349: } ! 1350: invoke: ! 1351: e.ATTR(DT_TPDU).e_datalen = datalen; ! 1352: e.ATTR(DT_TPDU).e_data = m; ! 1353: break; ! 1354: ! 1355: default: ! 1356: printf( ! 1357: "ERROR in tp_input! hdr->tpdu_type 0x%x takes_data 0x%x m 0x%x\n", ! 1358: hdr->tpdu_type, takes_data, m); ! 1359: break; ! 1360: } ! 1361: /* prevent m_freem() after tp_driver() from throwing it all away */ ! 1362: m = MNULL; ! 1363: } ! 1364: ! 1365: IncStat(ts_tpdu_rcvd); ! 1366: ! 1367: IFDEBUG(D_TPINPUT) ! 1368: printf( "tp_input: before driver, state 0x%x event 0x%x m 0x%x", ! 1369: tpcb->tp_state, e.ev_number, m ); ! 1370: printf(" e.e_data 0x%x\n", e.ATTR(DT_TPDU).e_data); ! 1371: printf("takes_data 0x%x m_len 0x%x, tpdu_len 0x%x\n", ! 1372: takes_data, (m==MNULL)?0:m->m_len, tpdu_len); ! 1373: ENDDEBUG ! 1374: ! 1375: error = tp_driver(tpcb, &e); ! 1376: ! 1377: ASSERT(tpcb != (struct tp_pcb *)0); ! 1378: ASSERT(tpcb->tp_sock != (struct socket *)0); ! 1379: if( tpcb->tp_sock->so_error == 0 ) ! 1380: tpcb->tp_sock->so_error = error; ! 1381: ! 1382: /* Kludge to keep the state tables under control (adding ! 1383: * data on connect & disconnect & freeing the mbuf containing ! 1384: * the data would have exploded the tables and made a big mess ). ! 1385: */ ! 1386: switch(e.ev_number) { ! 1387: case CC_TPDU: ! 1388: case DR_TPDU: ! 1389: case CR_TPDU: ! 1390: m = e.ATTR(CC_TPDU).e_data; /* same field for all three dutypes */ ! 1391: IFDEBUG(D_TPINPUT) ! 1392: printf("after driver, restoring m to 0x%x, takes_data 0x%x\n", ! 1393: m, takes_data); ! 1394: ENDDEBUG ! 1395: break; ! 1396: default: ! 1397: break; ! 1398: } ! 1399: /* Concatenated sequences are terminated by any tpdu that ! 1400: * carries data: CR, CC, DT, XPD, DR. ! 1401: * All other tpdu types may be concatenated: AK, XAK, DC, ER. ! 1402: */ ! 1403: ! 1404: separate: ! 1405: if ( takes_data == 0 ) { ! 1406: ASSERT( m != MNULL ); ! 1407: /* ! 1408: * we already peeled off the prev. tp header so ! 1409: * we can just pull up some more and repeat ! 1410: */ ! 1411: ! 1412: if( m = tp_inputprep(m) ) { ! 1413: IFDEBUG(D_TPINPUT) ! 1414: hdr = mtod(m, struct tpdu *); ! 1415: printf("tp_input @ separate: hdr 0x%x size %d m 0x%x\n", ! 1416: hdr, (int) hdr->tpdu_li + 1, m); ! 1417: dump_mbuf(m, "tp_input after driver, at separate"); ! 1418: ENDDEBUG ! 1419: ! 1420: IncStat(ts_concat_rcvd); ! 1421: goto again; ! 1422: } ! 1423: } ! 1424: if ( m != MNULL ) { ! 1425: IFDEBUG(D_TPINPUT) ! 1426: printf("tp_input : m_freem(0x%x)\n", m); ! 1427: ENDDEBUG ! 1428: m_freem(m); ! 1429: IFDEBUG(D_TPINPUT) ! 1430: printf("tp_input : after m_freem 0x%x\n", m); ! 1431: ENDDEBUG ! 1432: } ! 1433: return (ProtoHook) tpcb; ! 1434: ! 1435: discard: ! 1436: /* class 4: drop the tpdu */ ! 1437: /* class 2,0: Should drop the net connection, if you can figure out ! 1438: * to which connection it applies ! 1439: */ ! 1440: IFDEBUG(D_TPINPUT) ! 1441: printf("tp_input DISCARD\n"); ! 1442: ENDDEBUG ! 1443: IFTRACE(D_TPINPUT) ! 1444: tptrace(TPPTmisc, "tp_input DISCARD m", m,0,0,0); ! 1445: ENDTRACE ! 1446: m_freem(m); ! 1447: IncStat(ts_recv_drop); ! 1448: return (ProtoHook)0; ! 1449: ! 1450: nonx_dref: ! 1451: switch (dutype) { ! 1452: default: ! 1453: goto discard; ! 1454: case CC_TPDU_type: ! 1455: /* error = E_TP_MISM_REFS; */ ! 1456: break; ! 1457: case DR_TPDU_type: ! 1458: error |= TP_ERROR_SNDC; ! 1459: } ! 1460: respond: ! 1461: IFDEBUG(D_TPINPUT) ! 1462: printf("RESPOND: error 0x%x, errlen 0x%x\n", error, errlen); ! 1463: ENDDEBUG ! 1464: IFTRACE(D_TPINPUT) ! 1465: tptrace(TPPTmisc, "tp_input RESPOND m error sref", m, error, sref, 0); ! 1466: ENDTRACE ! 1467: if (sref == 0) ! 1468: goto discard; ! 1469: (void) tp_error_emit(error, (u_long)sref, (struct sockaddr_iso *)faddr, ! 1470: (struct sockaddr_iso *)laddr, m, errlen, tpcb, ! 1471: (int)cons_channel, dgout_routine); ! 1472: IFDEBUG(D_ERROR_EMIT) ! 1473: printf("tp_input after error_emit\n"); ! 1474: ENDDEBUG ! 1475: ! 1476: #ifdef lint ! 1477: printf("",sref,opt); ! 1478: #endif lint ! 1479: IncStat(ts_recv_drop); ! 1480: return (ProtoHook)0; ! 1481: } ! 1482: ! 1483: ! 1484: /* ! 1485: * NAME: tp_headersize() ! 1486: * ! 1487: * CALLED FROM: ! 1488: * tp_emit() and tp_sbsend() ! 1489: * TP needs to know the header size so it can figure out how ! 1490: * much data to put in each tpdu. ! 1491: * ! 1492: * FUNCTION, ARGUMENTS, and RETURN VALUE: ! 1493: * For a given connection, represented by (tpcb), and ! 1494: * tpdu type (dutype), return the size of a tp header. ! 1495: * ! 1496: * RETURNS: the expected size of the heade in bytesr ! 1497: * ! 1498: * SIDE EFFECTS: ! 1499: * ! 1500: * NOTES: It would be nice if it got the network header size as well. ! 1501: */ ! 1502: int ! 1503: tp_headersize(dutype, tpcb) ! 1504: int dutype; ! 1505: struct tp_pcb *tpcb; ! 1506: { ! 1507: register int size = 0; ! 1508: ! 1509: IFTRACE(D_CONN) ! 1510: tptrace(TPPTmisc, "tp_headersize dutype class xtd_format", ! 1511: dutype, tpcb->tp_class, tpcb->tp_xtd_format, 0); ! 1512: ENDTRACE ! 1513: if( !( (tpcb->tp_class == TP_CLASS_0) || ! 1514: (tpcb->tp_class == TP_CLASS_4) || ! 1515: (dutype == DR_TPDU_type) || ! 1516: (dutype == CR_TPDU_type) )) { ! 1517: printf("tp_headersize:dutype 0x%x, class 0x%x", ! 1518: dutype, tpcb->tp_class); ! 1519: /* TODO: identify this and GET RID OF IT */ ! 1520: } ! 1521: ASSERT( (tpcb->tp_class == TP_CLASS_0) || ! 1522: (tpcb->tp_class == TP_CLASS_4) || ! 1523: (dutype == DR_TPDU_type) || ! 1524: (dutype == CR_TPDU_type) ); ! 1525: ! 1526: if( tpcb->tp_class == TP_CLASS_0 ) { ! 1527: size = tpdu_info[ dutype ] [TP_LEN_CLASS_0_INDEX]; ! 1528: } else { ! 1529: size = tpdu_info[ dutype ] [tpcb->tp_xtd_format]; ! 1530: } ! 1531: return size; ! 1532: /* caller must get network level header size separately */ ! 1533: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.