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