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