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