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