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