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