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.17 (Berkeley) 04/30/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 (lsufxlen == t->tp_lsuffixlen && 645 bcmp(lsufxloc, t->tp_lsuffix, lsufxlen) == 0 && 646 laddr->sa_family == t->tp_nlproto->nlp_afamily) 647 break; 648 CHECK(t == 0, E_TP_NO_SESSION, ts_inv_sufx, respond, 649 (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 650 /* _tpduf is the fixed part; add 2 to get the dref bits of 651 * the fixed part (can't take the address of a bit field) 652 */ 653 IFDEBUG(D_TPINPUT) 654 printf("checking if dup CR\n"); 655 ENDDEBUG 656 check_duplicate_cr: 657 tpcb = t; 658 for (t = tpcb->tp_next; t != tpcb; t = t->tp_next) { 659 if (sref != t->tp_fref) 660 continue; 661 if ((*tpcb->tp_nlproto->nlp_cmpnetaddr)( 662 t->tp_npcb, faddr, TP_FOREIGN)) { 663 IFDEBUG(D_TPINPUT) 664 printf("duplicate CR discarded\n"); 665 ENDDEBUG 666 goto discard; 667 } 668 } 669 IFTRACE(D_TPINPUT) 670 tptrace(TPPTmisc, "tp_input: tpcb *lsufxloc tpstate", 671 tpcb, *lsufxloc, tpcb->tp_state, 0); 672 ENDTRACE 673 } 674 675 /* 676 * WE HAVE A TPCB 677 * already know that the classes in the CR match at least 678 * one class implemented, but we don't know yet if they 679 * include any classes permitted by this server. 680 */ 681 682 IFDEBUG(D_TPINPUT) 683 printf("HAVE A TPCB 1: 0x%x\n", tpcb); 684 ENDDEBUG 685 IFDEBUG(D_CONN) 686 printf( 687 "CR: bef CHKS: flags 0x%x class_to_use 0x%x alt 0x%x opt 0x%x tp_class 0x%x\n", 688 tpcb->tp_flags, class_to_use, alt_classes, opt, tpcb->tp_class); 689 ENDDEBUG 690 /* tpcb->tp_class doesn't include any classes not implemented */ 691 class_to_use = (preferred_class & tpcb->tp_class); 692 if( (class_to_use = preferred_class & tpcb->tp_class) == 0 ) 693 class_to_use = alt_classes & tpcb->tp_class; 694 695 class_to_use = 1 << tp_mask_to_num(class_to_use); 696 697 { 698 tpp = tpcb->_tp_param; 699 tpp.p_class = class_to_use; 700 tpp.p_tpdusize = dusize; 701 tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT; 702 tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD; 703 tpp.p_use_checksum = (tpp.p_class == TP_CLASS_0)?0: 704 (addlopt & TPAO_NO_CSUM) == 0; 705 tpp.p_version = version; 706 #ifdef notdef 707 tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC; 708 tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD; 709 tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC; 710 #endif notdef 711 712 CHECK( 713 tp_consistency(tpcb, 0 /* not force or strict */, &tpp) != 0, 714 E_TP_NEGOT_FAILED, ts_negotfailed, respond, 715 (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 716 /* ^ more or less the location of class */ 717 ) 718 } 719 IFTRACE(D_CONN) 720 tptrace(TPPTmisc, 721 "after 1 consist class_to_use class, out, tpconsout", 722 class_to_use, 723 tpcb->tp_class, dgout_routine, tpcons_output 724 ); 725 ENDTRACE 726 CHECK( 727 ((class_to_use == TP_CLASS_0)&&(dgout_routine != tpcons_output)), 728 E_TP_NEGOT_FAILED, ts_negotfailed, respond, 729 (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 730 /* ^ more or less the location of class */ 731 ) 732 IFDEBUG(D_CONN) 733 printf("CR: after CRCCCHECKS: tpcb 0x%x, flags 0x%x\n", 734 tpcb, tpcb->tp_flags); 735 ENDDEBUG 736 takes_data = TRUE; 737 e.ATTR(CR_TPDU).e_cdt = hdr->tpdu_CRcdt; 738 e.ev_number = CR_TPDU; 739 740 so = tpcb->tp_sock; 741 if (so->so_options & SO_ACCEPTCONN) { 742 struct tp_pcb *parent_tpcb = tpcb; 743 /* 744 * Create a socket, tpcb, ll pcb, etc. 745 * for this newborn connection, and fill in all the values. 746 */ 747 IFDEBUG(D_CONN) 748 printf("abt to call tp_newsocket(0x%x, 0x%x, 0x%x, 0x%x)\n", 749 so, laddr, faddr, cons_channel); 750 ENDDEBUG 751 if( (so = 752 tp_newsocket(so, faddr, cons_channel, 753 class_to_use, 754 ((tpcb->tp_netservice == IN_CLNS) ? IN_CLNS : 755 (dgout_routine == tpcons_output)?ISO_CONS:ISO_CLNS)) 756 ) == (struct socket *)0 ) { 757 /* note - even if netservice is IN_CLNS, as far as 758 * the tp entity is concerned, the only differences 759 * are CO vs CL 760 */ 761 IFDEBUG(D_CONN) 762 printf("tp_newsocket returns 0\n"); 763 ENDDEBUG 764 goto discard; 765 } 766 tpcb = sototpcb(so); 767 insque(tpcb, parent_tpcb); 768 769 /* 770 * Stash the addresses in the net level pcb 771 * kind of like a pcbconnect() but don't need 772 * or want all those checks. 773 */ 774 (tpcb->tp_nlproto->nlp_putnetaddr)(so->so_pcb, faddr, TP_FOREIGN); 775 (tpcb->tp_nlproto->nlp_putnetaddr)(so->so_pcb, laddr, TP_LOCAL); 776 777 /* stash the f suffix in the new tpcb */ 778 bcopy(fsufxloc, tpcb->tp_fsuffix, fsufxlen); 779 /* l suffix is already there, unless this is an intercept case */ 780 if (intercepted) 781 bcopy(lsufxloc, tpcb->tp_lsuffix, lsufxlen); 782 (tpcb->tp_nlproto->nlp_putsufx) 783 (so->so_pcb, fsufxloc, fsufxlen, TP_FOREIGN); 784 (tpcb->tp_nlproto->nlp_putsufx) 785 (so->so_pcb, lsufxloc, lsufxlen, TP_LOCAL); 786 #ifdef TP_PERF_MEAS 787 if( tpcb->tp_perf_on = perf_meas ) { /* assignment */ 788 /* ok, let's create an mbuf for stashing the 789 * statistics if one doesn't already exist 790 */ 791 (void) tp_setup_perf(tpcb); 792 } 793 #endif TP_PERF_MEAS 794 tpcb->tp_fref = sref; 795 796 /* We've already checked for consistency with the options 797 * set in tpp, but we couldn't set them earlier because 798 * we didn't want to change options in the LISTENING tpcb. 799 * Now we set the options in the new socket's tpcb. 800 */ 801 (void) tp_consistency( tpcb, TP_FORCE, &tpp); 802 803 if(!tpcb->tp_use_checksum) 804 IncStat(ts_csum_off); 805 if(tpcb->tp_xpd_service) 806 IncStat(ts_use_txpd); 807 if(tpcb->tp_xtd_format) 808 IncStat(ts_xtd_fmt); 809 810 /* 811 * Get the maximum transmission unit from the lower layer(s) 812 * so we can negotiate a reasonable max TPDU size. 813 */ 814 (tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb, 815 &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0); 816 tpcb->tp_peer_acktime = acktime; 817 818 /* 819 * The following kludge is used to test retransmissions and 820 * timeout during connection establishment. 821 */ 822 IFDEBUG(D_ZDREF) 823 IncStat(ts_zdebug); 824 /*tpcb->tp_fref = 0;*/ 825 ENDDEBUG 826 } 827 IncStat(ts_CR_rcvd); 828 if (!tpcb->tp_cebit_off) { 829 tpcb->tp_win_recv = tp_start_win << 8; 830 tpcb->tp_cong_sample.cs_size = 0; 831 LOCAL_CREDIT(tpcb); 832 CONG_INIT_SAMPLE(tpcb); 833 CONG_UPDATE_SAMPLE(tpcb, ce_bit); 834 } 835 tpcb->tp_ackrcvd = 0; 836 } else if ( dutype == ER_TPDU_type ) { 837 /* 838 * ER TPDUs have to be recognized separately 839 * because they don't necessarily have a tpcb 840 * with them and we don't want err out looking for such 841 * a beast. 842 * We could put a bunch of little kludges in the 843 * next section of code so it would avoid references to tpcb 844 * if dutype == ER_TPDU_type but we don't want code for ERs to 845 * mess up code for data transfer. 846 */ 847 IncStat(ts_ER_rcvd); 848 e.ev_number = ER_TPDU; 849 e.ATTR(ER_TPDU).e_reason = (u_char)hdr->tpdu_ERreason; 850 takes_data = FALSE; 851 } else { 852 /* tpdu type is CC, XPD, XAK, GR, AK, DR, DC, or DT */ 853 854 /* In the next 4 checks, 855 * _tpduf is the fixed part; add 2 to get the dref bits of 856 * the fixed part (can't take the address of a bit field) 857 */ 858 #ifdef old_history 859 if(cons_channel) { 860 #ifdef NARGOXTWENTYFIVE 861 extern struct tp_pcb *cons_chan_to_tpcb(); 862 863 tpcb = cons_chan_to_tpcb( cons_channel ); 864 /* Problem: We may have a legit 865 * error situation yet we may or may not have 866 * a correspondence between the tpcb and the vc, 867 * e.g., TP4cr--> <no dice, respond w/ DR on vc> 868 * <--- DR 869 * Now it's up to TP to look at the tpdu and do one of: 870 * confirm(dgm)(cr), confirm(circuit)(cr), reject(cr), or 871 * nothing, if the circuit is already open (any other tpdu). 872 * Sigh. 873 */ 874 875 /* I don't know about this error value */ 876 CHECK( (tpcb == (struct tp_pcb *)0) , 877 E_TP_NO_CR_ON_NC, ts_inv_dref, respond, 878 (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 879 #else 880 printf("tp_input(): X25 NOT CONFIGURED!!\n"); 881 #endif 882 } else 883 /* we've now made the error reporting thing check for 884 multiple channels and not close out if more than 885 one in use */ 886 #endif old_history 887 { 888 889 CHECK( ((int)dref <= 0 || dref >= N_TPREF) , 890 E_TP_MISM_REFS,ts_inv_dref, nonx_dref, 891 (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 892 CHECK( ((tpcb = tp_ref[dref].tpr_pcb ) == (struct tp_pcb *) 0 ), 893 E_TP_MISM_REFS,ts_inv_dref, nonx_dref, 894 (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 895 CHECK( (tpcb->tp_refp->tpr_state == REF_FREE), 896 E_TP_MISM_REFS,ts_inv_dref, nonx_dref, 897 (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 898 } 899 900 IFDEBUG(D_TPINPUT) 901 printf("HAVE A TPCB 2: 0x%x\n", tpcb); 902 ENDDEBUG 903 904 /* causes a DR to be sent for CC; ER for all else */ 905 CHECK( (tpcb->tp_refp->tpr_state == REF_FROZEN), 906 (dutype == CC_TPDU_type?E_TP_NO_SESSION:E_TP_MISM_REFS), 907 ts_inv_dref, respond, 908 (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) 909 910 IFDEBUG(D_TPINPUT) 911 printf("state of dref %d ok, tpcb 0x%x\n", dref,tpcb); 912 ENDDEBUG 913 /* 914 * At this point the state of the dref could be 915 * FROZEN: tpr_pcb == NULL, has ( reference only) timers 916 * for example, DC may arrive after the close() has detached 917 * the tpcb (e.g., if user turned off SO_LISTEN option) 918 * OPENING : a tpcb exists but no timers yet 919 * OPEN : tpcb exists & timers are outstanding 920 */ 921 922 if (!tpcb->tp_cebit_off) 923 CONG_UPDATE_SAMPLE(tpcb, ce_bit); 924 925 dusize = tpcb->tp_tpdusize; 926 927 dutype = hdr->tpdu_type << 8; /* for the switch below */ 928 929 WHILE_OPTIONS(P, hdr, tpcb->tp_xtd_format) /* { */ 930 931 #define caseof(x,y) case (((x)<<8)+(y)) 932 switch( dutype | vbptr(P)->tpv_code ) { 933 934 caseof( CC_TPDU_type, TPP_addl_opt ): 935 /* not in class 0; 1 octet */ 936 vb_getval(P, u_char, addlopt); 937 break; 938 caseof( CC_TPDU_type, TPP_tpdu_size ): 939 { 940 u_char odusize = dusize; 941 vb_getval(P, u_char, dusize); 942 CHECK( (dusize < TP_MIN_TPDUSIZE || 943 dusize > TP_MAX_TPDUSIZE || dusize > odusize), 944 E_TP_INV_PVAL, ts_inv_pval, respond, 945 (1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) ) 946 IFDEBUG(D_TPINPUT) 947 printf("CC dusize 0x%x\n", dusize); 948 ENDDEBUG 949 } 950 break; 951 caseof( CC_TPDU_type, TPP_calling_sufx): 952 IFDEBUG(D_TPINPUT) 953 printf("CC calling (local) sufxlen 0x%x\n", lsufxlen); 954 ENDDEBUG 955 lsufxloc = (caddr_t) &vbptr(P)->tpv_val; 956 lsufxlen = vbptr(P)->tpv_len; 957 break; 958 caseof( CC_TPDU_type, TPP_acktime ): 959 /* class 4 only, 2 octets */ 960 vb_getval(P, u_short, acktime); 961 acktime = ntohs(acktime); 962 acktime = acktime/500; /* convert to slowtimo ticks */ 963 if( (short)acktime <=0 ) 964 acktime = 2; 965 break; 966 caseof( CC_TPDU_type, TPP_called_sufx): 967 fsufxloc = (caddr_t) &vbptr(P)->tpv_val; 968 fsufxlen = vbptr(P)->tpv_len; 969 IFDEBUG(D_TPINPUT) 970 printf("CC called (foreign) sufx len %d\n", fsufxlen); 971 ENDDEBUG 972 break; 973 974 caseof( CC_TPDU_type, TPP_checksum): 975 caseof( DR_TPDU_type, TPP_checksum): 976 caseof( DT_TPDU_type, TPP_checksum): 977 caseof( XPD_TPDU_type, TPP_checksum): 978 if( tpcb->tp_use_checksum ) { 979 CHECK( iso_check_csum(m, tpdu_len), 980 E_TP_INV_PVAL, ts_bad_csum, discard, 0) 981 } 982 break; 983 984 /* this is different from the above because in the context 985 * of concat/ sep tpdu_len might not be the same as hdr len 986 */ 987 caseof( AK_TPDU_type, TPP_checksum): 988 caseof( XAK_TPDU_type, TPP_checksum): 989 caseof( DC_TPDU_type, TPP_checksum): 990 if( tpcb->tp_use_checksum ) { 991 CHECK( iso_check_csum(m, (int)hdr->tpdu_li + 1), 992 E_TP_INV_PVAL, ts_bad_csum, discard, 0) 993 } 994 break; 995 #ifdef notdef 996 caseof( DR_TPDU_type, TPP_addl_info ): 997 /* ignore - its length and meaning are 998 * user defined and there's no way 999 * to pass this info to the user anyway 1000 */ 1001 break; 1002 #endif notdef 1003 1004 caseof( AK_TPDU_type, TPP_subseq ): 1005 /* used after reduction of window */ 1006 vb_getval(P, u_short, subseq); 1007 subseq = ntohs(subseq); 1008 IFDEBUG(D_ACKRECV) 1009 printf("AK Subsequence # 0x%x\n", subseq); 1010 ENDDEBUG 1011 break; 1012 1013 caseof( AK_TPDU_type, TPP_flow_cntl_conf ): 1014 { 1015 u_int ylwe; 1016 u_short ysubseq, ycredit; 1017 1018 fcc_present = TRUE; 1019 vb_getval(P, u_int, ylwe); 1020 vb_getval(P, u_short, ysubseq); 1021 vb_getval(P, u_short, ycredit); 1022 ylwe = ntohl(ylwe); 1023 ysubseq = ntohs(ysubseq); 1024 ycredit = ntohs(ycredit); 1025 IFDEBUG(D_ACKRECV) 1026 printf("AK FCC lwe 0x%x, subseq 0x%x, cdt 0x%x\n", 1027 ylwe, ysubseq, ycredit); 1028 ENDDEBUG 1029 } 1030 break; 1031 1032 default: 1033 IFDEBUG(D_TPINPUT) 1034 printf("param ignored dutype 0x%x, code 0x%x\n", 1035 dutype, vbptr(P)->tpv_code); 1036 ENDDEBUG 1037 IFTRACE(D_TPINPUT) 1038 tptrace(TPPTmisc, "param ignored dutype code ", 1039 dutype, vbptr(P)->tpv_code ,0,0); 1040 ENDTRACE 1041 IncStat(ts_param_ignored); 1042 break; 1043 #undef caseof 1044 } 1045 /* } */ END_WHILE_OPTIONS(P) 1046 1047 /* NOTE: the variable dutype has been shifted left! */ 1048 1049 switch( hdr->tpdu_type ) { 1050 case CC_TPDU_type: 1051 /* If CC comes back with an unacceptable class 1052 * respond with a DR or ER 1053 */ 1054 1055 opt = hdr->tpdu_CCoptions; /* 1 byte */ 1056 1057 { 1058 tpp = tpcb->_tp_param; 1059 tpp.p_class = (1<<hdr->tpdu_CCclass); 1060 tpp.p_tpdusize = dusize; 1061 tpp.p_dont_change_params = 0; 1062 tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT; 1063 tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD; 1064 tpp.p_use_checksum = (addlopt & TPAO_NO_CSUM) == 0; 1065 #ifdef notdef 1066 tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC; 1067 tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD; 1068 tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC; 1069 #endif notdef 1070 1071 CHECK( 1072 tp_consistency(tpcb, TP_FORCE, &tpp) != 0, 1073 E_TP_NEGOT_FAILED, ts_negotfailed, respond, 1074 (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 1075 /* ^ more or less the location of class */ 1076 ) 1077 IFTRACE(D_CONN) 1078 tptrace(TPPTmisc, 1079 "after 1 consist class, out, tpconsout", 1080 tpcb->tp_class, dgout_routine, tpcons_output, 0 1081 ); 1082 ENDTRACE 1083 CHECK( 1084 ((class_to_use == TP_CLASS_0)&& 1085 (dgout_routine != tpcons_output)), 1086 E_TP_NEGOT_FAILED, ts_negotfailed, respond, 1087 (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 1088 /* ^ more or less the location of class */ 1089 ) 1090 #ifdef TPCONS 1091 if (tpcb->tp_netservice == ISO_CONS && 1092 class_to_use == TP_CLASS_0) { 1093 struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb; 1094 struct pklcd *lcp = (struct pklcd *)isop->isop_chan; 1095 lcp->lcd_flags &= ~X25_DG_CIRCUIT; 1096 } 1097 #endif 1098 } 1099 if( ! tpcb->tp_use_checksum) 1100 IncStat(ts_csum_off); 1101 if(tpcb->tp_xpd_service) 1102 IncStat(ts_use_txpd); 1103 if(tpcb->tp_xtd_format) 1104 IncStat(ts_xtd_fmt); 1105 1106 IFTRACE(D_CONN) 1107 tptrace(TPPTmisc, "after CC class flags dusize CCclass", 1108 tpcb->tp_class, tpcb->tp_flags, tpcb->tp_tpdusize, 1109 hdr->tpdu_CCclass); 1110 ENDTRACE 1111 1112 /* 1113 * Get the maximum transmission unit from the lower layer(s) 1114 * so we can decide how large a TPDU size to negotiate. 1115 * It would be nice if the arguments to this 1116 * were more reasonable. 1117 */ 1118 (tpcb->tp_nlproto->nlp_mtu)(tpcb->tp_sock, tpcb->tp_sock->so_pcb, 1119 &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0); 1120 1121 1122 /* if called or calling suffices appeared on the CC, 1123 * they'd better jive with what's in the pcb 1124 */ 1125 if( fsufxlen ) { 1126 CHECK( ((tpcb->tp_fsuffixlen != fsufxlen) || 1127 bcmp(fsufxloc, tpcb->tp_fsuffix, fsufxlen)), 1128 E_TP_INV_PVAL,ts_inv_sufx, respond, 1129 (1+fsufxloc - (caddr_t)hdr)) 1130 } 1131 if( lsufxlen ) { 1132 CHECK( ((tpcb->tp_lsuffixlen != lsufxlen) || 1133 bcmp(lsufxloc, tpcb->tp_lsuffix, lsufxlen)), 1134 E_TP_INV_PVAL,ts_inv_sufx, respond, 1135 (1+lsufxloc - (caddr_t)hdr)) 1136 } 1137 1138 e.ATTR(CC_TPDU).e_sref = sref; 1139 e.ATTR(CC_TPDU).e_cdt = hdr->tpdu_CCcdt; 1140 takes_data = TRUE; 1141 e.ev_number = CC_TPDU; 1142 IncStat(ts_CC_rcvd); 1143 break; 1144 1145 case DC_TPDU_type: 1146 if (sref != tpcb->tp_fref) 1147 printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n", 1148 sref, tpcb->tp_fref); 1149 1150 CHECK( (sref != tpcb->tp_fref), 1151 E_TP_MISM_REFS, ts_inv_sufx, discard, 1152 (1 + (caddr_t)&hdr->tpdu_DCsref - (caddr_t)hdr)) 1153 1154 e.ev_number = DC_TPDU; 1155 IncStat(ts_DC_rcvd); 1156 break; 1157 1158 case DR_TPDU_type: 1159 IFTRACE(D_TPINPUT) 1160 tptrace(TPPTmisc, "DR recvd", hdr->tpdu_DRreason, 0, 0, 0); 1161 ENDTRACE 1162 if (sref != tpcb->tp_fref) { 1163 printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n", 1164 sref, tpcb->tp_fref); 1165 } 1166 1167 CHECK( (sref != 0 && sref != tpcb->tp_fref && 1168 tpcb->tp_state != TP_CRSENT), 1169 (TP_ERROR_SNDC | E_TP_MISM_REFS),ts_inv_sufx, respond, 1170 (1 + (caddr_t)&hdr->tpdu_DRsref - (caddr_t)hdr)) 1171 1172 e.ATTR(DR_TPDU).e_reason = hdr->tpdu_DRreason; 1173 e.ATTR(DR_TPDU).e_sref = (u_short)sref; 1174 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 /* peel off the tp header; 1310 * remember that the du_li doesn't count itself. 1311 * This may leave us w/ an empty mbuf at the front of a chain. 1312 * We can't just throw away the empty mbuf because hdr still points 1313 * into the mbuf's data area and we're still using hdr (the tpdu header) 1314 */ 1315 m->m_len -= ((int)hdr->tpdu_li + 1); 1316 m->m_data += ((int)hdr->tpdu_li + 1); 1317 1318 if (takes_data) { 1319 int max = tpdu_info[ hdr->tpdu_type ] [TP_MAX_DATA_INDEX]; 1320 int datalen = tpdu_len - hdr->tpdu_li - 1, mbtype = MT_DATA; 1321 struct { 1322 struct tp_disc_reason dr; 1323 struct cmsghdr x_hdr; 1324 } x; 1325 #define c_hdr x.x_hdr 1326 register struct mbuf *n; 1327 1328 CHECK( (max && datalen > max), E_TP_LENGTH_INVAL, 1329 ts_inv_length, respond, (max + hdr->tpdu_li + 1) ); 1330 switch( hdr->tpdu_type ) { 1331 1332 case CR_TPDU_type: 1333 c_hdr.cmsg_type = TPOPT_CONN_DATA; 1334 goto make_control_msg; 1335 1336 case CC_TPDU_type: 1337 c_hdr.cmsg_type = TPOPT_CFRM_DATA; 1338 goto make_control_msg; 1339 1340 case DR_TPDU_type: 1341 x.dr.dr_hdr.cmsg_len = sizeof(x) - sizeof(c_hdr); 1342 x.dr.dr_hdr.cmsg_type = TPOPT_DISC_REASON; 1343 x.dr.dr_hdr.cmsg_level = SOL_TRANSPORT; 1344 x.dr.dr_reason = hdr->tpdu_DRreason; 1345 c_hdr.cmsg_type = TPOPT_DISC_DATA; 1346 make_control_msg: 1347 datalen += sizeof(c_hdr); 1348 c_hdr.cmsg_len = datalen; 1349 c_hdr.cmsg_level = SOL_TRANSPORT; 1350 mbtype = MT_CONTROL; 1351 MGET(n, M_DONTWAIT, MT_DATA); 1352 if (n == 0) 1353 {m_freem(m); m = 0; datalen = 0; goto invoke; } 1354 if (hdr->tpdu_type == DR_TPDU_type) { 1355 datalen += sizeof(x) - sizeof(c_hdr); 1356 bcopy((caddr_t)&x, mtod(n, caddr_t), n->m_len = sizeof(x)); 1357 } else 1358 bcopy((caddr_t)&c_hdr, mtod(n, caddr_t), 1359 n->m_len = sizeof(c_hdr)); 1360 n->m_next = m; 1361 m = n; 1362 /* FALLTHROUGH */ 1363 1364 case XPD_TPDU_type: 1365 if (mbtype != MT_CONTROL) 1366 mbtype = MT_OOBDATA; 1367 m->m_flags |= M_EOR; 1368 /* FALLTHROUGH */ 1369 1370 case DT_TPDU_type: 1371 for (n = m; n; n = n->m_next) { 1372 MCHTYPE(n, mbtype); 1373 } 1374 invoke: 1375 e.ATTR(DT_TPDU).e_datalen = datalen; 1376 e.ATTR(DT_TPDU).e_data = m; 1377 break; 1378 1379 default: 1380 printf( 1381 "ERROR in tp_input! hdr->tpdu_type 0x%x takes_data 0x%x m 0x%x\n", 1382 hdr->tpdu_type, takes_data, m); 1383 break; 1384 } 1385 /* prevent m_freem() after tp_driver() from throwing it all away */ 1386 m = MNULL; 1387 } 1388 1389 IncStat(ts_tpdu_rcvd); 1390 1391 IFDEBUG(D_TPINPUT) 1392 printf( "tp_input: before driver, state 0x%x event 0x%x m 0x%x", 1393 tpcb->tp_state, e.ev_number, m ); 1394 printf(" e.e_data 0x%x\n", e.ATTR(DT_TPDU).e_data); 1395 printf("takes_data 0x%x m_len 0x%x, tpdu_len 0x%x\n", 1396 takes_data, (m==MNULL)?0:m->m_len, tpdu_len); 1397 ENDDEBUG 1398 1399 error = tp_driver(tpcb, &e); 1400 1401 ASSERT(tpcb != (struct tp_pcb *)0); 1402 ASSERT(tpcb->tp_sock != (struct socket *)0); 1403 if( tpcb->tp_sock->so_error == 0 ) 1404 tpcb->tp_sock->so_error = error; 1405 1406 /* Kludge to keep the state tables under control (adding 1407 * data on connect & disconnect & freeing the mbuf containing 1408 * the data would have exploded the tables and made a big mess ). 1409 */ 1410 switch(e.ev_number) { 1411 case CC_TPDU: 1412 case DR_TPDU: 1413 case CR_TPDU: 1414 m = e.ATTR(CC_TPDU).e_data; /* same field for all three dutypes */ 1415 IFDEBUG(D_TPINPUT) 1416 printf("after driver, restoring m to 0x%x, takes_data 0x%x\n", 1417 m, takes_data); 1418 ENDDEBUG 1419 break; 1420 default: 1421 break; 1422 } 1423 /* Concatenated sequences are terminated by any tpdu that 1424 * carries data: CR, CC, DT, XPD, DR. 1425 * All other tpdu types may be concatenated: AK, XAK, DC, ER. 1426 */ 1427 1428 separate: 1429 if ( takes_data == 0 ) { 1430 ASSERT( m != MNULL ); 1431 /* 1432 * we already peeled off the prev. tp header so 1433 * we can just pull up some more and repeat 1434 */ 1435 1436 if( m = tp_inputprep(m) ) { 1437 IFDEBUG(D_TPINPUT) 1438 hdr = mtod(m, struct tpdu *); 1439 printf("tp_input @ separate: hdr 0x%x size %d m 0x%x\n", 1440 hdr, (int) hdr->tpdu_li + 1, m); 1441 dump_mbuf(m, "tp_input after driver, at separate"); 1442 ENDDEBUG 1443 1444 IncStat(ts_concat_rcvd); 1445 goto again; 1446 } 1447 } 1448 if ( m != MNULL ) { 1449 IFDEBUG(D_TPINPUT) 1450 printf("tp_input : m_freem(0x%x)\n", m); 1451 ENDDEBUG 1452 m_freem(m); 1453 IFDEBUG(D_TPINPUT) 1454 printf("tp_input : after m_freem 0x%x\n", m); 1455 ENDDEBUG 1456 } 1457 return (ProtoHook) tpcb; 1458 1459 discard: 1460 /* class 4: drop the tpdu */ 1461 /* class 2,0: Should drop the net connection, if you can figure out 1462 * to which connection it applies 1463 */ 1464 IFDEBUG(D_TPINPUT) 1465 printf("tp_input DISCARD\n"); 1466 ENDDEBUG 1467 IFTRACE(D_TPINPUT) 1468 tptrace(TPPTmisc, "tp_input DISCARD m", m,0,0,0); 1469 ENDTRACE 1470 m_freem(m); 1471 IncStat(ts_recv_drop); 1472 return (ProtoHook)0; 1473 1474 nonx_dref: 1475 switch (dutype) { 1476 default: 1477 goto discard; 1478 case CC_TPDU_type: 1479 /* error = E_TP_MISM_REFS; */ 1480 break; 1481 case DR_TPDU_type: 1482 error |= TP_ERROR_SNDC; 1483 } 1484 respond: 1485 IFDEBUG(D_TPINPUT) 1486 printf("RESPOND: error 0x%x, errlen 0x%x\n", error, errlen); 1487 ENDDEBUG 1488 IFTRACE(D_TPINPUT) 1489 tptrace(TPPTmisc, "tp_input RESPOND m error sref", m, error, sref, 0); 1490 ENDTRACE 1491 if (sref == 0) 1492 goto discard; 1493 (void) tp_error_emit(error, (u_long)sref, (struct sockaddr_iso *)faddr, 1494 (struct sockaddr_iso *)laddr, m, errlen, tpcb, 1495 (int)cons_channel, dgout_routine); 1496 IFDEBUG(D_ERROR_EMIT) 1497 printf("tp_input after error_emit\n"); 1498 ENDDEBUG 1499 1500 #ifdef lint 1501 printf("",sref,opt); 1502 #endif lint 1503 IncStat(ts_recv_drop); 1504 return (ProtoHook)0; 1505 } 1506 1507 1508 /* 1509 * NAME: tp_headersize() 1510 * 1511 * CALLED FROM: 1512 * tp_emit() and tp_sbsend() 1513 * TP needs to know the header size so it can figure out how 1514 * much data to put in each tpdu. 1515 * 1516 * FUNCTION, ARGUMENTS, and RETURN VALUE: 1517 * For a given connection, represented by (tpcb), and 1518 * tpdu type (dutype), return the size of a tp header. 1519 * 1520 * RETURNS: the expected size of the heade in bytesr 1521 * 1522 * SIDE EFFECTS: 1523 * 1524 * NOTES: It would be nice if it got the network header size as well. 1525 */ 1526 int 1527 tp_headersize(dutype, tpcb) 1528 int dutype; 1529 struct tp_pcb *tpcb; 1530 { 1531 register int size = 0; 1532 1533 IFTRACE(D_CONN) 1534 tptrace(TPPTmisc, "tp_headersize dutype class xtd_format", 1535 dutype, tpcb->tp_class, tpcb->tp_xtd_format, 0); 1536 ENDTRACE 1537 if( !( (tpcb->tp_class == TP_CLASS_0) || 1538 (tpcb->tp_class == TP_CLASS_4) || 1539 (dutype == DR_TPDU_type) || 1540 (dutype == CR_TPDU_type) )) { 1541 printf("tp_headersize:dutype 0x%x, class 0x%x", 1542 dutype, tpcb->tp_class); 1543 /* TODO: identify this and GET RID OF IT */ 1544 } 1545 ASSERT( (tpcb->tp_class == TP_CLASS_0) || 1546 (tpcb->tp_class == TP_CLASS_4) || 1547 (dutype == DR_TPDU_type) || 1548 (dutype == CR_TPDU_type) ); 1549 1550 if( tpcb->tp_class == TP_CLASS_0 ) { 1551 size = tpdu_info[ dutype ] [TP_LEN_CLASS_0_INDEX]; 1552 } else { 1553 size = tpdu_info[ dutype ] [tpcb->tp_xtd_format]; 1554 } 1555 return size; 1556 /* caller must get network level header size separately */ 1557 } 1558