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.23 (Berkeley) 04/17/92 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 u_long tp_sendspace = 1024 * 4; 328 u_long tp_recvspace = 1024 * 4; 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(tpcb) 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_refstate = REF_FROZEN; 451 tp_recycle_tsuffix(tpcb); 452 tp_etimeout(tpcb, TM_reference, (int)tpcb->tp_refer_ticks); 453 } 454 455 /* 456 * NAME: tp_freeref() 457 * 458 * CALLED FROM: 459 * tp.trans when the reference timer goes off, and 460 * from tp_attach() and tp_detach() when a tpcb is partially set up but not 461 * set up enough to have a ref timer set for it, and it's discarded 462 * due to some sort of error or an early close() 463 * 464 * FUNCTION and ARGUMENTS: 465 * Frees the reference represented by (r) for re-use. 466 * 467 * RETURNS: Nothing 468 * 469 * SIDE EFFECTS: 470 * 471 * NOTES: better be called at clock priority !!!!! 472 */ 473 void 474 tp_freeref(n) 475 RefNum n; 476 { 477 register struct tp_ref *r = tp_ref + n; 478 register struct tp_pcb *tpcb; 479 480 tpcb = r->tpr_pcb; 481 IFDEBUG(D_TIMER) 482 printf("tp_freeref called for ref %d pcb %x maxrefopen %d\n", 483 n, tpcb, tp_refinfo.tpr_maxopen); 484 ENDDEBUG 485 IFTRACE(D_TIMER) 486 tptrace(TPPTmisc, "tp_freeref ref maxrefopen pcb", 487 n, tp_refinfo.tpr_maxopen, tpcb, 0); 488 ENDTRACE 489 if (tpcb == 0) 490 return; 491 IFDEBUG(D_CONN) 492 printf("tp_freeref: CLEARING tpr_pcb 0x%x\n", tpcb); 493 ENDDEBUG 494 r->tpr_pcb = (struct tp_pcb *)0; 495 tpcb->tp_refstate = REF_FREE; 496 497 for (r = tp_ref + tp_refinfo.tpr_maxopen; r > tp_ref; r--) 498 if (r->tpr_pcb) 499 break; 500 tp_refinfo.tpr_maxopen = r - tp_ref; 501 tp_refinfo.tpr_numopen--; 502 503 IFDEBUG(D_TIMER) 504 printf("tp_freeref ends w/ maxrefopen %d\n", tp_refinfo.tpr_maxopen); 505 ENDDEBUG 506 } 507 508 /* 509 * NAME: tp_getref() 510 * 511 * CALLED FROM: 512 * tp_attach() 513 * 514 * FUNCTION and ARGUMENTS: 515 * obtains the next free reference and allocates the appropriate 516 * ref structure, links that structure to (tpcb) 517 * 518 * RETURN VALUE: 519 * a reference number 520 * or TP_ENOREF 521 * 522 * SIDE EFFECTS: 523 * 524 * NOTES: 525 */ 526 u_long 527 tp_getref(tpcb) 528 register struct tp_pcb *tpcb; 529 { 530 register struct tp_ref *r, *rlim; 531 register int i; 532 caddr_t obase; 533 unsigned size; 534 535 if (++tp_refinfo.tpr_numopen < tp_refinfo.tpr_size) 536 for (r = tp_refinfo.tpr_base, rlim = r + tp_refinfo.tpr_size; 537 ++r < rlim; ) /* tp_ref[0] is never used */ 538 if (r->tpr_pcb == 0) 539 goto got_one; 540 /* else have to allocate more space */ 541 542 obase = (caddr_t)tp_refinfo.tpr_base; 543 size = tp_refinfo.tpr_size * sizeof(struct tp_ref); 544 r = (struct tp_ref *) malloc(size + size, M_PCB, M_NOWAIT); 545 if (r == 0) 546 return (--tp_refinfo.tpr_numopen, TP_ENOREF); 547 tp_refinfo.tpr_base = tp_ref = r; 548 tp_refinfo.tpr_size *= 2; 549 bcopy(obase, (caddr_t)r, size); 550 free(obase, M_PCB); 551 r = (struct tp_ref *)(size + (caddr_t)r); 552 bzero((caddr_t)r, size); 553 554 got_one: 555 r->tpr_pcb = tpcb; 556 tpcb->tp_refstate = REF_OPENING; 557 i = r - tp_refinfo.tpr_base; 558 if (tp_refinfo.tpr_maxopen < i) 559 tp_refinfo.tpr_maxopen = i; 560 return (u_long)i; 561 } 562 563 /* 564 * NAME: tp_set_npcb() 565 * 566 * CALLED FROM: 567 * tp_attach(), tp_route_to() 568 * 569 * FUNCTION and ARGUMENTS: 570 * given a tpcb, allocate an appropriate lower-lever npcb, freeing 571 * any old ones that might need re-assigning. 572 */ 573 tp_set_npcb(tpcb) 574 register struct tp_pcb *tpcb; 575 { 576 register struct socket *so = tpcb->tp_sock; 577 int error; 578 579 if (tpcb->tp_nlproto && tpcb->tp_npcb) { 580 short so_state = so->so_state; 581 so->so_state &= ~SS_NOFDREF; 582 tpcb->tp_nlproto->nlp_pcbdetach(tpcb->tp_npcb); 583 so->so_state = so_state; 584 } 585 tpcb->tp_nlproto = &nl_protosw[tpcb->tp_netservice]; 586 /* xx_pcballoc sets so_pcb */ 587 error = tpcb->tp_nlproto->nlp_pcballoc(so, tpcb->tp_nlproto->nlp_pcblist); 588 tpcb->tp_npcb = so->so_pcb; 589 so->so_pcb = (caddr_t)tpcb; 590 return (error); 591 } 592 /* 593 * NAME: tp_attach() 594 * 595 * CALLED FROM: 596 * tp_usrreq, PRU_ATTACH 597 * 598 * FUNCTION and ARGUMENTS: 599 * given a socket (so) and a protocol family (dom), allocate a tpcb 600 * and ref structure, initialize everything in the structures that 601 * needs to be initialized. 602 * 603 * RETURN VALUE: 604 * 0 ok 605 * EINVAL if DEBUG(X) in is on and a disaster has occurred 606 * ENOPROTOOPT if TP hasn't been configured or if the 607 * socket wasn't created with tp as its protocol 608 * EISCONN if this socket is already part of a connection 609 * ETOOMANYREFS if ran out of tp reference numbers. 610 * E* whatever error is returned from soreserve() 611 * for from the network-layer pcb allocation routine 612 * 613 * SIDE EFFECTS: 614 * 615 * NOTES: 616 */ 617 tp_attach(so, protocol) 618 struct socket *so; 619 int protocol; 620 { 621 register struct tp_pcb *tpcb; 622 int error = 0; 623 int dom = so->so_proto->pr_domain->dom_family; 624 u_long lref; 625 extern struct tp_conn_param tp_conn_param[]; 626 627 IFDEBUG(D_CONN) 628 printf("tp_attach:dom 0x%x so 0x%x ", dom, so); 629 ENDDEBUG 630 IFTRACE(D_CONN) 631 tptrace(TPPTmisc, "tp_attach:dom so", dom, so, 0, 0); 632 ENDTRACE 633 634 if (so->so_pcb != NULL) { 635 return EISCONN; /* socket already part of a connection*/ 636 } 637 638 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) 639 error = soreserve(so, tp_sendspace, tp_recvspace); 640 /* later an ioctl will allow reallocation IF still in closed state */ 641 642 if (error) 643 goto bad2; 644 645 MALLOC(tpcb, struct tp_pcb *, sizeof(*tpcb), M_PCB, M_NOWAIT); 646 if (tpcb == NULL) { 647 error = ENOBUFS; 648 goto bad2; 649 } 650 bzero( (caddr_t)tpcb, sizeof (struct tp_pcb) ); 651 652 if ( ((lref = tp_getref(tpcb)) & TP_ENOREF) != 0 ) { 653 error = ETOOMANYREFS; 654 goto bad3; 655 } 656 tpcb->tp_lref = lref; 657 tpcb->tp_sock = so; 658 tpcb->tp_domain = dom; 659 /* tpcb->tp_proto = protocol; someday maybe? */ 660 if (protocol && protocol<ISOPROTO_TP4) { 661 tpcb->tp_netservice = ISO_CONS; 662 tpcb->tp_snduna = (SeqNum) -1;/* kludge so the pseudo-ack from the CR/CC 663 * will generate correct fake-ack values 664 */ 665 } else { 666 tpcb->tp_netservice = (dom== AF_INET)?IN_CLNS:ISO_CLNS; 667 /* the default */ 668 } 669 tpcb->_tp_param = tp_conn_param[tpcb->tp_netservice]; 670 671 tpcb->tp_state = TP_CLOSED; 672 tpcb->tp_vers = TP_VERSION; 673 tpcb->tp_notdetached = 1; 674 675 /* Spec says default is 128 octets, 676 * that is, if the tpdusize argument never appears, use 128. 677 * As the initiator, we will always "propose" the 2048 678 * size, that is, we will put this argument in the CR 679 * always, but accept what the other side sends on the CC. 680 * If the initiator sends us something larger on a CR, 681 * we'll respond w/ this. 682 * Our maximum is 4096. See tp_chksum.c comments. 683 */ 684 tpcb->tp_cong_win = 685 tpcb->tp_l_tpdusize = 1 << tpcb->tp_tpdusize; 686 687 tpcb->tp_seqmask = TP_NML_FMT_MASK; 688 tpcb->tp_seqbit = TP_NML_FMT_BIT; 689 tpcb->tp_seqhalf = tpcb->tp_seqbit >> 1; 690 691 /* attach to a network-layer protoswitch */ 692 if ( error = tp_set_npcb(tpcb)) 693 goto bad4; 694 ASSERT( tpcb->tp_nlproto->nlp_afamily == tpcb->tp_domain); 695 696 /* nothing to do for iso case */ 697 if( dom == AF_INET ) 698 sotoinpcb(so)->inp_ppcb = (caddr_t) tpcb; 699 700 return 0; 701 702 bad4: 703 IFDEBUG(D_CONN) 704 printf("BAD4 in tp_attach, so 0x%x\n", so); 705 ENDDEBUG 706 tp_freeref(tpcb->tp_lref); 707 708 bad3: 709 IFDEBUG(D_CONN) 710 printf("BAD3 in tp_attach, so 0x%x\n", so); 711 ENDDEBUG 712 713 free((caddr_t)tpcb, M_PCB); /* never a cluster */ 714 715 bad2: 716 IFDEBUG(D_CONN) 717 printf("BAD2 in tp_attach, so 0x%x\n", so); 718 ENDDEBUG 719 so->so_pcb = 0; 720 721 /*bad:*/ 722 IFDEBUG(D_CONN) 723 printf("BAD in tp_attach, so 0x%x\n", so); 724 ENDDEBUG 725 return error; 726 } 727 728 /* 729 * NAME: tp_detach() 730 * 731 * CALLED FROM: 732 * tp.trans, on behalf of a user close request 733 * and when the reference timer goes off 734 * (if the disconnect was initiated by the protocol entity 735 * rather than by the user) 736 * 737 * FUNCTION and ARGUMENTS: 738 * remove the tpcb structure from the list of active or 739 * partially active connections, recycle all the mbufs 740 * associated with the pcb, ref structure, sockbufs, etc. 741 * Only free the ref structure if you know that a ref timer 742 * wasn't set for this tpcb. 743 * 744 * RETURNS: Nada 745 * 746 * SIDE EFFECTS: 747 * 748 * NOTES: 749 * tp_soisdisconnected() was already when this is called 750 */ 751 void 752 tp_detach(tpcb) 753 register struct tp_pcb *tpcb; 754 { 755 void tp_freeref(), tp_rsyflush(); 756 register struct socket *so = tpcb->tp_sock; 757 758 IFDEBUG(D_CONN) 759 printf("tp_detach(tpcb 0x%x, so 0x%x)\n", 760 tpcb,so); 761 ENDDEBUG 762 IFTRACE(D_CONN) 763 tptraceTPCB(TPPTmisc, "tp_detach tpcb so lsufx", 764 tpcb, so, *(u_short *)(tpcb->tp_lsuffix), 0); 765 ENDTRACE 766 767 IFDEBUG(D_CONN) 768 printf("so_snd at 0x%x so_rcv at 0x%x\n", &so->so_snd, &so->so_rcv); 769 dump_mbuf(so->so_snd.sb_mb, "so_snd at detach "); 770 printf("about to call LL detach, nlproto 0x%x, nl_detach 0x%x\n", 771 tpcb->tp_nlproto, tpcb->tp_nlproto->nlp_pcbdetach); 772 ENDDEBUG 773 774 if (tpcb->tp_Xsnd.sb_mb) { 775 printf("Unsent Xdata on detach; would panic"); 776 sbflush(&tpcb->tp_Xsnd); 777 } 778 if (tpcb->tp_ucddata) 779 m_freem(tpcb->tp_ucddata); 780 781 IFDEBUG(D_CONN) 782 printf("reassembly info cnt %d rsyq 0x%x\n", 783 tpcb->tp_rsycnt, tpcb->tp_rsyq); 784 ENDDEBUG 785 if (tpcb->tp_rsyq) 786 tp_rsyflush(tpcb); 787 788 if (tpcb->tp_next) { 789 remque(tpcb); 790 tpcb->tp_next = tpcb->tp_prev = 0; 791 } 792 tpcb->tp_notdetached = 0; 793 794 IFDEBUG(D_CONN) 795 printf("calling (...nlproto->...)(0x%x, so 0x%x)\n", 796 tpcb->tp_npcb, so); 797 printf("so 0x%x so_head 0x%x, qlen %d q0len %d qlimit %d\n", 798 so, so->so_head, 799 so->so_q0len, so->so_qlen, so->so_qlimit); 800 ENDDEBUG 801 802 (tpcb->tp_nlproto->nlp_pcbdetach)(tpcb->tp_npcb); 803 /* does an so->so_pcb = 0; sofree(so) */ 804 805 IFDEBUG(D_CONN) 806 printf("after xxx_pcbdetach\n"); 807 ENDDEBUG 808 809 if (tpcb->tp_state == TP_LISTENING) { 810 register struct tp_pcb **tt; 811 for (tt = &tp_listeners; *tt; tt = &((*tt)->tp_nextlisten)) 812 if (*tt == tpcb) 813 break; 814 if (*tt) 815 *tt = tpcb->tp_nextlisten; 816 else 817 printf("tp_detach from listen: should panic\n"); 818 } 819 if (tpcb->tp_refstate == REF_OPENING ) { 820 /* no connection existed here so no reference timer will be called */ 821 IFDEBUG(D_CONN) 822 printf("SETTING ref %d to REF_FREE\n", tpcb->tp_lref); 823 ENDDEBUG 824 825 tp_freeref(tpcb->tp_lref); 826 } 827 #ifdef TP_PERF_MEAS 828 /* 829 * Get rid of the cluster mbuf allocated for performance measurements, if 830 * there is one. Note that tpcb->tp_perf_on says nothing about whether or 831 * not a cluster mbuf was allocated, so you have to check for a pointer 832 * to one (that is, we need the TP_PERF_MEASs around the following section 833 * of code, not the IFPERFs) 834 */ 835 if (tpcb->tp_p_mbuf) { 836 register struct mbuf *m = tpcb->tp_p_mbuf; 837 struct mbuf *n; 838 IFDEBUG(D_PERF_MEAS) 839 printf("freeing tp_p_meas 0x%x ", tpcb->tp_p_meas); 840 ENDDEBUG 841 do { 842 MFREE(m, n); 843 m = n; 844 } while (n); 845 tpcb->tp_p_meas = 0; 846 tpcb->tp_p_mbuf = 0; 847 } 848 #endif TP_PERF_MEAS 849 850 IFDEBUG(D_CONN) 851 printf( "end of detach, NOT single, tpcb 0x%x\n", tpcb); 852 ENDDEBUG 853 /* free((caddr_t)tpcb, M_PCB); WHere to put this ? */ 854 } 855 856 struct que { 857 struct tp_pcb *next; 858 struct tp_pcb *prev; 859 } tp_bound_pcbs = 860 {(struct tp_pcb *)&tp_bound_pcbs, (struct tp_pcb *)&tp_bound_pcbs}; 861 862 u_short tp_unique; 863 864 tp_tselinuse(tlen, tsel, siso, reuseaddr) 865 caddr_t tsel; 866 register struct sockaddr_iso *siso; 867 { 868 struct tp_pcb *b = tp_bound_pcbs.next, *l = tp_listeners; 869 register struct tp_pcb *t; 870 871 for (;;) { 872 if (b != (struct tp_pcb *)&tp_bound_pcbs) { 873 t = b; b = t->tp_next; 874 } else if (l) { 875 t = l; l = t->tp_nextlisten; 876 } else 877 break; 878 if (tlen == t->tp_lsuffixlen && bcmp(tsel, t->tp_lsuffix, tlen) == 0) { 879 if (t->tp_flags & TPF_GENERAL_ADDR) { 880 if (siso == 0 || reuseaddr == 0) 881 return 1; 882 } else if (siso) { 883 if (siso->siso_family == t->tp_domain && 884 t->tp_nlproto->nlp_cmpnetaddr(t->tp_npcb, siso, TP_LOCAL)) 885 return 1; 886 } else if (reuseaddr == 0) 887 return 1; 888 } 889 } 890 return 0; 891 892 } 893 894 895 tp_pcbbind(tpcb, nam) 896 register struct tp_pcb *tpcb; 897 register struct mbuf *nam; 898 { 899 register struct sockaddr_iso *siso = 0; 900 int tlen = 0, wrapped = 0; 901 caddr_t tsel; 902 u_short tutil; 903 904 if (tpcb->tp_state != TP_CLOSED) 905 return (EINVAL); 906 if (nam) { 907 siso = mtod(nam, struct sockaddr_iso *); 908 switch (siso->siso_family) { 909 default: 910 return (EAFNOSUPPORT); 911 #ifdef ISO 912 case AF_ISO: 913 tlen = siso->siso_tlen; 914 tsel = TSEL(siso); 915 if (siso->siso_nlen == 0) 916 siso = 0; 917 break; 918 #endif 919 #ifdef INET 920 case AF_INET: 921 tsel = (caddr_t)&tutil; 922 if (tutil = ((struct sockaddr_in *)siso)->sin_port) { 923 tlen = 2; 924 } 925 if (((struct sockaddr_in *)siso)->sin_addr.s_addr == 0) 926 siso = 0; 927 } 928 #endif 929 } 930 if (tpcb->tp_lsuffixlen == 0) { 931 if (tlen) { 932 if (tp_tselinuse(tlen, tsel, siso, 933 tpcb->tp_sock->so_options & SO_REUSEADDR)) 934 return (EINVAL); 935 } else { 936 for (tsel = (caddr_t)&tutil, tlen = 2;;){ 937 if (tp_unique++ < ISO_PORT_RESERVED || 938 tp_unique > ISO_PORT_USERRESERVED) { 939 if (wrapped++) 940 return ESRCH; 941 tp_unique = ISO_PORT_RESERVED; 942 } 943 tutil = htons(tp_unique); 944 if (tp_tselinuse(tlen, tsel, siso, 0) == 0) 945 break; 946 } 947 if (siso) switch (siso->siso_family) { 948 #ifdef ISO 949 case AF_ISO: 950 bcopy(tsel, TSEL(siso), tlen); 951 siso->siso_tlen = tlen; 952 break; 953 #endif 954 #ifdef INET 955 case AF_INET: 956 ((struct sockaddr_in *)siso)->sin_port = tutil; 957 #endif 958 } 959 } 960 bcopy(tsel, tpcb->tp_lsuffix, (tpcb->tp_lsuffixlen = tlen)); 961 insque(tpcb, &tp_bound_pcbs); 962 } else { 963 if (tlen || siso == 0) 964 return (EINVAL); 965 } 966 if (siso == 0) { 967 tpcb->tp_flags |= TPF_GENERAL_ADDR; 968 return (0); 969 } 970 return tpcb->tp_nlproto->nlp_pcbbind(tpcb->tp_npcb, nam); 971 } 972