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