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