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