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_pcb.c,v 5.4 88/11/18 17:28:24 nhall Exp $ 31 * $Source: /usr/argo/sys/netiso/RCS/tp_pcb.c,v $ 32 * @(#)tp_pcb.c 7.7 (Berkeley) 01/09/91 * 33 * 34 * 35 * This is the initialization and cleanup stuff - 36 * for the tp machine in general as well as for the individual pcbs. 37 * tp_init() is called at system startup. tp_attach() and tp_getref() are 38 * called when a socket is created. tp_detach() and tp_freeref() 39 * are called during the closing stage and/or when the reference timer 40 * goes off. 41 * tp_soisdisconnecting() and tp_soisdisconnected() are tp-specific 42 * versions of soisconnect* 43 * and are called (obviously) during the closing phase. 44 * 45 */ 46 47 #ifndef lint 48 static char *rcsid = "$Header: tp_pcb.c,v 5.4 88/11/18 17:28:24 nhall Exp $"; 49 #endif lint 50 51 #include "types.h" 52 #include "param.h" 53 #include "mbuf.h" 54 #include "socket.h" 55 #include "socketvar.h" 56 #include "protosw.h" 57 #include "errno.h" 58 #include "time.h" 59 #include "argo_debug.h" 60 #include "tp_param.h" 61 #include "tp_timer.h" 62 #include "tp_ip.h" 63 #include "tp_stat.h" 64 #include "tp_pcb.h" 65 #include "tp_tpdu.h" 66 #include "tp_trace.h" 67 #include "tp_meas.h" 68 #include "tp_seq.h" 69 #include "tp_clnp.h" 70 71 /* list of reference structures */ 72 struct tp_ref tp_ref[N_TPREF]; 73 74 struct tp_param tp_param = { 75 1, /* configured */ 76 }; 77 78 /* ticks are in units of: 79 * 500 nano-fortnights ;-) or 80 * 500 ms or 81 * 1/2 second 82 */ 83 84 struct tp_conn_param tp_conn_param[] = { 85 /* ISO_CLNS: TP4 CONNECTION LESS */ 86 { 87 TP_NRETRANS, /* short p_Nretrans; */ 88 20, /* 10 sec */ /* short p_dr_ticks; */ 89 90 20, /* 10 sec */ /* short p_cc_ticks; */ 91 20, /* 10 sec */ /* short p_dt_ticks; */ 92 93 40, /* 20 sec */ /* short p_x_ticks; */ 94 80, /* 40 sec */ /* short p_cr_ticks;*/ 95 96 240, /* 2 min */ /* short p_keepalive_ticks;*/ 97 10, /* 5 sec */ /* short p_sendack_ticks; */ 98 99 600, /* 5 min */ /* short p_ref_ticks; */ 100 360, /* 3 min */ /* short p_inact_ticks; */ 101 102 (short) 100, /* short p_lcdtfract */ 103 (short) TP_SOCKBUFSIZE, /* short p_winsize */ 104 TP_TPDUSIZE, /* u_char p_tpdusize */ 105 106 TPACK_WINDOW, /* 4 bits p_ack_strat */ 107 TPRX_USE_CW | TPRX_FASTSTART, 108 /* 4 bits p_rx_strat*/ 109 TP_CLASS_4 | TP_CLASS_0,/* 5 bits p_class */ 110 1, /* 1 bit xtd format */ 111 1, /* 1 bit xpd service */ 112 1, /* 1 bit use_checksum */ 113 0, /* 1 bit use net xpd */ 114 0, /* 1 bit use rcc */ 115 0, /* 1 bit use efc */ 116 1, /* no disc indications */ 117 0, /* don't change params */ 118 ISO_CLNS, /* p_netservice */ 119 }, 120 /* IN_CLNS: TP4 CONNECTION LESS */ 121 { 122 TP_NRETRANS, /* short p_Nretrans; */ 123 20, /* 10 sec */ /* short p_dr_ticks; */ 124 125 20, /* 10 sec */ /* short p_cc_ticks; */ 126 20, /* 10 sec */ /* short p_dt_ticks; */ 127 128 40, /* 20 sec */ /* short p_x_ticks; */ 129 80, /* 40 sec */ /* short p_cr_ticks;*/ 130 131 240, /* 2 min */ /* short p_keepalive_ticks;*/ 132 10, /* 5 sec */ /* short p_sendack_ticks; */ 133 134 600, /* 5 min */ /* short p_ref_ticks; */ 135 360, /* 3 min */ /* short p_inact_ticks; */ 136 137 (short) 100, /* short p_lcdtfract */ 138 (short) TP_SOCKBUFSIZE, /* short p_winsize */ 139 TP_TPDUSIZE, /* u_char p_tpdusize */ 140 141 TPACK_WINDOW, /* 4 bits p_ack_strat */ 142 TPRX_USE_CW | TPRX_FASTSTART, 143 /* 4 bits p_rx_strat*/ 144 TP_CLASS_4, /* 5 bits p_class */ 145 1, /* 1 bit xtd format */ 146 1, /* 1 bit xpd service */ 147 1, /* 1 bit use_checksum */ 148 0, /* 1 bit use net xpd */ 149 0, /* 1 bit use rcc */ 150 0, /* 1 bit use efc */ 151 1, /* no disc indications */ 152 0, /* don't change params */ 153 IN_CLNS, /* p_netservice */ 154 }, 155 /* ISO_CONS: TP0 CONNECTION MODE */ 156 { 157 TP_NRETRANS, /* short p_Nretrans; */ 158 0, /* n/a */ /* short p_dr_ticks; */ 159 160 40, /* 20 sec */ /* short p_cc_ticks; */ 161 0, /* n/a */ /* short p_dt_ticks; */ 162 163 0, /* n/a */ /* short p_x_ticks; */ 164 360, /* 3 min */ /* short p_cr_ticks;*/ 165 166 0, /* n/a */ /* short p_keepalive_ticks;*/ 167 0, /* n/a */ /* short p_sendack_ticks; */ 168 169 600, /* for cr/cc to clear *//* short p_ref_ticks; */ 170 0, /* n/a */ /* short p_inact_ticks; */ 171 172 /* Use tp4 defaults just in case the user changes ONLY 173 * the class 174 */ 175 (short) 100, /* short p_lcdtfract */ 176 (short) TP0_SOCKBUFSIZE, /* short p_winsize */ 177 TP0_TPDUSIZE, /* 8 bits p_tpdusize */ 178 179 0, /* 4 bits p_ack_strat */ 180 0, /* 4 bits p_rx_strat*/ 181 TP_CLASS_0, /* 5 bits p_class */ 182 0, /* 1 bit xtd format */ 183 0, /* 1 bit xpd service */ 184 0, /* 1 bit use_checksum */ 185 0, /* 1 bit use net xpd */ 186 0, /* 1 bit use rcc */ 187 0, /* 1 bit use efc */ 188 0, /* no disc indications */ 189 0, /* don't change params */ 190 ISO_CONS, /* p_netservice */ 191 }, 192 /* ISO_COSNS: TP4 CONNECTION LESS SERVICE over CONSNS */ 193 { 194 TP_NRETRANS, /* short p_Nretrans; */ 195 40, /* 20 sec */ /* short p_dr_ticks; */ 196 197 40, /* 20 sec */ /* short p_cc_ticks; */ 198 80, /* 40 sec */ /* short p_dt_ticks; */ 199 200 120, /* 1 min */ /* short p_x_ticks; */ 201 360, /* 3 min */ /* short p_cr_ticks;*/ 202 203 360, /* 3 min */ /* short p_keepalive_ticks;*/ 204 20, /* 10 sec */ /* short p_sendack_ticks; */ 205 206 600, /* 5 min */ /* short p_ref_ticks; */ 207 480, /* 4 min */ /* short p_inact_ticks; */ 208 209 (short) 100, /* short p_lcdtfract */ 210 (short) TP0_SOCKBUFSIZE, /* short p_winsize */ 211 TP0_TPDUSIZE, /* u_char p_tpdusize */ 212 213 TPACK_WINDOW, /* 4 bits p_ack_strat */ 214 TPRX_USE_CW , /* No fast start */ 215 /* 4 bits p_rx_strat*/ 216 TP_CLASS_4 | TP_CLASS_0,/* 5 bits p_class */ 217 0, /* 1 bit xtd format */ 218 1, /* 1 bit xpd service */ 219 1, /* 1 bit use_checksum */ 220 0, /* 1 bit use net xpd */ 221 0, /* 1 bit use rcc */ 222 0, /* 1 bit use efc */ 223 0, /* no disc indications */ 224 0, /* don't change params */ 225 ISO_COSNS, /* p_netservice */ 226 }, 227 }; 228 229 #ifdef INET 230 int in_putnetaddr(); 231 int in_getnetaddr(); 232 int in_cmpnetaddr(); 233 int in_putsufx(); 234 int in_getsufx(); 235 int in_recycle_tsuffix(); 236 int tpip_mtu(); 237 int in_pcbbind(); 238 int in_pcbconnect(); 239 int in_pcbdisconnect(); 240 int in_pcbdetach(); 241 int in_pcballoc(); 242 int tpip_output(); 243 int tpip_output_dg(); 244 struct inpcb tp_inpcb; 245 #endif INET 246 #ifdef ISO 247 int iso_putnetaddr(); 248 int iso_getnetaddr(); 249 int iso_cmpnetaddr(); 250 int iso_putsufx(); 251 int iso_getsufx(); 252 int iso_recycle_tsuffix(); 253 int tpclnp_mtu(); 254 int iso_pcbbind(); 255 int iso_pcbconnect(); 256 int iso_pcbdisconnect(); 257 int iso_pcbdetach(); 258 int iso_pcballoc(); 259 int tpclnp_output(); 260 int tpclnp_output_dg(); 261 int iso_nlctloutput(); 262 struct isopcb tp_isopcb; 263 #endif ISO 264 #ifdef TPCONS 265 int iso_putnetaddr(); 266 int iso_getnetaddr(); 267 int iso_cmpnetaddr(); 268 int iso_putsufx(); 269 int iso_getsufx(); 270 int iso_recycle_tsuffix(); 271 int tpcons_mtu(); 272 int iso_pcbbind(); 273 int tpcons_pcbconnect(); 274 int iso_pcbdisconnect(); 275 int iso_pcbdetach(); 276 int iso_pcballoc(); 277 int tpcons_output(); 278 struct isopcb tp_isopcb; 279 #endif TPCONS 280 281 282 struct nl_protosw nl_protosw[] = { 283 /* ISO_CLNS */ 284 #ifdef ISO 285 { AF_ISO, iso_putnetaddr, iso_getnetaddr, iso_cmpnetaddr, 286 iso_putsufx, iso_getsufx, 287 iso_recycle_tsuffix, 288 tpclnp_mtu, iso_pcbbind, iso_pcbconnect, 289 iso_pcbdisconnect, iso_pcbdetach, 290 iso_pcballoc, 291 tpclnp_output, tpclnp_output_dg, iso_nlctloutput, 292 (caddr_t) &tp_isopcb, 293 }, 294 #else 295 { 0 }, 296 #endif ISO 297 /* IN_CLNS */ 298 #ifdef INET 299 { AF_INET, in_putnetaddr, in_getnetaddr, in_cmpnetaddr, 300 in_putsufx, in_getsufx, 301 in_recycle_tsuffix, 302 tpip_mtu, in_pcbbind, in_pcbconnect, 303 in_pcbdisconnect, in_pcbdetach, 304 in_pcballoc, 305 tpip_output, tpip_output_dg, /* nl_ctloutput */ NULL, 306 (caddr_t) &tp_inpcb, 307 }, 308 #else 309 { 0 }, 310 #endif INET 311 /* ISO_CONS */ 312 #if defined(ISO) && defined(TPCONS) 313 { AF_ISO, iso_putnetaddr, iso_getnetaddr, iso_cmpnetaddr, 314 iso_putsufx, iso_getsufx, 315 iso_recycle_tsuffix, 316 tpcons_mtu, iso_pcbbind, tpcons_pcbconnect, 317 iso_pcbdisconnect, iso_pcbdetach, 318 iso_pcballoc, 319 tpcons_output, tpcons_output, iso_nlctloutput, 320 (caddr_t) &tp_isopcb, 321 }, 322 #else 323 { 0 }, 324 #endif ISO_CONS 325 /* End of protosw marker */ 326 { 0 } 327 }; 328 329 /* 330 * NAME: tp_init() 331 * 332 * CALLED FROM: 333 * autoconf through the protosw structure 334 * 335 * FUNCTION: 336 * initialize tp machine 337 * 338 * RETURNS: Nada 339 * 340 * SIDE EFFECTS: 341 * 342 * NOTES: 343 */ 344 int 345 tp_init() 346 { 347 static int init_done=0; 348 void tp_timerinit(); 349 350 if (init_done++) 351 return 0; 352 353 354 /* FOR INET */ 355 tp_inpcb.inp_next = tp_inpcb.inp_prev = &tp_inpcb; 356 /* FOR ISO */ 357 tp_isopcb.isop_next = tp_isopcb.isop_prev = &tp_isopcb; 358 359 tp_start_win = 2; 360 361 tp_timerinit(); 362 bzero((caddr_t)&tp_stat, sizeof(struct tp_stat)); 363 return 0; 364 } 365 366 /* 367 * NAME: tp_soisdisconnecting() 368 * 369 * CALLED FROM: 370 * tp.trans 371 * 372 * FUNCTION and ARGUMENTS: 373 * Set state of the socket (so) to reflect that fact that we're disconnectING 374 * 375 * RETURNS: Nada 376 * 377 * SIDE EFFECTS: 378 * 379 * NOTES: 380 * This differs from the regular soisdisconnecting() in that the latter 381 * also sets the SS_CANTRECVMORE and SS_CANTSENDMORE flags. 382 * We don't want to set those flags because those flags will cause 383 * a SIGPIPE to be delivered in sosend() and we don't like that. 384 * If anyone else is sleeping on this socket, wake 'em up. 385 */ 386 void 387 tp_soisdisconnecting(so) 388 register struct socket *so; 389 { 390 soisdisconnecting(so); 391 so->so_state &= ~SS_CANTSENDMORE; 392 IFPERF(sototpcb(so)) 393 register struct tp_pcb *tpcb = sototpcb(so); 394 u_int fsufx, lsufx; 395 396 bcopy ((caddr_t)tpcb->tp_fsuffix, (caddr_t)&fsufx, sizeof(u_int) ); 397 bcopy ((caddr_t)tpcb->tp_lsuffix, (caddr_t)&lsufx, sizeof(u_int) ); 398 399 tpmeas(tpcb->tp_lref, TPtime_close, &time, fsufx, lsufx, tpcb->tp_fref); 400 tpcb->tp_perf_on = 0; /* turn perf off */ 401 ENDPERF 402 } 403 404 405 /* 406 * NAME: tp_soisdisconnected() 407 * 408 * CALLED FROM: 409 * tp.trans 410 * 411 * FUNCTION and ARGUMENTS: 412 * Set state of the socket (so) to reflect that fact that we're disconnectED 413 * Set the state of the reference structure to closed, and 414 * recycle the suffix. 415 * Start a reference timer. 416 * 417 * RETURNS: Nada 418 * 419 * SIDE EFFECTS: 420 * 421 * NOTES: 422 * This differs from the regular soisdisconnected() in that the latter 423 * also sets the SS_CANTRECVMORE and SS_CANTSENDMORE flags. 424 * We don't want to set those flags because those flags will cause 425 * a SIGPIPE to be delivered in sosend() and we don't like that. 426 * If anyone else is sleeping on this socket, wake 'em up. 427 */ 428 void 429 tp_soisdisconnected(tpcb) 430 register struct tp_pcb *tpcb; 431 { 432 register struct socket *so = tpcb->tp_sock; 433 434 soisdisconnecting(so); 435 so->so_state &= ~SS_CANTSENDMORE; 436 IFPERF(sototpcb(so)) 437 register struct tp_pcb *ttpcb = sototpcb(so); 438 u_int fsufx, lsufx; 439 440 /* CHOKE */ 441 bcopy ((caddr_t)ttpcb->tp_fsuffix, (caddr_t)&fsufx, sizeof(u_int) ); 442 bcopy ((caddr_t)ttpcb->tp_lsuffix, (caddr_t)&lsufx, sizeof(u_int) ); 443 444 tpmeas(ttpcb->tp_lref, TPtime_close, 445 &time, &lsufx, &fsufx, ttpcb->tp_fref); 446 tpcb->tp_perf_on = 0; /* turn perf off */ 447 ENDPERF 448 449 tpcb->tp_refp->tpr_state = REF_FROZEN; 450 tp_recycle_tsuffix( tpcb ); 451 tp_etimeout(tpcb->tp_refp, TM_reference, 0,0,0, (int)tpcb->tp_refer_ticks); 452 } 453 454 int tp_maxrefopen; /* highest reference # of the set of open tp connections */ 455 456 /* 457 * NAME: tp_freeref() 458 * 459 * CALLED FROM: 460 * tp.trans when the reference timer goes off, and 461 * from tp_attach() and tp_detach() when a tpcb is partially set up but not 462 * set up enough to have a ref timer set for it, and it's discarded 463 * due to some sort of error or an early close() 464 * 465 * FUNCTION and ARGUMENTS: 466 * Frees the reference represented by (r) for re-use. 467 * 468 * RETURNS: Nothing 469 * 470 * SIDE EFFECTS: 471 * 472 * NOTES: better be called at clock priority !!!!! 473 */ 474 void 475 tp_freeref(r) 476 register struct tp_ref *r; 477 { 478 IFDEBUG(D_TIMER) 479 printf("tp_freeref called for ref %d maxrefopen %d\n", 480 r - tp_ref, tp_maxrefopen); 481 ENDDEBUG 482 IFTRACE(D_TIMER) 483 tptrace(TPPTmisc, "tp_freeref ref tp_maxrefopen", 484 r - tp_ref, tp_maxrefopen, 0, 0); 485 ENDTRACE 486 r->tpr_state = REF_FREE; 487 IFDEBUG(D_CONN) 488 printf("tp_freeref: CLEARING tpr_pcb 0x%x\n", r->tpr_pcb); 489 ENDDEBUG 490 r->tpr_pcb = (struct tp_pcb *)0; 491 492 r = &tp_ref[tp_maxrefopen]; 493 494 while( tp_maxrefopen > 0 ) { 495 if(r->tpr_state ) 496 break; 497 tp_maxrefopen--; 498 r--; 499 } 500 IFDEBUG(D_TIMER) 501 printf("tp_freeref ends w/ maxrefopen %d\n", tp_maxrefopen); 502 ENDDEBUG 503 } 504 505 /* 506 * NAME: tp_getref() 507 * 508 * CALLED FROM: 509 * tp_attach() 510 * 511 * FUNCTION and ARGUMENTS: 512 * obtains the next free reference and allocates the appropriate 513 * ref structure, links that structure to (tpcb) 514 * 515 * RETURN VALUE: 516 * a reference number 517 * or TP_ENOREF 518 * 519 * SIDE EFFECTS: 520 * 521 * NOTES: 522 */ 523 static RefNum 524 tp_getref(tpcb) 525 register struct tp_pcb *tpcb; 526 { 527 register struct tp_ref *r = tp_ref; 528 register int i=1; 529 530 r++; /* tp_ref[0] is never used */ 531 532 /* REF_FREE is zero */ 533 while( r->tpr_state ) { 534 r++; 535 if ( i == N_TPREF ) { 536 return TP_ENOREF; 537 } 538 i++; 539 } 540 r->tpr_state = REF_OPENING; 541 if (tp_maxrefopen < i) 542 tp_maxrefopen = i; 543 r->tpr_pcb = tpcb; 544 tpcb->tp_refp = r; 545 546 return i; 547 } 548 549 /* 550 * NAME: tp_attach() 551 * 552 * CALLED FROM: 553 * tp_usrreq, PRU_ATTACH 554 * 555 * FUNCTION and ARGUMENTS: 556 * given a socket (so) and a protocol family (dom), allocate a tpcb 557 * and ref structure, initialize everything in the structures that 558 * needs to be initialized. 559 * 560 * RETURN VALUE: 561 * 0 ok 562 * EINVAL if DEBUG(X) in is on and a disaster has occurred 563 * ENOPROTOOPT if TP hasn't been configured or if the 564 * socket wasn't created with tp as its protocol 565 * EISCONN if this socket is already part of a connection 566 * ETOOMANYREFS if ran out of tp reference numbers. 567 * E* whatever error is returned from soreserve() 568 * for from the network-layer pcb allocation routine 569 * 570 * SIDE EFFECTS: 571 * 572 * NOTES: 573 */ 574 tp_attach(so, dom) 575 struct socket *so; 576 int dom; 577 { 578 register struct tp_pcb *tpcb; 579 int error; 580 int protocol = so->so_proto->pr_protocol; 581 extern struct tp_conn_param tp_conn_param[]; 582 583 IFDEBUG(D_CONN) 584 printf("tp_attach:dom 0x%x so 0x%x ", dom, so); 585 ENDDEBUG 586 IFTRACE(D_CONN) 587 tptrace(TPPTmisc, "tp_attach:dom so", dom, so, 0, 0); 588 ENDTRACE 589 if ( ! tp_param.tpp_configed ) { 590 error = ENOPROTOOPT; /* protocol not available */ 591 goto bad2; 592 } 593 594 if (so->so_pcb != NULL) { 595 return EISCONN; /* socket already part of a connection*/ 596 } 597 598 error = soreserve(so, TP_SOCKBUFSIZE, TP_SOCKBUFSIZE); 599 /* later an ioctl will allow reallocation IF still in closed state */ 600 601 if (error) 602 goto bad2; 603 604 MALLOC(tpcb, struct tp_pcb *, sizeof(*tpcb), M_PCB, M_NOWAIT); 605 if (tpcb == NULL) { 606 error = ENOBUFS; 607 goto bad2; 608 } 609 bzero( (caddr_t)tpcb, sizeof (struct tp_pcb) ); 610 611 if ( ((tpcb->tp_lref = tp_getref(tpcb)) & TP_ENOREF) != 0 ) { 612 error = ETOOMANYREFS; 613 goto bad3; 614 } 615 tpcb->tp_sock = so; 616 tpcb->tp_domain = dom; 617 if (protocol<ISOPROTO_TP4) { 618 tpcb->tp_netservice = ISO_CONS; 619 tpcb->tp_snduna = (SeqNum) -1;/* kludge so the pseudo-ack from the CR/CC 620 * will generate correct fake-ack values 621 */ 622 } else { 623 tpcb->tp_netservice = (dom== AF_INET)?IN_CLNS:ISO_CLNS; 624 /* the default */ 625 } 626 tpcb->_tp_param = tp_conn_param[tpcb->tp_netservice]; 627 628 tpcb->tp_cong_win = 1; 629 tpcb->tp_state = TP_CLOSED; 630 tpcb->tp_vers = TP_VERSION; 631 632 /* Spec says default is 128 octets, 633 * that is, if the tpdusize argument never appears, use 128. 634 * As the initiator, we will always "propose" the 2048 635 * size, that is, we will put this argument in the CR 636 * always, but accept what the other side sends on the CC. 637 * If the initiator sends us something larger on a CR, 638 * we'll respond w/ this. 639 * Our maximum is 4096. See tp_chksum.c comments. 640 */ 641 tpcb->tp_l_tpdusize = 1 << tpcb->tp_tpdusize; 642 643 tpcb->tp_seqmask = TP_NML_FMT_MASK; 644 tpcb->tp_seqbit = TP_NML_FMT_BIT; 645 tpcb->tp_seqhalf = tpcb->tp_seqbit >> 1; 646 tpcb->tp_sndhiwat = (SeqNum) - 1; /* a kludge but it works */ 647 tpcb->tp_s_subseq = 0; 648 649 /* attach to a network-layer protoswitch */ 650 /* new way */ 651 tpcb->tp_nlproto = & nl_protosw[tpcb->tp_netservice]; 652 ASSERT( tpcb->tp_nlproto->nlp_afamily == tpcb->tp_domain); 653 #ifdef notdef 654 /* OLD WAY */ 655 /* TODO: properly, this search would be on the basis of 656 * domain,netservice or just netservice only (if you have 657 * IN_CLNS, ISO_CLNS, and ISO_CONS) 658 */ 659 tpcb->tp_nlproto = nl_protosw; 660 while(tpcb->tp_nlproto->nlp_afamily != tpcb->tp_domain ) { 661 if( tpcb->tp_nlproto->nlp_afamily == 0 ) { 662 error = EAFNOSUPPORT; 663 goto bad4; 664 } 665 tpcb->tp_nlproto ++; 666 } 667 #endif notdef 668 669 /* xx_pcballoc sets so_pcb */ 670 if ( error = (tpcb->tp_nlproto->nlp_pcballoc) ( 671 so, tpcb->tp_nlproto->nlp_pcblist ) ) { 672 goto bad4; 673 } 674 675 if( dom == AF_INET ) 676 sotoinpcb(so)->inp_ppcb = (caddr_t) tpcb; 677 /* nothing to do for iso case */ 678 679 tpcb->tp_npcb = (caddr_t) so->so_pcb; 680 so->so_tpcb = (caddr_t) tpcb; 681 682 return 0; 683 684 bad4: 685 IFDEBUG(D_CONN) 686 printf("BAD4 in tp_attach, so 0x%x\n", so); 687 ENDDEBUG 688 tp_freeref(tpcb->tp_refp); 689 690 bad3: 691 IFDEBUG(D_CONN) 692 printf("BAD3 in tp_attach, so 0x%x\n", so); 693 ENDDEBUG 694 695 free((caddr_t)tpcb, M_PCB); /* never a cluster */ 696 697 bad2: 698 IFDEBUG(D_CONN) 699 printf("BAD2 in tp_attach, so 0x%x\n", so); 700 ENDDEBUG 701 so->so_pcb = 0; 702 so->so_tpcb = 0; 703 sofree(so); 704 705 /*bad:*/ 706 IFDEBUG(D_CONN) 707 printf("BAD in tp_attach, so 0x%x\n", so); 708 ENDDEBUG 709 return error; 710 } 711 712 /* 713 * NAME: tp_detach() 714 * 715 * CALLED FROM: 716 * tp.trans, on behalf of a user close request 717 * and when the reference timer goes off 718 * (if the disconnect was initiated by the protocol entity 719 * rather than by the user) 720 * 721 * FUNCTION and ARGUMENTS: 722 * remove the tpcb structure from the list of active or 723 * partially active connections, recycle all the mbufs 724 * associated with the pcb, ref structure, sockbufs, etc. 725 * Only free the ref structure if you know that a ref timer 726 * wasn't set for this tpcb. 727 * 728 * RETURNS: Nada 729 * 730 * SIDE EFFECTS: 731 * 732 * NOTES: 733 * tp_soisdisconnected() was already when this is called 734 */ 735 void 736 tp_detach(tpcb) 737 register struct tp_pcb *tpcb; 738 { 739 void tp_freeref(); 740 register struct socket *so = tpcb->tp_sock; 741 742 IFDEBUG(D_CONN) 743 printf("tp_detach(tpcb 0x%x, so 0x%x)\n", 744 tpcb,so); 745 ENDDEBUG 746 IFTRACE(D_CONN) 747 tptraceTPCB(TPPTmisc, "tp_detach tpcb so lsufx", 748 tpcb, so, *(u_short *)(tpcb->tp_lsuffix), 0); 749 ENDTRACE 750 751 if (so->so_head) { 752 if (!soqremque(so, 0) && !soqremque(so, 1)) 753 panic("sofree dq"); 754 so->so_head = 0; 755 } 756 757 IFDEBUG(D_CONN) 758 printf("tp_detach(freeing RTC list snduna 0x%x rcvnxt 0x%x)\n", 759 tpcb->tp_snduna_rtc, 760 tpcb->tp_rcvnxt_rtc); 761 ENDDEBUG 762 763 #define FREE_RTC_LIST(XXX)\ 764 { register struct tp_rtc *xxr = XXX, *xxs; while (xxr) {\ 765 xxs = xxr->tprt_next;\ 766 m_freem( xxr->tprt_data );\ 767 m_free( dtom(xxr) ); xxr = xxs; }\ 768 XXX = (struct tp_rtc *)0;\ 769 } 770 771 FREE_RTC_LIST( tpcb->tp_snduna_rtc ); 772 tpcb->tp_sndhiwat_rtc = (struct tp_rtc *)0; 773 774 FREE_RTC_LIST( tpcb->tp_rcvnxt_rtc ); 775 776 #undef FREE_RTC_LIST 777 778 IFDEBUG(D_CONN) 779 printf("calling (...nlproto->...)(0x%x, so 0x%x)\n", 780 so->so_pcb, so); 781 printf("so 0x%x so_head 0x%x, qlen %d q0len %d qlimit %d\n", 782 so, so->so_head, 783 so->so_q0len, so->so_qlen, so->so_qlimit); 784 ENDDEBUG 785 786 if ( tpcb->tp_flags & (TPF_DISC_DATA_OUT | TPF_CONN_DATA_OUT ) ) { 787 ASSERT( so->so_snd.sb_cc != 0 ); 788 IFDEBUG(D_CONN) 789 printf( 790 "detach, flags 0x%x doing sbdrop on so_snd, mb 0x%x cc 0x%x\n", 791 tpcb->tp_flags, so->so_snd.sb_mb, so->so_snd.sb_cc); 792 dump_mbuf( so->so_snd.sb_mb, "detach so snd: \n"); 793 ENDDEBUG 794 if ( so->so_snd.sb_cc != 0 ) 795 sbflush(&so->so_snd); 796 tpcb->tp_flags &= ~(TPF_CONN_DATA_OUT | TPF_DISC_DATA_OUT); 797 } 798 if ( tpcb->tp_flags & (TPF_DISC_DATA_IN | TPF_CONN_DATA_IN ) ) { 799 ASSERT( tpcb->tp_Xrcv.sb_cc != 0 ); 800 IFDEBUG(D_CONN) 801 printf( 802 "detach, flags 0x%x doing sbdrop on tp_Xrcv, mb 0x%x cc 0x%x\n", 803 tpcb->tp_flags, tpcb->tp_Xrcv.sb_mb, tpcb->tp_Xrcv.sb_cc); 804 dump_mbuf( tpcb->tp_Xrcv.sb_mb, "detach Xrcv: \n"); 805 ENDDEBUG 806 if( tpcb->tp_Xrcv.sb_cc != 0 ) 807 sbdrop(&tpcb->tp_Xrcv, (int)tpcb->tp_Xrcv.sb_cc); 808 tpcb->tp_flags &= ~(TPF_CONN_DATA_IN | TPF_DISC_DATA_IN); 809 } 810 811 IFDEBUG(D_CONN) 812 printf("so_snd at 0x%x so_rcv at 0x%x\n", &so->so_snd, &so->so_rcv); 813 dump_mbuf(so->so_snd.sb_mb, "so_snd at detach "); 814 printf("about to call LL detach, nlproto 0x%x, nl_detach 0x%x\n", 815 tpcb->tp_nlproto, tpcb->tp_nlproto->nlp_pcbdetach); 816 ENDDEBUG 817 818 819 820 (tpcb->tp_nlproto->nlp_pcbdetach)((struct inpcb *)so->so_pcb); 821 /* does an sofree(so) */ 822 823 IFDEBUG(D_CONN) 824 printf("after xxx_pcbdetach\n"); 825 ENDDEBUG 826 827 if( tpcb->tp_refp->tpr_state == REF_OPENING ) { 828 /* no connection existed here so no reference timer will be called */ 829 IFDEBUG(D_CONN) 830 printf("SETTING ref %d, 0x%x to REF_FREE\n", tpcb->tp_lref, 831 tpcb->tp_refp - &tp_ref[0]); 832 ENDDEBUG 833 834 tp_freeref(tpcb->tp_refp); 835 } 836 837 if (tpcb->tp_Xsnd.sb_mb) { 838 printf("Unsent Xdata on detach; would panic"); 839 sbflush(&tpcb->tp_Xsnd); 840 } 841 so->so_tpcb = (caddr_t)0; 842 843 /* 844 * Get rid of the cluster mbuf allocated for performance measurements, if 845 * there is one. Note that tpcb->tp_perf_on says nothing about whether or 846 * not a cluster mbuf was allocated, so you have to check for a pointer 847 * to one (that is, we need the TP_PERF_MEASs around the following section 848 * of code, not the IFPERFs) 849 */ 850 #ifdef TP_PERF_MEAS 851 if(tpcb->tp_p_mbuf) { 852 register struct mbuf *m = tpcb->tp_p_mbuf; 853 struct mbuf *n; 854 IFDEBUG(D_PERF_MEAS) 855 printf("freeing tp_p_meas 0x%x ", tpcb->tp_p_meas); 856 ENDDEBUG 857 do { 858 MFREE(m, n); 859 m = n; 860 } while (n); 861 tpcb->tp_p_meas = 0; 862 tpcb->tp_p_mbuf = 0; 863 } 864 #endif TP_PERF_MEAS 865 866 IFDEBUG(D_CONN) 867 printf( "end of detach, NOT single, tpcb 0x%x\n", tpcb); 868 ENDDEBUG 869 /* free((caddr_t)tpcb, M_PCB); WHere to put this ? */ 870 } 871