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