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