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