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