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