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