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