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