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