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