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.12 (Berkeley) 06/28/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 = mtod(m, struct tpdu *); 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 #ifdef TP_PERF_MEAS 401 GET_CUR_TIME( &e.e_time ); perf_meas = 0; 402 #endif TP_PERF_MEAS 403 404 IFDEBUG(D_TPINPUT) 405 printf("tp_input(0x%x, ... 0x%x)\n", m, cons_channel); 406 ENDDEBUG 407 408 409 /* 410 * get the actual tpdu length - necessary for monitoring 411 * and for checksumming 412 * 413 * Also, maybe measure the mbuf chain lengths and sizes. 414 */ 415 416 { register struct mbuf *n=m; 417 # ifdef ARGO_DEBUG 418 int chain_length = 0; 419 # endif ARGO_DEBUG 420 421 for(;;) { 422 tpdu_len += n->m_len; 423 IFDEBUG(D_MBUF_MEAS) 424 if( n->m_flags & M_EXT) { 425 IncStat(ts_mb_cluster); 426 } else { 427 IncStat(ts_mb_small); 428 } 429 chain_length ++; 430 ENDDEBUG 431 if (n->m_next == MNULL ) { 432 break; 433 } 434 n = n->m_next; 435 } 436 IFDEBUG(D_MBUF_MEAS) 437 if(chain_length > 16) 438 chain_length = 0; /* zero used for anything > 16 */ 439 tp_stat.ts_mb_len_distr[chain_length] ++; 440 ENDDEBUG 441 } 442 IFTRACE(D_TPINPUT) 443 tptraceTPCB(TPPTtpduin, hdr->tpdu_type, hdr, hdr->tpdu_li+1, tpdu_len, 444 0); 445 ENDTRACE 446 447 dref = ntohs((short)hdr->tpdu_dref); 448 sref = ntohs((short)hdr->tpdu_sref); 449 dutype = (int)hdr->tpdu_type; 450 451 IFDEBUG(D_TPINPUT) 452 printf("input: dutype 0x%x cons_channel 0x%x dref 0x%x\n", dutype, 453 cons_channel, dref); 454 printf("input: dref 0x%x sref 0x%x\n", dref, sref); 455 ENDDEBUG 456 IFTRACE(D_TPINPUT) 457 tptrace(TPPTmisc, "channel dutype dref ", 458 cons_channel, dutype, dref, 0); 459 ENDTRACE 460 461 462 #ifdef ARGO_DEBUG 463 if( (dutype < TP_MIN_TPDUTYPE) || (dutype > TP_MAX_TPDUTYPE)) { 464 printf("BAD dutype! 0x%x, channel 0x%x dref 0x%x\n", 465 dutype, cons_channel, dref); 466 dump_buf (m, sizeof( struct mbuf )); 467 468 IncStat(ts_inv_dutype); 469 goto discard; 470 } 471 #endif ARGO_DEBUG 472 473 CHECK( (dutype < TP_MIN_TPDUTYPE || dutype > TP_MAX_TPDUTYPE), 474 E_TP_INV_TPDU, ts_inv_dutype, respond, 475 2 ); 476 /* unfortunately we can't take the address of the tpdu_type field, 477 * since it's a bit field - so we just use the constant offset 2 478 */ 479 480 /* Now this isn't very neat but since you locate a pcb one way 481 * at the beginning of connection establishment, and by 482 * the dref for each tpdu after that, we have to treat CRs differently 483 */ 484 if ( dutype == CR_TPDU_type ) { 485 u_char alt_classes = 0; 486 487 preferred_class = 1 << hdr->tpdu_CRclass; 488 opt = hdr->tpdu_CRoptions; 489 490 WHILE_OPTIONS(P, hdr, 1 ) /* { */ 491 492 switch( vbptr(P)->tpv_code ) { 493 494 case TPP_tpdu_size: 495 vb_getval(P, u_char, dusize); 496 IFDEBUG(D_TPINPUT) 497 printf("CR dusize 0x%x\n", dusize); 498 ENDDEBUG 499 /* COS tests: NBS IA (Dec. 1987) Sec. 4.5.2.1 */ 500 if (dusize < TP_MIN_TPDUSIZE || dusize > TP_MAX_TPDUSIZE) 501 dusize = TP_DFL_TPDUSIZE; 502 break; 503 case TPP_addl_opt: 504 vb_getval(P, u_char, addlopt); 505 break; 506 case TPP_calling_sufx: 507 /* could use vb_getval, but we want to save the loc & len 508 * for later use 509 */ 510 fsufxloc = (caddr_t) &vbptr(P)->tpv_val; 511 fsufxlen = vbptr(P)->tpv_len; 512 IFDEBUG(D_TPINPUT) 513 printf("CR fsufx:"); 514 { register int j; 515 for(j=0; j<fsufxlen; j++ ) { 516 printf(" 0x%x. ", *((caddr_t)(fsufxloc+j)) ); 517 } 518 printf("\n"); 519 } 520 ENDDEBUG 521 break; 522 case TPP_called_sufx: 523 /* could use vb_getval, but we want to save the loc & len 524 * for later use 525 */ 526 lsufxloc = (caddr_t) &vbptr(P)->tpv_val; 527 lsufxlen = vbptr(P)->tpv_len; 528 IFDEBUG(D_TPINPUT) 529 printf("CR lsufx:"); 530 { register int j; 531 for(j=0; j<lsufxlen; j++ ) { 532 printf(" 0x%x. ", *((u_char *)(lsufxloc+j)) ); 533 } 534 printf("\n"); 535 } 536 ENDDEBUG 537 break; 538 539 #ifdef TP_PERF_MEAS 540 case TPP_perf_meas: 541 vb_getval(P, u_char, perf_meas); 542 break; 543 #endif TP_PERF_MEAS 544 545 case TPP_vers: 546 /* not in class 0; 1 octet; in CR_TPDU only */ 547 /* COS tests says if version wrong, use default version!?XXX */ 548 CHECK( (vbval(P, u_char) != TP_VERSION ), 549 E_TP_INV_PVAL, ts_inv_pval, setversion, 550 (1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) ); 551 setversion: 552 version = vbval(P, u_char); 553 break; 554 case TPP_acktime: 555 vb_getval(P, u_short, acktime); 556 acktime = ntohs(acktime); 557 acktime = acktime/500; /* convert to slowtimo ticks */ 558 if((short)acktime <=0 ) 559 acktime = 2; /* don't allow a bad peer to screw us up */ 560 IFDEBUG(D_TPINPUT) 561 printf("CR acktime 0x%x\n", acktime); 562 ENDDEBUG 563 break; 564 565 case TPP_alt_class: 566 { 567 u_char *aclass = 0; 568 register int i; 569 static u_char bad_alt_classes[5] = 570 { ~0, ~3, ~5, ~0xf, ~0x1f}; 571 572 aclass = 573 (u_char *) &(((struct tp_vbp *)P)->tpv_val); 574 for (i = ((struct tp_vbp *)P)->tpv_len; i>0; i--) { 575 alt_classes |= (1<<((*aclass++)>>4)); 576 } 577 CHECK( (bad_alt_classes[hdr->tpdu_CRclass] & alt_classes), 578 E_TP_INV_PVAL, ts_inv_aclass, respond, 579 ((caddr_t)aclass) - (caddr_t)hdr); 580 IFDEBUG(D_TPINPUT) 581 printf("alt_classes 0x%x\n", alt_classes); 582 ENDDEBUG 583 } 584 break; 585 586 case TPP_security: 587 case TPP_residER: 588 case TPP_priority: 589 case TPP_transdelay: 590 case TPP_throughput: 591 case TPP_addl_info: 592 case TPP_subseq: 593 IFDEBUG(D_TPINPUT) 594 printf("param ignored CR_TPDU code= 0x%x\n", 595 vbptr(P)->tpv_code); 596 ENDDEBUG 597 IncStat(ts_param_ignored); 598 break; 599 600 case TPP_checksum: 601 IFDEBUG(D_TPINPUT) 602 printf("CR before cksum\n"); 603 ENDDEBUG 604 605 CHECK( iso_check_csum(m, tpdu_len), 606 E_TP_INV_PVAL, ts_bad_csum, discard, 0) 607 608 IFDEBUG(D_TPINPUT) 609 printf("CR before cksum\n"); 610 ENDDEBUG 611 break; 612 613 default: 614 IncStat(ts_inv_pcode); 615 error = E_TP_INV_PCODE; 616 goto discard; 617 618 } 619 620 /* } */ END_WHILE_OPTIONS(P) 621 622 if (lsufxlen == 0) { 623 /* can't look for a tpcb w/o any called sufx */ 624 error = E_TP_LENGTH_INVAL; 625 IncStat(ts_inv_sufx); 626 goto respond; 627 } else { 628 register struct tp_pcb *t; 629 630 for (t = tp_intercepts; t ; t->tp_nextlisten) { 631 if (laddr->sa_family != t->tp_nlproto->nlp_afamily) 632 continue; 633 if ((*tpcb->tp_nlproto->nlp_cmpnetaddr)( 634 t->tp_npcb, laddr, TP_LOCAL)) { 635 intercepted = 1; 636 goto check_duplicate_cr; 637 } 638 } 639 for (t = tp_listeners; t ; t->tp_nextlisten) { 640 if (bcmp(lsufxloc, t->tp_lsuffix, lsufxlen) != 0) 641 continue; 642 if (laddr->sa_family != t->tp_nlproto->nlp_afamily) 643 continue; 644 } 645 CHECK(t == 0, E_TP_NO_SESSION, ts_inv_sufx, respond, 646 (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 647 /* _tpduf is the fixed part; add 2 to get the dref bits of 648 * the fixed part (can't take the address of a bit field) 649 */ 650 check_duplicate_cr: 651 tpcb = t; 652 for (t = tpcb->tp_next; t != tpcb; t = t->tp_next) { 653 if (sref != t->tp_fref) 654 continue; 655 if ((*tpcb->tp_nlproto->nlp_cmpnetaddr)( 656 t->tp_npcb, faddr, TP_FOREIGN)) { 657 IFDEBUG(D_TPINPUT) 658 printf("duplicate CR discarded\n"); 659 ENDDEBUG 660 goto discard; 661 } 662 } 663 IFTRACE(D_TPINPUT) 664 tptrace(TPPTmisc, "tp_input: tpcb *lsufxloc tpstate", 665 tpcb, *lsufxloc, tpcb->tp_state, 0); 666 ENDTRACE 667 } 668 669 /* 670 * WE HAVE A TPCB 671 * already know that the classes in the CR match at least 672 * one class implemented, but we don't know yet if they 673 * include any classes permitted by this server. 674 */ 675 676 IFDEBUG(D_TPINPUT) 677 printf("HAVE A TPCB 1: 0x%x\n", tpcb); 678 ENDDEBUG 679 IFDEBUG(D_CONN) 680 printf( 681 "CR: bef CHKS: flags 0x%x class_to_use 0x%x alt 0x%x opt 0x%x tp_class 0x%x\n", 682 tpcb->tp_flags, class_to_use, alt_classes, opt, tpcb->tp_class); 683 ENDDEBUG 684 /* tpcb->tp_class doesn't include any classes not implemented */ 685 class_to_use = (preferred_class & tpcb->tp_class); 686 if( (class_to_use = preferred_class & tpcb->tp_class) == 0 ) 687 class_to_use = alt_classes & tpcb->tp_class; 688 689 class_to_use = 1 << tp_mask_to_num(class_to_use); 690 691 { 692 tpp = tpcb->_tp_param; 693 tpp.p_class = class_to_use; 694 tpp.p_tpdusize = dusize; 695 tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT; 696 tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD; 697 tpp.p_use_checksum = (tpp.p_class == TP_CLASS_0)?0: 698 (addlopt & TPAO_NO_CSUM) == 0; 699 tpp.p_version = version; 700 #ifdef notdef 701 tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC; 702 tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD; 703 tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC; 704 #endif notdef 705 706 CHECK( 707 tp_consistency(tpcb, 0 /* not force or strict */, &tpp) != 0, 708 E_TP_NEGOT_FAILED, ts_negotfailed, respond, 709 (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 710 /* ^ more or less the location of class */ 711 ) 712 } 713 IFTRACE(D_CONN) 714 tptrace(TPPTmisc, 715 "after 1 consist class_to_use class, out, tpconsout", 716 class_to_use, 717 tpcb->tp_class, dgout_routine, tpcons_output 718 ); 719 ENDTRACE 720 CHECK( 721 ((class_to_use == TP_CLASS_0)&&(dgout_routine != tpcons_output)), 722 E_TP_NEGOT_FAILED, ts_negotfailed, respond, 723 (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 724 /* ^ more or less the location of class */ 725 ) 726 IFDEBUG(D_CONN) 727 printf("CR: after CRCCCHECKS: tpcb 0x%x, flags 0x%x\n", 728 tpcb, tpcb->tp_flags); 729 ENDDEBUG 730 takes_data = TRUE; 731 e.ATTR(CR_TPDU).e_cdt = hdr->tpdu_CRcdt; 732 e.ev_number = CR_TPDU; 733 734 so = tpcb->tp_sock; 735 if (so->so_options & SO_ACCEPTCONN) { 736 struct tp_pcb *parent_tpcb = tpcb; 737 /* 738 * Create a socket, tpcb, ll pcb, etc. 739 * for this newborn connection, and fill in all the values. 740 */ 741 IFDEBUG(D_CONN) 742 printf("abt to call tp_newsocket(0x%x, 0x%x, 0x%x, 0x%x)\n", 743 so, laddr, faddr, cons_channel); 744 ENDDEBUG 745 if( (so = 746 tp_newsocket(so, faddr, cons_channel, 747 class_to_use, 748 ((tpcb->tp_netservice == IN_CLNS) ? IN_CLNS : 749 (dgout_routine == tpcons_output)?ISO_CONS:ISO_CLNS)) 750 ) == (struct socket *)0 ) { 751 /* note - even if netservice is IN_CLNS, as far as 752 * the tp entity is concerned, the only differences 753 * are CO vs CL 754 */ 755 IFDEBUG(D_CONN) 756 printf("tp_newsocket returns 0\n"); 757 ENDDEBUG 758 goto discard; 759 } 760 tpcb = sototpcb(so); 761 insque(parent_tpcb, tpcb); 762 763 /* 764 * Stash the addresses in the net level pcb 765 * kind of like a pcbconnect() but don't need 766 * or want all those checks. 767 */ 768 (tpcb->tp_nlproto->nlp_putnetaddr)(so->so_pcb, faddr, TP_FOREIGN); 769 (tpcb->tp_nlproto->nlp_putnetaddr)(so->so_pcb, laddr, TP_LOCAL); 770 771 /* stash the f suffix in the new tpcb */ 772 bcopy(fsufxloc, tpcb->tp_fsuffix, fsufxlen); 773 /* l suffix is already there, unless this is an intercept case */ 774 if (intercepted) 775 bcopy(lsufxloc, tpcb->tp_lsuffix, lsufxlen); 776 (tpcb->tp_nlproto->nlp_putsufx) 777 (so->so_pcb, fsufxloc, fsufxlen, TP_FOREIGN); 778 (tpcb->tp_nlproto->nlp_putsufx) 779 (so->so_pcb, lsufxloc, lsufxlen, TP_LOCAL); 780 #ifdef TP_PERF_MEAS 781 if( tpcb->tp_perf_on = perf_meas ) { /* assignment */ 782 /* ok, let's create an mbuf for stashing the 783 * statistics if one doesn't already exist 784 */ 785 (void) tp_setup_perf(tpcb); 786 } 787 #endif TP_PERF_MEAS 788 tpcb->tp_fref = sref; 789 790 /* We've already checked for consistency with the options 791 * set in tpp, but we couldn't set them earlier because 792 * we didn't want to change options in the LISTENING tpcb. 793 * Now we set the options in the new socket's tpcb. 794 */ 795 (void) tp_consistency( tpcb, TP_FORCE, &tpp); 796 797 if(!tpcb->tp_use_checksum) 798 IncStat(ts_csum_off); 799 if(tpcb->tp_xpd_service) 800 IncStat(ts_use_txpd); 801 if(tpcb->tp_xtd_format) 802 IncStat(ts_xtd_fmt); 803 804 /* 805 * Get the maximum transmission unit from the lower layer(s) 806 * so we can negotiate a reasonable max TPDU size. 807 */ 808 (tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb, 809 &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0); 810 tpcb->tp_peer_acktime = acktime; 811 812 /* 813 * The following kludge is used to test retransmissions and 814 * timeout during connection establishment. 815 */ 816 IFDEBUG(D_ZDREF) 817 IncStat(ts_zdebug); 818 /*tpcb->tp_fref = 0;*/ 819 ENDDEBUG 820 } 821 IncStat(ts_CR_rcvd); 822 if (!tpcb->tp_cebit_off) { 823 tpcb->tp_win_recv = tp_start_win << 8; 824 tpcb->tp_cong_sample.cs_size = 0; 825 LOCAL_CREDIT(tpcb); 826 CONG_INIT_SAMPLE(tpcb); 827 CONG_UPDATE_SAMPLE(tpcb, ce_bit); 828 } 829 tpcb->tp_ackrcvd = 0; 830 } else if ( dutype == ER_TPDU_type ) { 831 /* 832 * ER TPDUs have to be recognized separately 833 * because they don't necessarily have a tpcb 834 * with them and we don't want err out looking for such 835 * a beast. 836 * We could put a bunch of little kludges in the 837 * next section of code so it would avoid references to tpcb 838 * if dutype == ER_TPDU_type but we don't want code for ERs to 839 * mess up code for data transfer. 840 */ 841 IncStat(ts_ER_rcvd); 842 e.ev_number = ER_TPDU; 843 e.ATTR(ER_TPDU).e_reason = (u_char)hdr->tpdu_ERreason; 844 takes_data = 1; 845 } else { 846 /* tpdu type is CC, XPD, XAK, GR, AK, DR, DC, or DT */ 847 848 /* In the next 4 checks, 849 * _tpduf is the fixed part; add 2 to get the dref bits of 850 * the fixed part (can't take the address of a bit field) 851 */ 852 if(cons_channel) { 853 #if NARGOXTWENTYFIVE > 0 854 extern struct tp_pcb *cons_chan_to_tpcb(); 855 856 tpcb = cons_chan_to_tpcb( cons_channel ); 857 /* Problem: We may have a legit 858 * error situation yet we may or may not have 859 * a correspondence between the tpcb and the vc, 860 * e.g., TP4cr--> <no dice, respond w/ DR on vc> 861 * <--- DR 862 * Now it's up to TP to look at the tpdu and do one of: 863 * confirm(dgm)(cr), confirm(circuit)(cr), reject(cr), or 864 * nothing, if the circuit is already open (any other tpdu). 865 * Sigh. 866 */ 867 868 /* I don't know about this error value */ 869 CHECK( (tpcb == (struct tp_pcb *)0) , 870 E_TP_NO_CR_ON_NC, ts_inv_dref, respond, 871 (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 872 #else 873 printf("tp_input(): X25 NOT CONFIGURED!!\n"); 874 #endif NARGOXTWENTYFIVE > 0 875 876 } else { 877 878 CHECK( ((int)dref <= 0 || dref >= N_TPREF) , 879 E_TP_MISM_REFS,ts_inv_dref, nonx_dref, 880 (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 881 CHECK( ((tpcb = tp_ref[dref].tpr_pcb ) == (struct tp_pcb *) 0 ), 882 E_TP_MISM_REFS,ts_inv_dref, nonx_dref, 883 (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 884 CHECK( (tpcb->tp_refp->tpr_state == REF_FREE), 885 E_TP_MISM_REFS,ts_inv_dref, nonx_dref, 886 (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 887 } 888 889 IFDEBUG(D_TPINPUT) 890 printf("HAVE A TPCB 2: 0x%x\n", tpcb); 891 ENDDEBUG 892 893 /* causes a DR to be sent for CC; ER for all else */ 894 CHECK( (tpcb->tp_refp->tpr_state == REF_FROZEN), 895 (dutype == CC_TPDU_type?E_TP_NO_SESSION:E_TP_MISM_REFS), 896 ts_inv_dref, respond, 897 (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 898 899 IFDEBUG(D_TPINPUT) 900 printf("state of dref %d ok, tpcb 0x%x\n", dref,tpcb); 901 ENDDEBUG 902 /* 903 * At this point the state of the dref could be 904 * FROZEN: tpr_pcb == NULL, has ( reference only) timers 905 * for example, DC may arrive after the close() has detached 906 * the tpcb (e.g., if user turned off SO_LISTEN option) 907 * OPENING : a tpcb exists but no timers yet 908 * OPEN : tpcb exists & timers are outstanding 909 */ 910 911 if (!tpcb->tp_cebit_off) 912 CONG_UPDATE_SAMPLE(tpcb, ce_bit); 913 914 dusize = tpcb->tp_tpdusize; 915 916 dutype = hdr->tpdu_type << 8; /* for the switch below */ 917 918 WHILE_OPTIONS(P, hdr, tpcb->tp_xtd_format) /* { */ 919 920 #define caseof(x,y) case (((x)<<8)+(y)) 921 switch( dutype | vbptr(P)->tpv_code ) { 922 923 caseof( CC_TPDU_type, TPP_addl_opt ): 924 /* not in class 0; 1 octet */ 925 vb_getval(P, u_char, addlopt); 926 break; 927 caseof( CC_TPDU_type, TPP_tpdu_size ): 928 { 929 u_char odusize = dusize; 930 vb_getval(P, u_char, dusize); 931 CHECK( (dusize < TP_MIN_TPDUSIZE || 932 dusize > TP_MAX_TPDUSIZE || dusize > odusize), 933 E_TP_INV_PVAL, ts_inv_pval, respond, 934 (1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) ) 935 IFDEBUG(D_TPINPUT) 936 printf("CC dusize 0x%x\n", dusize); 937 ENDDEBUG 938 } 939 break; 940 caseof( CC_TPDU_type, TPP_calling_sufx): 941 IFDEBUG(D_TPINPUT) 942 printf("CC calling (local) sufxlen 0x%x\n", lsufxlen); 943 ENDDEBUG 944 lsufxloc = (caddr_t) &vbptr(P)->tpv_val; 945 lsufxlen = vbptr(P)->tpv_len; 946 break; 947 caseof( CC_TPDU_type, TPP_acktime ): 948 /* class 4 only, 2 octets */ 949 vb_getval(P, u_short, acktime); 950 acktime = acktime/500; /* convert to slowtimo ticks */ 951 if( (short)acktime <=0 ) 952 acktime = 2; 953 break; 954 caseof( CC_TPDU_type, TPP_called_sufx): 955 fsufxloc = (caddr_t) &vbptr(P)->tpv_val; 956 fsufxlen = vbptr(P)->tpv_len; 957 IFDEBUG(D_TPINPUT) 958 printf("CC called (foreign) sufx len %d\n", fsufxlen); 959 ENDDEBUG 960 break; 961 962 caseof( CC_TPDU_type, TPP_checksum): 963 caseof( DR_TPDU_type, TPP_checksum): 964 caseof( DT_TPDU_type, TPP_checksum): 965 caseof( XPD_TPDU_type, TPP_checksum): 966 if( tpcb->tp_use_checksum ) { 967 CHECK( iso_check_csum(m, tpdu_len), 968 E_TP_INV_PVAL, ts_bad_csum, discard, 0) 969 } 970 break; 971 972 /* this is different from the above because in the context 973 * of concat/ sep tpdu_len might not be the same as hdr len 974 */ 975 caseof( AK_TPDU_type, TPP_checksum): 976 caseof( XAK_TPDU_type, TPP_checksum): 977 caseof( DC_TPDU_type, TPP_checksum): 978 if( tpcb->tp_use_checksum ) { 979 CHECK( iso_check_csum(m, (int)hdr->tpdu_li + 1), 980 E_TP_INV_PVAL, ts_bad_csum, discard, 0) 981 } 982 break; 983 #ifdef notdef 984 caseof( DR_TPDU_type, TPP_addl_info ): 985 /* ignore - its length and meaning are 986 * user defined and there's no way 987 * to pass this info to the user anyway 988 */ 989 break; 990 #endif notdef 991 992 caseof( AK_TPDU_type, TPP_subseq ): 993 /* used after reduction of window */ 994 vb_getval(P, u_short, subseq); 995 subseq = ntohs(subseq); 996 IFDEBUG(D_ACKRECV) 997 printf("AK Subsequence # 0x%x\n", subseq); 998 ENDDEBUG 999 break; 1000 1001 caseof( AK_TPDU_type, TPP_flow_cntl_conf ): 1002 { 1003 u_int ylwe; 1004 u_short ysubseq, ycredit; 1005 1006 fcc_present = TRUE; 1007 vb_getval(P, u_int, ylwe); 1008 vb_getval(P, u_short, ysubseq); 1009 vb_getval(P, u_short, ycredit); 1010 ylwe = ntohl(ylwe); 1011 ysubseq = ntohs(ysubseq); 1012 ycredit = ntohs(ycredit); 1013 IFDEBUG(D_ACKRECV) 1014 printf("AK FCC lwe 0x%x, subseq 0x%x, cdt 0x%x\n", 1015 ylwe, ysubseq, ycredit); 1016 ENDDEBUG 1017 } 1018 break; 1019 1020 default: 1021 IFDEBUG(D_TPINPUT) 1022 printf("param ignored dutype 0x%x, code 0x%x\n", 1023 dutype, vbptr(P)->tpv_code); 1024 ENDDEBUG 1025 IFTRACE(D_TPINPUT) 1026 tptrace(TPPTmisc, "param ignored dutype code ", 1027 dutype, vbptr(P)->tpv_code ,0,0); 1028 ENDTRACE 1029 IncStat(ts_param_ignored); 1030 break; 1031 #undef caseof 1032 } 1033 /* } */ END_WHILE_OPTIONS(P) 1034 1035 /* NOTE: the variable dutype has been shifted left! */ 1036 1037 switch( hdr->tpdu_type ) { 1038 case CC_TPDU_type: 1039 /* If CC comes back with an unacceptable class 1040 * respond with a DR or ER 1041 */ 1042 1043 opt = hdr->tpdu_CCoptions; /* 1 byte */ 1044 1045 { 1046 tpp = tpcb->_tp_param; 1047 tpp.p_class = (1<<hdr->tpdu_CCclass); 1048 tpp.p_tpdusize = dusize; 1049 tpp.p_dont_change_params = 0; 1050 tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT; 1051 tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD; 1052 tpp.p_use_checksum = (addlopt & TPAO_NO_CSUM) == 0; 1053 #ifdef notdef 1054 tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC; 1055 tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD; 1056 tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC; 1057 #endif notdef 1058 1059 CHECK( 1060 tp_consistency(tpcb, TP_FORCE, &tpp) != 0, 1061 E_TP_NEGOT_FAILED, ts_negotfailed, respond, 1062 (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 1063 /* ^ more or less the location of class */ 1064 ) 1065 IFTRACE(D_CONN) 1066 tptrace(TPPTmisc, 1067 "after 1 consist class, out, tpconsout", 1068 tpcb->tp_class, dgout_routine, tpcons_output, 0 1069 ); 1070 ENDTRACE 1071 CHECK( 1072 ((class_to_use == TP_CLASS_0)&& 1073 (dgout_routine != tpcons_output)), 1074 E_TP_NEGOT_FAILED, ts_negotfailed, respond, 1075 (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 1076 /* ^ more or less the location of class */ 1077 ) 1078 } 1079 if( ! tpcb->tp_use_checksum) 1080 IncStat(ts_csum_off); 1081 if(tpcb->tp_xpd_service) 1082 IncStat(ts_use_txpd); 1083 if(tpcb->tp_xtd_format) 1084 IncStat(ts_xtd_fmt); 1085 1086 IFTRACE(D_CONN) 1087 tptrace(TPPTmisc, "after CC class flags dusize CCclass", 1088 tpcb->tp_class, tpcb->tp_flags, tpcb->tp_tpdusize, 1089 hdr->tpdu_CCclass); 1090 ENDTRACE 1091 1092 /* 1093 * Get the maximum transmission unit from the lower layer(s) 1094 * so we can decide how large a TPDU size to negotiate. 1095 * It would be nice if the arguments to this 1096 * were more reasonable. 1097 */ 1098 (tpcb->tp_nlproto->nlp_mtu)(tpcb->tp_sock, tpcb->tp_sock->so_pcb, 1099 &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0); 1100 1101 #ifdef CONS 1102 /* Could be that this CC came in on a NEW vc, in which case 1103 * we have to confirm it. 1104 */ 1105 if( cons_channel ) 1106 cons_netcmd( CONN_CONFIRM, tpcb->tp_npcb, cons_channel, 1107 tpcb->tp_class == TP_CLASS_4); 1108 #endif CONS 1109 1110 tpcb->tp_peer_acktime = acktime; 1111 1112 /* if called or calling suffices appeared on the CC, 1113 * they'd better jive with what's in the pcb 1114 */ 1115 if( fsufxlen ) { 1116 CHECK( ((tpcb->tp_fsuffixlen != fsufxlen) || 1117 bcmp(fsufxloc, tpcb->tp_fsuffix, fsufxlen)), 1118 E_TP_INV_PVAL,ts_inv_sufx, respond, 1119 (1+fsufxloc - (caddr_t)hdr)) 1120 } 1121 if( lsufxlen ) { 1122 CHECK( ((tpcb->tp_lsuffixlen != lsufxlen) || 1123 bcmp(lsufxloc, tpcb->tp_lsuffix, lsufxlen)), 1124 E_TP_INV_PVAL,ts_inv_sufx, respond, 1125 (1+lsufxloc - (caddr_t)hdr)) 1126 } 1127 1128 e.ATTR(CC_TPDU).e_sref = sref; 1129 e.ATTR(CC_TPDU).e_cdt = hdr->tpdu_CCcdt; 1130 takes_data = TRUE; 1131 e.ev_number = CC_TPDU; 1132 IncStat(ts_CC_rcvd); 1133 break; 1134 1135 case DC_TPDU_type: 1136 if (sref != tpcb->tp_fref) 1137 printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n", 1138 sref, tpcb->tp_fref); 1139 1140 CHECK( (sref != tpcb->tp_fref), 1141 E_TP_MISM_REFS, ts_inv_sufx, discard, 1142 (1 + (caddr_t)&hdr->tpdu_DCsref - (caddr_t)hdr)) 1143 1144 e.ev_number = DC_TPDU; 1145 IncStat(ts_DC_rcvd); 1146 break; 1147 1148 case DR_TPDU_type: 1149 IFTRACE(D_TPINPUT) 1150 tptrace(TPPTmisc, "DR recvd", hdr->tpdu_DRreason, 0, 0, 0); 1151 ENDTRACE 1152 if (sref != tpcb->tp_fref) { 1153 printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n", 1154 sref, tpcb->tp_fref); 1155 } 1156 1157 CHECK( (sref != 0 && sref != tpcb->tp_fref && 1158 tpcb->tp_state != TP_CRSENT), 1159 (TP_ERROR_SNDC | E_TP_MISM_REFS),ts_inv_sufx, respond, 1160 (1 + (caddr_t)&hdr->tpdu_DRsref - (caddr_t)hdr)) 1161 1162 e.ATTR(DR_TPDU).e_reason = hdr->tpdu_DRreason; 1163 e.ATTR(DR_TPDU).e_sref = (u_short)sref; 1164 takes_data = TRUE; 1165 e.ev_number = DR_TPDU; 1166 IncStat(ts_DR_rcvd); 1167 break; 1168 1169 case ER_TPDU_type: 1170 IFTRACE(D_TPINPUT) 1171 tptrace(TPPTmisc, "ER recvd", hdr->tpdu_ERreason,0,0,0); 1172 ENDTRACE 1173 e.ev_number = ER_TPDU; 1174 e.ATTR(ER_TPDU).e_reason = hdr->tpdu_ERreason; 1175 IncStat(ts_ER_rcvd); 1176 break; 1177 1178 case AK_TPDU_type: 1179 1180 e.ATTR(AK_TPDU).e_subseq = subseq; 1181 e.ATTR(AK_TPDU).e_fcc_present = fcc_present; 1182 1183 if (tpcb->tp_xtd_format) { 1184 #ifdef BYTE_ORDER 1185 union seq_type seqeotX; 1186 1187 seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 1188 e.ATTR(AK_TPDU).e_seq = seqeotX.s_seq; 1189 e.ATTR(AK_TPDU).e_cdt = ntohs(hdr->tpdu_AKcdtX); 1190 #else 1191 e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdtX; 1192 e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseqX; 1193 #endif BYTE_ORDER 1194 } else { 1195 e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdt; 1196 e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseq; 1197 } 1198 IFTRACE(D_TPINPUT) 1199 tptrace(TPPTmisc, "AK recvd seq cdt subseq fcc_pres", 1200 e.ATTR(AK_TPDU).e_seq, e.ATTR(AK_TPDU).e_cdt, 1201 subseq, fcc_present); 1202 ENDTRACE 1203 1204 e.ev_number = AK_TPDU; 1205 IncStat(ts_AK_rcvd); 1206 IncPStat(tpcb, tps_AK_rcvd); 1207 break; 1208 1209 case XAK_TPDU_type: 1210 if (tpcb->tp_xtd_format) { 1211 #ifdef BYTE_ORDER 1212 union seq_type seqeotX; 1213 1214 seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 1215 e.ATTR(XAK_TPDU).e_seq = seqeotX.s_seq; 1216 #else 1217 e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseqX; 1218 #endif BYTE_ORDER 1219 } else { 1220 e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseq; 1221 } 1222 e.ev_number = XAK_TPDU; 1223 IncStat(ts_XAK_rcvd); 1224 IncPStat(tpcb, tps_XAK_rcvd); 1225 break; 1226 1227 case XPD_TPDU_type: 1228 if (tpcb->tp_xtd_format) { 1229 #ifdef BYTE_ORDER 1230 union seq_type seqeotX; 1231 1232 seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 1233 e.ATTR(XPD_TPDU).e_seq = seqeotX.s_seq; 1234 #else 1235 e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseqX; 1236 #endif BYTE_ORDER 1237 } else { 1238 e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseq; 1239 } 1240 takes_data = TRUE; 1241 e.ev_number = XPD_TPDU; 1242 IncStat(ts_XPD_rcvd); 1243 IncPStat(tpcb, tps_XPD_rcvd); 1244 break; 1245 1246 case DT_TPDU_type: 1247 { /* the y option will cause occasional packets to be dropped. 1248 * A little crude but it works. 1249 */ 1250 1251 IFDEBUG(D_DROP) 1252 if(time.tv_usec & 0x4 && hdr->tpdu_DTseq & 0x1) { 1253 IncStat(ts_ydebug); 1254 goto discard; 1255 } 1256 ENDDEBUG 1257 } 1258 if (tpcb->tp_class == TP_CLASS_0) { 1259 e.ATTR(DT_TPDU).e_seq = 0; /* actually don't care */ 1260 e.ATTR(DT_TPDU).e_eot = (((struct tp0du *)hdr)->tp0du_eot); 1261 } else if (tpcb->tp_xtd_format) { 1262 #ifdef BYTE_ORDER 1263 union seq_type seqeotX; 1264 1265 seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 1266 e.ATTR(DT_TPDU).e_seq = seqeotX.s_seq; 1267 e.ATTR(DT_TPDU).e_eot = seqeotX.s_eot; 1268 #else 1269 e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseqX; 1270 e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeotX; 1271 #endif BYTE_ORDER 1272 } else { 1273 e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseq; 1274 e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeot; 1275 } 1276 if(e.ATTR(DT_TPDU).e_eot) 1277 IncStat(ts_eot_input); 1278 takes_data = TRUE; 1279 e.ev_number = DT_TPDU; 1280 IncStat(ts_DT_rcvd); 1281 IncPStat(tpcb, tps_DT_rcvd); 1282 break; 1283 1284 case GR_TPDU_type: 1285 tp_indicate(T_DISCONNECT, tpcb, ECONNABORTED); 1286 /* drop through */ 1287 default: 1288 /* this should NEVER happen because there is a 1289 * check for dutype well above here 1290 */ 1291 error = E_TP_INV_TPDU; /* causes an ER */ 1292 IFDEBUG(D_TPINPUT) 1293 printf("INVALID dutype 0x%x\n", hdr->tpdu_type); 1294 ENDDEBUG 1295 IncStat(ts_inv_dutype); 1296 goto respond; 1297 } 1298 } 1299 /* peel off the tp header; 1300 * remember that the du_li doesn't count itself. 1301 * This may leave us w/ an empty mbuf at the front of a chain. 1302 * We can't just throw away the empty mbuf because hdr still points 1303 * into the mbuf's data area and we're still using hdr (the tpdu header) 1304 */ 1305 m->m_len -= ((int)hdr->tpdu_li + 1); 1306 m->m_data += ((int)hdr->tpdu_li + 1); 1307 1308 if (takes_data) { 1309 int max = tpdu_info[ hdr->tpdu_type ] [TP_MAX_DATA_INDEX]; 1310 int datalen = tpdu_len - hdr->tpdu_li - 1, mbtype = MT_DATA; 1311 struct cmsghdr c_hdr; 1312 struct mbuf *n; 1313 1314 CHECK( (max && datalen > max), E_TP_LENGTH_INVAL, 1315 ts_inv_length, respond, (max + hdr->tpdu_li + 1) ); 1316 switch( hdr->tpdu_type ) { 1317 1318 case CR_TPDU_type: 1319 c_hdr.cmsg_type = TPOPT_CONN_DATA; 1320 goto make_control_msg; 1321 1322 case CC_TPDU_type: 1323 c_hdr.cmsg_type = TPOPT_CFRM_DATA; 1324 goto make_control_msg; 1325 1326 case DR_TPDU_type: 1327 c_hdr.cmsg_type = TPOPT_DISC_DATA; 1328 make_control_msg: 1329 c_hdr.cmsg_level = SOL_TRANSPORT; 1330 mbtype = MT_CONTROL; 1331 MGET(n, M_DONTWAIT, MT_DATA); 1332 if (n) { 1333 datalen += sizeof(c_hdr); 1334 n->m_len = sizeof(c_hdr); 1335 c_hdr.cmsg_len = datalen; 1336 *mtod(n, struct cmsghdr *) = c_hdr; 1337 n->m_next = m; 1338 m = n; 1339 } else {m_freem(m); m = 0; goto invoke;} 1340 /* FALLTHROUGH */ 1341 1342 case XPD_TPDU_type: 1343 if (mbtype != MT_CONTROL) 1344 mbtype = MT_OOBDATA; 1345 m->m_flags |= M_EOR; 1346 /* FALLTHROUGH */ 1347 1348 case DT_TPDU_type: 1349 for (n = m; n; n = n->m_next) { 1350 MCHTYPE(n, mbtype); 1351 } 1352 invoke: 1353 e.ATTR(DT_TPDU).e_datalen = datalen; 1354 e.ATTR(DT_TPDU).e_data = m; 1355 break; 1356 1357 default: 1358 printf( 1359 "ERROR in tp_input! hdr->tpdu_type 0x%x takes_data 0x%x m 0x%x\n", 1360 hdr->tpdu_type, takes_data, m); 1361 break; 1362 } 1363 /* prevent m_freem() after tp_driver() from throwing it all away */ 1364 m = MNULL; 1365 } 1366 1367 IncStat(ts_tpdu_rcvd); 1368 1369 IFDEBUG(D_TPINPUT) 1370 printf( "tp_input: before driver, state 0x%x event 0x%x m 0x%x", 1371 tpcb->tp_state, e.ev_number, m ); 1372 printf(" e.e_data 0x%x\n", e.ATTR(DT_TPDU).e_data); 1373 printf("takes_data 0x%x m_len 0x%x, tpdu_len 0x%x\n", 1374 takes_data, (m==MNULL)?0:m->m_len, tpdu_len); 1375 ENDDEBUG 1376 1377 error = tp_driver(tpcb, &e); 1378 1379 ASSERT(tpcb != (struct tp_pcb *)0); 1380 ASSERT(tpcb->tp_sock != (struct socket *)0); 1381 if( tpcb->tp_sock->so_error == 0 ) 1382 tpcb->tp_sock->so_error = error; 1383 1384 /* Kludge to keep the state tables under control (adding 1385 * data on connect & disconnect & freeing the mbuf containing 1386 * the data would have exploded the tables and made a big mess ). 1387 */ 1388 switch(e.ev_number) { 1389 case CC_TPDU: 1390 case DR_TPDU: 1391 case CR_TPDU: 1392 m = e.ATTR(CC_TPDU).e_data; /* same field for all three dutypes */ 1393 IFDEBUG(D_TPINPUT) 1394 printf("after driver, restoring m to 0x%x, takes_data 0x%x\n", 1395 m, takes_data); 1396 ENDDEBUG 1397 break; 1398 default: 1399 break; 1400 } 1401 /* Concatenated sequences are terminated by any tpdu that 1402 * carries data: CR, CC, DT, XPD, DR. 1403 * All other tpdu types may be concatenated: AK, XAK, DC, ER. 1404 */ 1405 1406 separate: 1407 if ( takes_data == 0 ) { 1408 ASSERT( m != MNULL ); 1409 /* 1410 * we already peeled off the prev. tp header so 1411 * we can just pull up some more and repeat 1412 */ 1413 1414 if( m = tp_inputprep(m) ) { 1415 IFDEBUG(D_TPINPUT) 1416 hdr = mtod(m, struct tpdu *); 1417 printf("tp_input @ separate: hdr 0x%x size %d m 0x%x\n", 1418 hdr, (int) hdr->tpdu_li + 1, m); 1419 dump_mbuf(m, "tp_input after driver, at separate"); 1420 ENDDEBUG 1421 1422 IncStat(ts_concat_rcvd); 1423 goto again; 1424 } 1425 } 1426 if ( m != MNULL ) { 1427 IFDEBUG(D_TPINPUT) 1428 printf("tp_input : m_freem(0x%x)\n", m); 1429 ENDDEBUG 1430 m_freem(m); 1431 IFDEBUG(D_TPINPUT) 1432 printf("tp_input : after m_freem 0x%x\n", m); 1433 ENDDEBUG 1434 } 1435 return (ProtoHook) tpcb; 1436 1437 discard: 1438 /* class 4: drop the tpdu */ 1439 /* class 2,0: Should drop the net connection, if you can figure out 1440 * to which connection it applies 1441 */ 1442 IFDEBUG(D_TPINPUT) 1443 printf("tp_input DISCARD\n"); 1444 ENDDEBUG 1445 IFTRACE(D_TPINPUT) 1446 tptrace(TPPTmisc, "tp_input DISCARD m", m,0,0,0); 1447 ENDTRACE 1448 m_freem(m); 1449 IncStat(ts_recv_drop); 1450 return (ProtoHook)0; 1451 1452 nonx_dref: 1453 switch (dutype) { 1454 default: 1455 goto discard; 1456 case CC_TPDU_type: 1457 /* error = E_TP_MISM_REFS; */ 1458 break; 1459 case DR_TPDU_type: 1460 error |= TP_ERROR_SNDC; 1461 } 1462 respond: 1463 IFDEBUG(D_TPINPUT) 1464 printf("RESPOND: error 0x%x, errlen 0x%x\n", error, errlen); 1465 ENDDEBUG 1466 IFTRACE(D_TPINPUT) 1467 tptrace(TPPTmisc, "tp_input RESPOND m error sref", m, error, sref, 0); 1468 ENDTRACE 1469 if (sref == 0) 1470 goto discard; 1471 (void) tp_error_emit(error, (u_long)sref, (struct sockaddr_iso *)faddr, 1472 (struct sockaddr_iso *)laddr, m, errlen, tpcb, 1473 (int)cons_channel, dgout_routine); 1474 IFDEBUG(D_ERROR_EMIT) 1475 printf("tp_input after error_emit\n"); 1476 ENDDEBUG 1477 1478 #ifdef lint 1479 printf("",sref,opt); 1480 #endif lint 1481 IncStat(ts_recv_drop); 1482 return (ProtoHook)0; 1483 } 1484 1485 1486 /* 1487 * NAME: tp_headersize() 1488 * 1489 * CALLED FROM: 1490 * tp_emit() and tp_sbsend() 1491 * TP needs to know the header size so it can figure out how 1492 * much data to put in each tpdu. 1493 * 1494 * FUNCTION, ARGUMENTS, and RETURN VALUE: 1495 * For a given connection, represented by (tpcb), and 1496 * tpdu type (dutype), return the size of a tp header. 1497 * 1498 * RETURNS: the expected size of the heade in bytesr 1499 * 1500 * SIDE EFFECTS: 1501 * 1502 * NOTES: It would be nice if it got the network header size as well. 1503 */ 1504 int 1505 tp_headersize(dutype, tpcb) 1506 int dutype; 1507 struct tp_pcb *tpcb; 1508 { 1509 register int size = 0; 1510 1511 IFTRACE(D_CONN) 1512 tptrace(TPPTmisc, "tp_headersize dutype class xtd_format", 1513 dutype, tpcb->tp_class, tpcb->tp_xtd_format, 0); 1514 ENDTRACE 1515 if( !( (tpcb->tp_class == TP_CLASS_0) || 1516 (tpcb->tp_class == TP_CLASS_4) || 1517 (dutype == DR_TPDU_type) || 1518 (dutype == CR_TPDU_type) )) { 1519 printf("tp_headersize:dutype 0x%x, class 0x%x", 1520 dutype, tpcb->tp_class); 1521 /* TODO: identify this and GET RID OF IT */ 1522 } 1523 ASSERT( (tpcb->tp_class == TP_CLASS_0) || 1524 (tpcb->tp_class == TP_CLASS_4) || 1525 (dutype == DR_TPDU_type) || 1526 (dutype == CR_TPDU_type) ); 1527 1528 if( tpcb->tp_class == TP_CLASS_0 ) { 1529 size = tpdu_info[ dutype ] [TP_LEN_CLASS_0_INDEX]; 1530 } else { 1531 size = tpdu_info[ dutype ] [tpcb->tp_xtd_format]; 1532 } 1533 return size; 1534 /* caller must get network level header size separately */ 1535 } 1536