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