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