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 * 33 * tp_input() gets an mbuf chain from ip. Actually, not directly 34 * from ip, because ip calls a net-level routine that strips off 35 * the net header and then calls tp_input(), passing the proper type 36 * of addresses for the address family in use (how it figures out 37 * which AF is not yet determined. 38 * 39 * Decomposing the tpdu is some of the most laughable code. The variable-length 40 * parameters and the problem of non-aligned memory references 41 * necessitates such abominations as the macros WHILE_OPTIONS (q.v. below) 42 * to loop through the header and decompose it. 43 * 44 * The routine tp_newsocket() is called when a CR comes in for a listening 45 * socket. tp_input calls sonewconn() and tp_newsocket() to set up the 46 * "child" socket. Most tpcb values are copied from the parent tpcb into 47 * the child. 48 * 49 * Also in here is tp_headersize() (grot) which tells the expected size 50 * of a tp header, to be used by other layers. It's in here because it 51 * uses the static structure tpdu_info. 52 */ 53 54 #ifndef lint 55 static char *rcsid = "$Header: tp_input.c,v 5.6 88/11/18 17:27:38 nhall Exp $"; 56 #endif lint 57 58 #include "argoxtwentyfive.h" 59 #include "param.h" 60 #include "mbuf.h" 61 #include "socket.h" 62 #include "socketvar.h" 63 #include "domain.h" 64 #include "protosw.h" 65 #include "errno.h" 66 #include "time.h" 67 #include "kernel.h" 68 #include "types.h" 69 #include "iso_errno.h" 70 #include "tp_param.h" 71 #include "tp_timer.h" 72 #include "tp_stat.h" 73 #include "tp_pcb.h" 74 #include "argo_debug.h" 75 #include "tp_trace.h" 76 #include "tp_tpdu.h" 77 #include "iso.h" 78 #include "cons.h" 79 80 int iso_check_csum(), tp_driver(), tp_headersize(), tp_error_emit(); 81 82 /* 83 #ifdef lint 84 #undef ATTR 85 #define ATTR(X)ev_number 86 #endif lint 87 */ 88 89 struct mbuf * 90 tp_inputprep(m) 91 register struct mbuf *m; 92 { 93 int hdrlen; 94 95 IFDEBUG(D_TPINPUT) 96 printf("tp_inputprep: m 0x%x\n", m) ; 97 ENDDEBUG 98 99 while( m->m_len < 1 ) { 100 if( (m = m_free(m)) == MNULL ) { 101 return (struct mbuf *)0; 102 } 103 } 104 if(((int)m->m_data) & 0x3) { 105 /* If we are not 4-byte aligned, we have to be 106 * above the beginning of the mbuf, and it is ok just 107 * to slide it back. 108 */ 109 caddr_t ocp = m->m_data; 110 111 m->m_data = (caddr_t)(((int)m->m_data) & ~0x3); 112 ovbcopy(ocp, m->m_data, (unsigned)m->m_len); 113 } 114 CHANGE_MTYPE(m, TPMT_DATA); 115 116 /* we KNOW that there is at least 1 byte in this mbuf 117 and that it is hdr->tpdu_li XXXXXXX! */ 118 119 hdrlen = 1 + *mtod( m, u_char *); 120 121 /* 122 * now pull up the whole tp header 123 */ 124 if ( m->m_len < hdrlen) { 125 if ((m = m_pullup(m, hdrlen)) == MNULL ) { 126 IncStat(ts_recv_drop); 127 return (struct mbuf *)0; 128 } 129 } 130 IFDEBUG(D_INPUT) 131 printf( 132 " at end: m 0x%x hdr->tpdu_li 0x%x m_len 0x%x\n",m, 133 hdrlen, m->m_len); 134 ENDDEBUG 135 return m; 136 } 137 138 /* begin groan 139 * -- this array and the following macros allow you to step through the 140 * parameters of the variable part of a header 141 * note that if for any reason the values of the **_TPDU macros (in tp_events.h) 142 * should change, this array has to be rearranged 143 */ 144 145 #define TP_LEN_CLASS_0_INDEX 2 146 #define TP_MAX_DATA_INDEX 3 147 148 static u_char tpdu_info[][4] = 149 { 150 /* length max data len */ 151 /* reg fmt xtd fmt class 0 */ 152 /* UNUSED 0x0 */ 0x0 , 0x0, 0x0, 0x0, 153 /* XPD_TPDU_type 0x1 */ 0x5, 0x8, 0x0, TP_MAX_XPD_DATA, 154 /* XAK_TPDU_type 0x2 */ 0x5 , 0x8, 0x0, 0x0, 155 /* GR_TPDU_type 0x3 */ 0x0 , 0x0, 0x0, 0x0, 156 /* UNUSED 0x4 */ 0x0 , 0x0, 0x0, 0x0, 157 /* UNUSED 0x5 */ 0x0 , 0x0, 0x0, 0x0, 158 /* AK_TPDU_type 0x6 */ 0x5, 0xa, 0x0, 0x0, 159 /* ER_TPDU_type 0x7 */ 0x5, 0x5, 0x0, 0x0, 160 /* DR_TPDU_type 0x8 */ 0x7, 0x7, 0x7, TP_MAX_DR_DATA, 161 /* UNUSED 0x9 */ 0x0 , 0x0, 0x0, 0x0, 162 /* UNUSED 0xa */ 0x0 , 0x0, 0x0, 0x0, 163 /* UNUSED 0xb */ 0x0 , 0x0, 0x0, 0x0, 164 /* DC_TPDU_type 0xc */ 0x6, 0x6, 0x0, 0x0, 165 /* CC_TPDU_type 0xd */ 0x7, 0x7, 0x7, TP_MAX_CC_DATA, 166 /* CR_TPDU_type 0xe */ 0x7, 0x7, 0x7, TP_MAX_CR_DATA, 167 /* DT_TPDU_type 0xf */ 0x5, 0x8, 0x3, 0x0, 168 }; 169 170 /* 171 * WHENEVER YOU USE THE FOLLOWING MACRO, 172 * BE SURE THE TPDUTYPE IS A LEGIT VALUE FIRST! 173 */ 174 175 #define WHILE_OPTIONS(P, hdr,format)\ 176 { register caddr_t P;\ 177 P = (caddr_t)(hdr) +\ 178 tpdu_info[(hdr)->tpdu_type][(format)];\ 179 while( P < (caddr_t)(hdr) + (int)((hdr)->tpdu_li) ) { 180 181 #define END_WHILE_OPTIONS(P)\ 182 P = P + 2 + (int)((struct tp_vbp *)P)->tpv_len ;\ 183 } } 184 185 #define CHECK(Phrase, Erval, Stat, Whattodo, Loc)\ 186 if(Phrase) { error = (Erval); errloc = (caddr_t)(Loc); IncStat(Stat); \ 187 goto Whattodo; } 188 189 /* end groan */ 190 191 /* 192 * NAME: tp_newsocket() 193 * 194 * CALLED FROM: 195 * tp_input() on incoming CR, when a socket w/ the called suffix 196 * is awaiting a connection request 197 * 198 * FUNCTION and ARGUMENTS: 199 * Create a new socket structure, attach to it a new transport pcb, 200 * using a copy of the net level pcb for the parent socket. 201 * (so) is the parent socket. 202 * (fname) is the foreign address (all that's used is the nsap portion) 203 * 204 * RETURN VALUE: 205 * a new socket structure, being this end of the newly formed connection. 206 * 207 * SIDE EFFECTS: 208 * Sets a few things in the tpcb and net level pcb 209 * 210 * NOTES: 211 */ 212 static struct socket * 213 tp_newsocket(so, fname, cons_channel, class_to_use, netservice) 214 struct socket *so; 215 struct sockaddr *fname; 216 u_int cons_channel; 217 u_char class_to_use; 218 u_int netservice; 219 { 220 register struct tp_pcb *tpcb = sototpcb(so); /* old tpcb, needed below */ 221 struct tp_pcb * newtpcb; 222 struct proc * selproc = so->so_rcv.sb_sel; /* kludge for select */ 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 selproc, so_head", 231 so, tpcb, selproc, so->so_head); 232 ENDTRACE 233 234 if ((so = sonewconn(so)) == (struct socket *)0) 235 return so; 236 IFTRACE(D_NEWSOCK) 237 tptraceTPCB(TPPTmisc, "newsock: after newconn so, selproc, so_head", 238 so, selproc, so->so_head, 0); 239 ENDTRACE 240 241 so->so_rcv.sb_sel = selproc; /* so that soisconnected() after receipt 242 * of the ack will wake this guy up if he's selecting on the 243 * listening socket 244 */ 245 IFDEBUG(D_NEWSOCK) 246 printf("tp_newsocket(channel 0x%x) after sonewconn so 0x%x \n", 247 cons_channel, so); 248 dump_addr(fname); 249 { 250 struct socket *t, *head ; 251 252 head = so->so_head; 253 t = so; 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 while( (t=t->so_q0) && t!= so && t!= head) 257 printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n", 258 t, t->so_head, t->so_q0, t->so_q0len); 259 } 260 ENDDEBUG 261 262 /* 263 * before we clobber the old tpcb ptr, get these items from the parent pcb 264 */ 265 newtpcb = sototpcb(so); 266 newtpcb->_tp_param = tpcb->_tp_param; 267 newtpcb->tp_flags = tpcb->tp_flags; 268 newtpcb->tp_lcredit = tpcb->tp_lcredit; 269 newtpcb->tp_l_tpdusize = tpcb->tp_l_tpdusize; 270 newtpcb->tp_lsuffixlen = tpcb->tp_lsuffixlen; 271 bcopy( tpcb->tp_lsuffix, newtpcb->tp_lsuffix, newtpcb->tp_lsuffixlen); 272 soreserve(so, (u_long)tpcb->tp_winsize, (u_long)tpcb->tp_winsize); 273 274 if( /* old */ tpcb->tp_ucddata) { 275 /* 276 * These data are the connect- , confirm- or disconnect- data. 277 */ 278 struct mbuf *conndata; 279 280 conndata = m_copy(tpcb->tp_ucddata, 0, (int)M_COPYALL); 281 IFDEBUG(D_CONN) 282 dump_mbuf(conndata, "conndata after mcopy"); 283 ENDDEBUG 284 newtpcb->tp_ucddata = conndata; 285 } 286 287 tpcb = newtpcb; 288 tpcb->tp_state = TP_LISTENING; 289 tpcb->tp_class = class_to_use; 290 tpcb->tp_netservice = netservice; 291 292 293 ASSERT( fname != 0 ) ; /* just checking */ 294 if ( fname ) { 295 /* 296 * tp_route_to takes its address argument in the form of an mbuf. 297 */ 298 struct mbuf *m; 299 int err; 300 301 MGET(m, M_DONTWAIT, MT_SONAME); /* mbuf type used is confusing */ 302 if (m) { 303 /* 304 * this seems a bit grotesque, but tp_route_to expects 305 * an mbuf * instead of simply a sockaddr; it calls the ll 306 * pcb_connect, which expects the name/addr in an mbuf as well. 307 * sigh. 308 */ 309 bcopy((caddr_t)fname, mtod(m, caddr_t), fname->sa_len); 310 m->m_len = fname->sa_len; 311 312 /* grot : have to say the kernel can override params in 313 * the passive open case 314 */ 315 tpcb->tp_dont_change_params = 0; 316 err = tp_route_to( m, tpcb, cons_channel); 317 m_free(m); 318 319 if (!err) 320 goto ok; 321 } 322 IFDEBUG(D_CONN) 323 printf("tp_route_to FAILED! detaching tpcb 0x%x, so 0x%x\n", 324 tpcb, so); 325 ENDDEBUG 326 (void) tp_detach(tpcb); 327 return 0; 328 } 329 ok: 330 IFDEBUG(D_TPINPUT) 331 printf("tp_newsocket returning so 0x%x, sototpcb(so) 0x%x\n", 332 so, sototpcb(so)); 333 ENDDEBUG 334 return so; 335 } 336 337 #ifndef CONS 338 tpcons_output() 339 { 340 return(0); 341 } 342 #endif !CONS 343 344 /* 345 * NAME: tp_input() 346 * 347 * CALLED FROM: 348 * net layer input routine 349 * 350 * FUNCTION and ARGUMENTS: 351 * Process an incoming TPDU (m), finding the associated tpcb if there 352 * is one. Create the appropriate type of event and call the driver. 353 * (faddr) and (laddr) are the foreign and local addresses. 354 * 355 * When tp_input() is called we KNOW that the ENTIRE TP HEADER 356 * has been m_pullup-ed. 357 * 358 * RETURN VALUE: Nada 359 * 360 * SIDE EFFECTS: 361 * When using COSNS it may affect the state of the net-level pcb 362 * 363 * NOTE: 364 * The initial value of acktime is 2 so that we will never 365 * have a 0 value for tp_peer_acktime. It gets used in the 366 * computation of the retransmission timer value, and so it 367 * mustn't be zero. 368 * 2 seems like a reasonable minimum. 369 */ 370 ProtoHook 371 tp_input(m, faddr, laddr, cons_channel, dgout_routine) 372 register struct mbuf *m; 373 struct sockaddr *faddr, *laddr; /* NSAP addresses */ 374 u_int cons_channel; 375 int (*dgout_routine)(); 376 377 { 378 register struct tp_pcb *tpcb = (struct tp_pcb *)0; 379 register struct tpdu *hdr = mtod(m, struct tpdu *); 380 struct socket *so; 381 struct tp_event e; 382 int error = 0; 383 unsigned dutype; 384 u_short dref, sref, acktime, subseq; /*VAX*/ 385 u_char preferred_class=0, class_to_use=0; 386 u_char opt, dusize, addlopt; 387 #ifdef TP_PERF_MEAS 388 u_char perf_meas=0; 389 #endif TP_PERF_MEAS 390 u_char fsufxlen; 391 u_char lsufxlen; 392 caddr_t fsufxloc=0, lsufxloc=0; 393 int tpdu_len; 394 u_int takes_data; 395 u_int fcc_present; 396 caddr_t errloc=0; 397 struct tp_conn_param tpp; 398 int tpcons_output(); 399 400 #ifdef TP_PERF_MEAS 401 GET_CUR_TIME( &e.e_time ); 402 #endif TP_PERF_MEAS 403 404 IFDEBUG(D_TPINPUT) 405 printf("tp_input(0x%x, ... 0x%x)\n", m, cons_channel); 406 ENDDEBUG 407 408 again: 409 410 tpdu_len = 0; 411 tpcb = (struct tp_pcb *)0; 412 fsufxlen = 0; 413 lsufxlen = 0; 414 addlopt = 0; 415 acktime = 2; 416 dusize = TP_DFL_TPDUSIZE; 417 sref = 0; 418 subseq = 0; 419 takes_data = FALSE; 420 fcc_present = FALSE; 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 774 bcopy(fsufxloc, tpcb->tp_fsuffix, fsufxlen); 775 (tpcb->tp_nlproto->nlp_putsufx) 776 (so->so_pcb, fsufxloc, fsufxlen, TP_FOREIGN); 777 778 #ifdef TP_PERF_MEAS 779 if( tpcb->tp_perf_on = perf_meas ) { /* assignment */ 780 /* ok, let's create an mbuf for stashing the 781 * statistics if one doesn't already exist 782 */ 783 (void) tp_setup_perf(tpcb); 784 } 785 #endif TP_PERF_MEAS 786 tpcb->tp_fref = sref; 787 788 /* We've already checked for consistency with the options 789 * set in tpp, but we couldn't set them earlier because 790 * we didn't want to change options in the LISTENING tpcb. 791 * Now we set the options in the new socket's tpcb. 792 */ 793 (void) tp_consistency( tpcb, TP_FORCE, &tpp); 794 795 if(!tpcb->tp_use_checksum) 796 IncStat(ts_csum_off); 797 if(tpcb->tp_xpd_service) 798 IncStat(ts_use_txpd); 799 if(tpcb->tp_xtd_format) 800 IncStat(ts_xtd_fmt); 801 802 /* 803 * Get the maximum transmission unit from the lower layer(s) 804 * so we can negotiate a reasonable max TPDU size. 805 */ 806 (tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb, 807 &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0); 808 tpcb->tp_peer_acktime = acktime; 809 810 /* 811 * The following kludge is used to test retransmissions and 812 * timeout during connection establishment. 813 */ 814 IFDEBUG(D_ZDREF) 815 IncStat(ts_zdebug); 816 /*tpcb->tp_fref = 0;*/ 817 ENDDEBUG 818 } 819 IncStat(ts_CR_rcvd); 820 } else if ( dutype == ER_TPDU_type ) { 821 /* 822 * ER TPDUs have to be recognized separately 823 * because they don't necessarily have a tpcb 824 * with them and we don't want err out looking for such 825 * a beast. 826 * We could put a bunch of little kludges in the 827 * next section of code so it would avoid references to tpcb 828 * if dutype == ER_TPDU_type but we don't want code for ERs to 829 * mess up code for data transfer. 830 */ 831 IncStat(ts_ER_rcvd); 832 e.ev_number = ER_TPDU; 833 e.ATTR(ER_TPDU).e_reason = (u_char)hdr->tpdu_ERreason; 834 takes_data = 1; 835 } else { 836 /* tpdu type is CC, XPD, XAK, GR, AK, DR, DC, or DT */ 837 838 /* In the next 4 checks, 839 * _tpduf is the fixed part; add 2 to get the dref bits of 840 * the fixed part (can't take the address of a bit field) 841 */ 842 if(cons_channel) { 843 #if NARGOXTWENTYFIVE > 0 844 extern struct tp_pcb *cons_chan_to_tpcb(); 845 846 tpcb = cons_chan_to_tpcb( cons_channel ); 847 /* Problem: We may have a legit 848 * error situation yet we may or may not have 849 * a correspondence between the tpcb and the vc, 850 * e.g., TP4cr--> <no dice, respond w/ DR on vc> 851 * <--- DR 852 * Now it's up to TP to look at the tpdu and do one of: 853 * confirm(dgm)(cr), confirm(circuit)(cr), reject(cr), or 854 * nothing, if the circuit is already open (any other tpdu). 855 * Sigh. 856 */ 857 858 /* I don't know about this error value */ 859 CHECK( (tpcb == (struct tp_pcb *)0) , 860 E_TP_NO_CR_ON_NC, ts_inv_dref, respond, 861 (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 862 #else 863 printf("tp_input(): X25 NOT CONFIGURED!!\n"); 864 #endif NARGOXTWENTYFIVE > 0 865 866 } else { 867 868 CHECK( ((int)dref <= 0 || dref >= N_TPREF) , 869 E_TP_MISM_REFS,ts_inv_dref, respond, 870 (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 871 CHECK( ((tpcb = tp_ref[dref].tpr_pcb ) == (struct tp_pcb *) 0 ), 872 E_TP_MISM_REFS,ts_inv_dref, respond, 873 (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 874 CHECK( (tpcb->tp_refp->tpr_state == REF_FREE), 875 E_TP_MISM_REFS,ts_inv_dref, respond, 876 (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 877 } 878 879 IFDEBUG(D_TPINPUT) 880 printf("HAVE A TPCB 2: 0x%x\n", tpcb); 881 ENDDEBUG 882 883 /* causes a DR to be sent for CC; ER for all else */ 884 CHECK( (tpcb->tp_refp->tpr_state == REF_FROZEN), 885 (dutype == CC_TPDU_type?E_TP_NO_SESSION:E_TP_MISM_REFS), 886 ts_inv_dref, respond, 887 (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 888 889 IFDEBUG(D_TPINPUT) 890 printf("state of dref %d ok, tpcb 0x%x\n", dref,tpcb); 891 ENDDEBUG 892 /* 893 * At this point the state of the dref could be 894 * FROZEN: tpr_pcb == NULL, has ( reference only) timers 895 * for example, DC may arrive after the close() has detached 896 * the tpcb (e.g., if user turned off SO_LISTEN option) 897 * OPENING : a tpcb exists but no timers yet 898 * OPEN : tpcb exists & timers are outstanding 899 */ 900 901 dusize = tpcb->tp_tpdusize; 902 903 dutype = hdr->tpdu_type << 8; /* for the switch below */ 904 905 WHILE_OPTIONS(P, hdr, tpcb->tp_xtd_format) /* { */ 906 907 #define caseof(x,y) case (((x)<<8)+(y)) 908 switch( dutype | vbptr(P)->tpv_code ) { 909 910 caseof( CC_TPDU_type, TPP_addl_opt ): 911 /* not in class 0; 1 octet */ 912 vb_getval(P, u_char, addlopt); 913 break; 914 caseof( CC_TPDU_type, TPP_tpdu_size ): 915 vb_getval(P, u_char, dusize); 916 CHECK( (dusize < TP_MIN_TPDUSIZE || dusize > 917 TP_MAX_TPDUSIZE), E_TP_INV_PVAL, ts_inv_pval, respond, 918 (1 + (caddr_t)&vbptr(P)->tpv_val - P) ) 919 IFDEBUG(D_TPINPUT) 920 printf("CC dusize 0x%x\n", dusize); 921 ENDDEBUG 922 break; 923 caseof( CC_TPDU_type, TPP_calling_sufx): 924 IFDEBUG(D_TPINPUT) 925 printf("CC calling (local) sufxlen 0x%x\n", lsufxlen); 926 ENDDEBUG 927 lsufxloc = (caddr_t) &vbptr(P)->tpv_val; 928 lsufxlen = vbptr(P)->tpv_len; 929 break; 930 caseof( CC_TPDU_type, TPP_acktime ): 931 /* class 4 only, 2 octets */ 932 vb_getval(P, u_short, acktime); 933 acktime = acktime/500; /* convert to slowtimo ticks */ 934 if( (short)acktime <=0 ) 935 acktime = 2; 936 break; 937 caseof( CC_TPDU_type, TPP_called_sufx): 938 fsufxloc = (caddr_t) &vbptr(P)->tpv_val; 939 fsufxlen = vbptr(P)->tpv_len; 940 IFDEBUG(D_TPINPUT) 941 printf("CC called (foreign) sufx len %d\n", fsufxlen); 942 ENDDEBUG 943 break; 944 945 caseof( CC_TPDU_type, TPP_checksum): 946 caseof( DR_TPDU_type, TPP_checksum): 947 caseof( DT_TPDU_type, TPP_checksum): 948 caseof( XPD_TPDU_type, TPP_checksum): 949 if( tpcb->tp_use_checksum ) { 950 CHECK( iso_check_csum(m, tpdu_len), 951 E_TP_INV_PVAL, ts_bad_csum, discard, 0) 952 } 953 break; 954 955 /* this is different from the above because in the context 956 * of concat/ sep tpdu_len might not be the same as hdr len 957 */ 958 caseof( AK_TPDU_type, TPP_checksum): 959 caseof( XAK_TPDU_type, TPP_checksum): 960 caseof( DC_TPDU_type, TPP_checksum): 961 if( tpcb->tp_use_checksum ) { 962 CHECK( iso_check_csum(m, (int)hdr->tpdu_li + 1), 963 E_TP_INV_PVAL, ts_bad_csum, discard, 0) 964 } 965 break; 966 #ifdef notdef 967 caseof( DR_TPDU_type, TPP_addl_info ): 968 /* ignore - its length and meaning are 969 * user defined and there's no way 970 * to pass this info to the user anyway 971 */ 972 break; 973 #endif notdef 974 975 caseof( AK_TPDU_type, TPP_subseq ): 976 /* used after reduction of window */ 977 vb_getval(P, u_short, subseq); 978 subseq = ntohs(subseq); 979 IFDEBUG(D_ACKRECV) 980 printf("AK Subsequence # 0x%x\n", subseq); 981 ENDDEBUG 982 break; 983 984 caseof( AK_TPDU_type, TPP_flow_cntl_conf ): 985 { 986 u_int ylwe; 987 u_short ysubseq, ycredit; 988 989 fcc_present = TRUE; 990 vb_getval(P, u_int, ylwe); 991 vb_getval(P, u_short, ysubseq); 992 vb_getval(P, u_short, ycredit); 993 ylwe = ntohl(ylwe); 994 ysubseq = ntohs(ysubseq); 995 ycredit = ntohs(ycredit); 996 IFDEBUG(D_ACKRECV) 997 printf("AK FCC lwe 0x%x, subseq 0x%x, cdt 0x%x\n", 998 ylwe, ysubseq, ycredit); 999 ENDDEBUG 1000 } 1001 break; 1002 1003 default: 1004 IFDEBUG(D_TPINPUT) 1005 printf("param ignored dutype 0x%x, code 0x%x\n", 1006 dutype, vbptr(P)->tpv_code); 1007 ENDDEBUG 1008 IFTRACE(D_TPINPUT) 1009 tptrace(TPPTmisc, "param ignored dutype code ", 1010 dutype, vbptr(P)->tpv_code ,0,0); 1011 ENDTRACE 1012 IncStat(ts_param_ignored); 1013 break; 1014 #undef caseof 1015 } 1016 /* } */ END_WHILE_OPTIONS(P) 1017 1018 /* NOTE: the variable dutype has been shifted left! */ 1019 1020 switch( hdr->tpdu_type ) { 1021 case CC_TPDU_type: 1022 /* If CC comes back with an unacceptable class 1023 * respond with a DR or ER 1024 */ 1025 1026 opt = hdr->tpdu_CCoptions; /* 1 byte */ 1027 1028 { 1029 tpp = tpcb->_tp_param; 1030 tpp.p_class = (1<<hdr->tpdu_CCclass); 1031 tpp.p_tpdusize = dusize; 1032 tpp.p_dont_change_params = 0; 1033 tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT; 1034 tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD; 1035 tpp.p_use_checksum = (addlopt & TPAO_NO_CSUM) == 0; 1036 #ifdef notdef 1037 tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC; 1038 tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD; 1039 tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC; 1040 #endif notdef 1041 1042 CHECK( 1043 tp_consistency(tpcb, TP_FORCE, &tpp) != 0, 1044 E_TP_NEGOT_FAILED, ts_negotfailed, respond, 1045 (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 1046 /* ^ more or less the location of class */ 1047 ) 1048 IFTRACE(D_CONN) 1049 tptrace(TPPTmisc, 1050 "after 1 consist class, out, tpconsout", 1051 tpcb->tp_class, dgout_routine, tpcons_output, 0 1052 ); 1053 ENDTRACE 1054 CHECK( 1055 ((class_to_use == TP_CLASS_0)&& 1056 (dgout_routine != tpcons_output)), 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 } 1062 if( ! tpcb->tp_use_checksum) 1063 IncStat(ts_csum_off); 1064 if(tpcb->tp_xpd_service) 1065 IncStat(ts_use_txpd); 1066 if(tpcb->tp_xtd_format) 1067 IncStat(ts_xtd_fmt); 1068 1069 IFTRACE(D_CONN) 1070 tptrace(TPPTmisc, "after CC class flags dusize CCclass", 1071 tpcb->tp_class, tpcb->tp_flags, tpcb->tp_tpdusize, 1072 hdr->tpdu_CCclass); 1073 ENDTRACE 1074 1075 /* 1076 * Get the maximum transmission unit from the lower layer(s) 1077 * so we can decide how large a TPDU size to negotiate. 1078 * It would be nice if the arguments to this 1079 * were more reasonable. 1080 */ 1081 (tpcb->tp_nlproto->nlp_mtu)(tpcb->tp_sock, tpcb->tp_sock->so_pcb, 1082 &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0); 1083 1084 #ifdef CONS 1085 /* Could be that this CC came in on a NEW vc, in which case 1086 * we have to confirm it. 1087 */ 1088 if( cons_channel ) 1089 cons_netcmd( CONN_CONFIRM, tpcb->tp_npcb, cons_channel, 1090 tpcb->tp_class == TP_CLASS_4); 1091 #endif CONS 1092 1093 tpcb->tp_peer_acktime = acktime; 1094 1095 /* if called or calling suffices appeared on the CC, 1096 * they'd better jive with what's in the pcb 1097 */ 1098 if( fsufxlen ) { 1099 CHECK( ((tpcb->tp_fsuffixlen != fsufxlen) || 1100 bcmp(fsufxloc, tpcb->tp_fsuffix, fsufxlen)), 1101 E_TP_INV_PVAL,ts_inv_sufx, respond, 1102 (1+fsufxloc - (caddr_t)hdr)) 1103 } 1104 if( lsufxlen ) { 1105 CHECK( ((tpcb->tp_lsuffixlen != lsufxlen) || 1106 bcmp(lsufxloc, tpcb->tp_lsuffix, lsufxlen)), 1107 E_TP_INV_PVAL,ts_inv_sufx, respond, 1108 (1+lsufxloc - (caddr_t)hdr)) 1109 } 1110 1111 #ifdef notdef 1112 e.ATTR(CC_TPDU).e_sref = (u_short)hdr->tpdu_CCsref; 1113 #else 1114 e.ATTR(CC_TPDU).e_sref = sref; 1115 #endif notdef 1116 e.ATTR(CC_TPDU).e_cdt = hdr->tpdu_CCcdt; 1117 takes_data = TRUE; 1118 e.ev_number = CC_TPDU; 1119 IncStat(ts_CC_rcvd); 1120 break; 1121 1122 case DC_TPDU_type: 1123 #ifdef notdef 1124 if (hdr->tpdu_DCsref != tpcb->tp_fref) 1125 printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n", 1126 hdr->tpdu_DCsref, tpcb->tp_fref); 1127 #else 1128 if (sref != tpcb->tp_fref) 1129 printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n", 1130 sref, tpcb->tp_fref); 1131 #endif notdef 1132 1133 #ifdef notdef 1134 CHECK( (hdr->tpdu_DCsref != tpcb->tp_fref), 1135 E_TP_MISM_REFS, ts_inv_sufx, respond, 1136 (1 + (caddr_t)&hdr->tpdu_DCsref - (caddr_t)hdr)) 1137 #else 1138 CHECK( (sref != tpcb->tp_fref), 1139 E_TP_MISM_REFS, ts_inv_sufx, respond, 1140 (1 + (caddr_t)&hdr->tpdu_DCsref - (caddr_t)hdr)) 1141 #endif notdef 1142 e.ev_number = DC_TPDU; 1143 IncStat(ts_DC_rcvd); 1144 break; 1145 1146 case DR_TPDU_type: 1147 IFTRACE(D_TPINPUT) 1148 tptrace(TPPTmisc, "DR recvd", hdr->tpdu_DRreason, 0, 0, 0); 1149 ENDTRACE 1150 #ifdef vax 1151 if(sref != tpcb->tp_fref) 1152 printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n", 1153 sref, tpcb->tp_fref); 1154 1155 CHECK( (sref != tpcb->tp_fref), 1156 E_TP_MISM_REFS,ts_inv_sufx, respond, 1157 (1 + (caddr_t)&hdr->tpdu_DRsref - (caddr_t)hdr)) 1158 1159 e.ATTR(DR_TPDU).e_reason = hdr->tpdu_DRreason; 1160 e.ATTR(DR_TPDU).e_sref = (u_short)sref; 1161 #else 1162 if(hdr->tpdu_DRsref != tpcb->tp_fref) 1163 printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n", 1164 hdr->tpdu_DRsref, tpcb->tp_fref); 1165 1166 CHECK( (hdr->tpdu_DRsref != tpcb->tp_fref), 1167 E_TP_MISM_REFS,ts_inv_sufx, respond, 1168 (1 + (caddr_t)&hdr->tpdu_DRsref - (caddr_t)hdr)) 1169 1170 e.ATTR(DR_TPDU).e_reason = 1171 hdr->tpdu_DRreason; 1172 e.ATTR(DR_TPDU).e_sref = (u_short)hdr->tpdu_DRsref; 1173 #endif vax 1174 takes_data = TRUE; 1175 e.ev_number = DR_TPDU; 1176 IncStat(ts_DR_rcvd); 1177 break; 1178 1179 case ER_TPDU_type: 1180 IFTRACE(D_TPINPUT) 1181 tptrace(TPPTmisc, "ER recvd", hdr->tpdu_ERreason,0,0,0); 1182 ENDTRACE 1183 e.ev_number = ER_TPDU; 1184 e.ATTR(ER_TPDU).e_reason = hdr->tpdu_ERreason; 1185 IncStat(ts_ER_rcvd); 1186 break; 1187 1188 case AK_TPDU_type: 1189 1190 e.ATTR(AK_TPDU).e_subseq = subseq; 1191 e.ATTR(AK_TPDU).e_fcc_present = fcc_present; 1192 1193 if (tpcb->tp_xtd_format) { 1194 #ifdef BYTE_ORDER 1195 union seq_type seqeotX; 1196 1197 seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 1198 e.ATTR(AK_TPDU).e_seq = seqeotX.s_seq; 1199 e.ATTR(AK_TPDU).e_cdt = ntohs(hdr->tpdu_AKcdtX); 1200 #else 1201 e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdtX; 1202 e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseqX; 1203 #endif BYTE_ORDER 1204 } else { 1205 e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdt; 1206 e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseq; 1207 } 1208 IFTRACE(D_TPINPUT) 1209 tptrace(TPPTmisc, "AK recvd seq cdt subseq fcc_pres", 1210 e.ATTR(AK_TPDU).e_seq, e.ATTR(AK_TPDU).e_cdt, 1211 subseq, fcc_present); 1212 ENDTRACE 1213 1214 e.ev_number = AK_TPDU; 1215 IncStat(ts_AK_rcvd); 1216 IncPStat(tpcb, tps_AK_rcvd); 1217 break; 1218 1219 case XAK_TPDU_type: 1220 if (tpcb->tp_xtd_format) { 1221 #ifdef BYTE_ORDER 1222 union seq_type seqeotX; 1223 1224 seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 1225 e.ATTR(XAK_TPDU).e_seq = seqeotX.s_seq; 1226 #else 1227 e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseqX; 1228 #endif BYTE_ORDER 1229 } else { 1230 e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseq; 1231 } 1232 e.ev_number = XAK_TPDU; 1233 IncStat(ts_XAK_rcvd); 1234 IncPStat(tpcb, tps_XAK_rcvd); 1235 break; 1236 1237 case XPD_TPDU_type: 1238 if (tpcb->tp_xtd_format) { 1239 #ifdef BYTE_ORDER 1240 union seq_type seqeotX; 1241 1242 seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 1243 e.ATTR(XPD_TPDU).e_seq = seqeotX.s_seq; 1244 #else 1245 e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseqX; 1246 #endif BYTE_ORDER 1247 } else { 1248 e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseq; 1249 } 1250 takes_data = TRUE; 1251 e.ev_number = XPD_TPDU; 1252 IncStat(ts_XPD_rcvd); 1253 IncPStat(tpcb, tps_XPD_rcvd); 1254 break; 1255 1256 case DT_TPDU_type: 1257 { /* the y option will cause occasional packets to be dropped. 1258 * A little crude but it works. 1259 */ 1260 1261 IFDEBUG(D_DROP) 1262 if(time.tv_usec & 0x4 && hdr->tpdu_DTseq & 0x1) { 1263 IncStat(ts_ydebug); 1264 goto discard; 1265 } 1266 ENDDEBUG 1267 } 1268 if (tpcb->tp_class == TP_CLASS_0) { 1269 e.ATTR(DT_TPDU).e_seq = 0; /* actually don't care */ 1270 e.ATTR(DT_TPDU).e_eot = (((struct tp0du *)hdr)->tp0du_eot); 1271 } else if (tpcb->tp_xtd_format) { 1272 #ifdef BYTE_ORDER 1273 union seq_type seqeotX; 1274 1275 seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); 1276 e.ATTR(DT_TPDU).e_seq = seqeotX.s_seq; 1277 e.ATTR(DT_TPDU).e_eot = seqeotX.s_eot; 1278 #else 1279 e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseqX; 1280 e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeotX; 1281 #endif BYTE_ORDER 1282 } else { 1283 e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseq; 1284 e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeot; 1285 } 1286 if(e.ATTR(DT_TPDU).e_eot) 1287 IncStat(ts_eot_input); 1288 takes_data = TRUE; 1289 e.ev_number = DT_TPDU; 1290 IncStat(ts_DT_rcvd); 1291 IncPStat(tpcb, tps_DT_rcvd); 1292 break; 1293 1294 case GR_TPDU_type: 1295 tp_indicate(T_DISCONNECT, tpcb, ECONNABORTED); 1296 /* drop through */ 1297 default: 1298 /* this should NEVER happen because there is a 1299 * check for dutype well above here 1300 */ 1301 error = E_TP_INV_TPDU; /* causes an ER */ 1302 IFDEBUG(D_TPINPUT) 1303 printf("INVALID dutype 0x%x\n", hdr->tpdu_type); 1304 ENDDEBUG 1305 IncStat(ts_inv_dutype); 1306 goto respond; 1307 } 1308 } 1309 1310 /* peel off the tp header; 1311 * remember that the du_li doesn't count itself. 1312 * This may leave us w/ an empty mbuf at the front of a chain. 1313 * We can't just throw away the empty mbuf because hdr still points 1314 * into the mbuf's data area and we're still using hdr (the tpdu header) 1315 */ 1316 m->m_len -= ((int)hdr->tpdu_li + 1); 1317 m->m_data += ((int)hdr->tpdu_li + 1); 1318 1319 if (takes_data) { 1320 int max = tpdu_info[ hdr->tpdu_type ] [TP_MAX_DATA_INDEX]; 1321 int datalen = tpdu_len - hdr->tpdu_li - 1, mbtype = MT_DATA; 1322 struct tp_control_hdr c_hdr; 1323 struct mbuf *n; 1324 1325 CHECK( (max && datalen > max), E_TP_LENGTH_INVAL, 1326 ts_inv_length, respond, (max + hdr->tpdu_li + 1) ); 1327 switch( hdr->tpdu_type ) { 1328 1329 case CR_TPDU_type: 1330 c_hdr.cmsg_type = TPOPT_CONN_DATA; 1331 goto make_control_msg; 1332 1333 case CC_TPDU_type: 1334 c_hdr.cmsg_type = TPOPT_CFRM_DATA; 1335 goto make_control_msg; 1336 1337 case DR_TPDU_type: 1338 c_hdr.cmsg_type = TPOPT_DISC_DATA; 1339 make_control_msg: 1340 c_hdr.cmsg_level = SOL_TRANSPORT; 1341 mbtype = MT_CONTROL; 1342 if (datalen > 0) { 1343 datalen += sizeof(c_hdr); 1344 m->m_len += sizeof(c_hdr); 1345 m->m_data -= sizeof(c_hdr); 1346 c_hdr.cmsg_len = datalen; 1347 bcopy((caddr_t)&c_hdr, mtod(m, caddr_t), 1348 sizeof(c_hdr)); 1349 } 1350 /* FALLTHROUGH */ 1351 1352 case XPD_TPDU_type: 1353 if (mbtype != MT_CONTROL) 1354 mbtype = MT_OOBDATA; 1355 m->m_flags |= M_EOR; 1356 /* FALLTHROUGH */ 1357 1358 case DT_TPDU_type: 1359 for (n = m; n; n = n->m_next) { 1360 MCHTYPE(n, mbtype); 1361 } 1362 e.ATTR(DT_TPDU).e_datalen = datalen; 1363 e.ATTR(DT_TPDU).e_data = m; 1364 break; 1365 1366 default: 1367 printf( 1368 "ERROR in tp_input! hdr->tpdu_type 0x%x takes_data 0x%x m 0x%x\n", 1369 hdr->tpdu_type, takes_data, m); 1370 break; 1371 } 1372 /* prevent m_freem() after tp_driver() from throwing it all away */ 1373 m = MNULL; 1374 } 1375 1376 IncStat(ts_tpdu_rcvd); 1377 1378 IFDEBUG(D_TPINPUT) 1379 printf( "tp_input: before driver, state 0x%x event 0x%x m 0x%x", 1380 tpcb->tp_state, e.ev_number, m ); 1381 printf(" e.e_data 0x%x\n", e.ATTR(DT_TPDU).e_data); 1382 printf("takes_data 0x%x m_len 0x%x, tpdu_len 0x%x\n", 1383 takes_data, (m==MNULL)?0:m->m_len, tpdu_len); 1384 ENDDEBUG 1385 1386 if( tpcb->tp_decbit != 0 ) /* unsigned 4 bits */ 1387 tpcb->tp_decbit --; 1388 1389 error = tp_driver(tpcb, &e); 1390 1391 ASSERT(tpcb != (struct tp_pcb *)0); 1392 ASSERT(tpcb->tp_sock != (struct socket *)0); 1393 if( tpcb->tp_sock->so_error == 0 ) 1394 tpcb->tp_sock->so_error = error; 1395 1396 /* Kludge to keep the state tables under control (adding 1397 * data on connect & disconnect & freeing the mbuf containing 1398 * the data would have exploded the tables and made a big mess ). 1399 */ 1400 switch(e.ev_number) { 1401 case CC_TPDU: 1402 case DR_TPDU: 1403 case CR_TPDU: 1404 m = e.ATTR(CC_TPDU).e_data; /* same field for all three dutypes */ 1405 IFDEBUG(D_TPINPUT) 1406 printf("after driver, restoring m to 0x%x, takes_data 0x%x\n", 1407 m, takes_data); 1408 ENDDEBUG 1409 break; 1410 default: 1411 break; 1412 } 1413 /* Concatenated sequences are terminated by any tpdu that 1414 * carries data: CR, CC, DT, XPD, DR. 1415 * All other tpdu types may be concatenated: AK, XAK, DC, ER. 1416 */ 1417 1418 separate: 1419 if ( takes_data == 0 ) { 1420 ASSERT( m != MNULL ); 1421 /* 1422 * we already peeled off the prev. tp header so 1423 * we can just pull up some more and repeat 1424 */ 1425 1426 if( m = tp_inputprep(m) ) { 1427 IFDEBUG(D_TPINPUT) 1428 hdr = mtod(m, struct tpdu *); 1429 printf("tp_input @ separate: hdr 0x%x size %d m 0x%x\n", 1430 hdr, (int) hdr->tpdu_li + 1, m); 1431 dump_mbuf(m, "tp_input after driver, at separate"); 1432 ENDDEBUG 1433 1434 IncStat(ts_concat_rcvd); 1435 goto again; 1436 } 1437 } 1438 if ( m != MNULL ) { 1439 IFDEBUG(D_TPINPUT) 1440 printf("tp_input : m_freem(0x%x)\n", m); 1441 ENDDEBUG 1442 m_freem(m); 1443 IFDEBUG(D_TPINPUT) 1444 printf("tp_input : after m_freem 0x%x\n", m); 1445 ENDDEBUG 1446 } 1447 return (ProtoHook) tpcb; 1448 1449 discard: 1450 /* class 4: drop the tpdu */ 1451 /* class 2,0: Should drop the net connection, if you can figure out 1452 * to which connection it applies 1453 */ 1454 IFDEBUG(D_TPINPUT) 1455 printf("tp_input DISCARD\n"); 1456 ENDDEBUG 1457 IFTRACE(D_TPINPUT) 1458 tptrace(TPPTmisc, "tp_input DISCARD m", m,0,0,0); 1459 ENDTRACE 1460 m_freem(m); 1461 IncStat(ts_recv_drop); 1462 return (ProtoHook)0; 1463 1464 respond: 1465 IFDEBUG(D_ERROR_EMIT) 1466 printf("RESPOND: error 0x%x, errloc 0x%x\n", error, errloc); 1467 ENDDEBUG 1468 IFTRACE(D_TPINPUT) 1469 tptrace(TPPTmisc, "tp_input RESPOND m error sref", m,error,sref,0); 1470 ENDTRACE 1471 if( sref == 0 ) 1472 goto discard; 1473 (void) tp_error_emit(error, (u_long)sref, (struct sockaddr_iso *)faddr, 1474 (struct sockaddr_iso *)laddr, m, (int)errloc, tpcb, 1475 (int)cons_channel, dgout_routine); 1476 IFDEBUG(D_ERROR_EMIT) 1477 printf("tp_input after error_emit\n"); 1478 ENDDEBUG 1479 1480 #ifdef lint 1481 printf("",sref,opt); 1482 #endif lint 1483 IncStat(ts_recv_drop); 1484 return (ProtoHook)0; 1485 } 1486 1487 1488 /* 1489 * NAME: tp_headersize() 1490 * 1491 * CALLED FROM: 1492 * tp_emit() and tp_sbsend() 1493 * TP needs to know the header size so it can figure out how 1494 * much data to put in each tpdu. 1495 * 1496 * FUNCTION, ARGUMENTS, and RETURN VALUE: 1497 * For a given connection, represented by (tpcb), and 1498 * tpdu type (dutype), return the size of a tp header. 1499 * 1500 * RETURNS: the expected size of the heade in bytesr 1501 * 1502 * SIDE EFFECTS: 1503 * 1504 * NOTES: It would be nice if it got the network header size as well. 1505 */ 1506 int 1507 tp_headersize(dutype, tpcb) 1508 int dutype; 1509 struct tp_pcb *tpcb; 1510 { 1511 register int size = 0; 1512 1513 IFTRACE(D_CONN) 1514 tptrace(TPPTmisc, "tp_headersize dutype class xtd_format", 1515 dutype, tpcb->tp_class, tpcb->tp_xtd_format, 0); 1516 ENDTRACE 1517 if( !( (tpcb->tp_class == TP_CLASS_0) || 1518 (tpcb->tp_class == TP_CLASS_4) || 1519 (dutype == DR_TPDU_type) || 1520 (dutype == CR_TPDU_type) )) { 1521 printf("tp_headersize:dutype 0x%x, class 0x%x", 1522 dutype, tpcb->tp_class); 1523 /* TODO: identify this and GET RID OF IT */ 1524 } 1525 ASSERT( (tpcb->tp_class == TP_CLASS_0) || 1526 (tpcb->tp_class == TP_CLASS_4) || 1527 (dutype == DR_TPDU_type) || 1528 (dutype == CR_TPDU_type) ); 1529 1530 if( tpcb->tp_class == TP_CLASS_0 ) { 1531 size = tpdu_info[ dutype ] [TP_LEN_CLASS_0_INDEX]; 1532 } else { 1533 size = tpdu_info[ dutype ] [tpcb->tp_xtd_format]; 1534 } 1535 return size; 1536 /* caller must get network level header size separately */ 1537 } 1538