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.24 (Berkeley) 05/27/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_rhiwat = so->so_rcv.sb_hiwat; 660 /* tpcb->tp_proto = protocol; someday maybe? */ 661 if (protocol && protocol<ISOPROTO_TP4) { 662 tpcb->tp_netservice = ISO_CONS; 663 tpcb->tp_snduna = (SeqNum) -1;/* kludge so the pseudo-ack from the CR/CC 664 * will generate correct fake-ack values 665 */ 666 } else { 667 tpcb->tp_netservice = (dom== AF_INET)?IN_CLNS:ISO_CLNS; 668 /* the default */ 669 } 670 tpcb->_tp_param = tp_conn_param[tpcb->tp_netservice]; 671 672 tpcb->tp_state = TP_CLOSED; 673 tpcb->tp_vers = TP_VERSION; 674 tpcb->tp_notdetached = 1; 675 676 /* Spec says default is 128 octets, 677 * that is, if the tpdusize argument never appears, use 128. 678 * As the initiator, we will always "propose" the 2048 679 * size, that is, we will put this argument in the CR 680 * always, but accept what the other side sends on the CC. 681 * If the initiator sends us something larger on a CR, 682 * we'll respond w/ this. 683 * Our maximum is 4096. See tp_chksum.c comments. 684 */ 685 tpcb->tp_cong_win = 686 tpcb->tp_l_tpdusize = 1 << tpcb->tp_tpdusize; 687 688 tpcb->tp_seqmask = TP_NML_FMT_MASK; 689 tpcb->tp_seqbit = TP_NML_FMT_BIT; 690 tpcb->tp_seqhalf = tpcb->tp_seqbit >> 1; 691 692 /* attach to a network-layer protoswitch */ 693 if ( error = tp_set_npcb(tpcb)) 694 goto bad4; 695 ASSERT( tpcb->tp_nlproto->nlp_afamily == tpcb->tp_domain); 696 697 /* nothing to do for iso case */ 698 if( dom == AF_INET ) 699 sotoinpcb(so)->inp_ppcb = (caddr_t) tpcb; 700 701 return 0; 702 703 bad4: 704 IFDEBUG(D_CONN) 705 printf("BAD4 in tp_attach, so 0x%x\n", so); 706 ENDDEBUG 707 tp_freeref(tpcb->tp_lref); 708 709 bad3: 710 IFDEBUG(D_CONN) 711 printf("BAD3 in tp_attach, so 0x%x\n", so); 712 ENDDEBUG 713 714 free((caddr_t)tpcb, M_PCB); /* never a cluster */ 715 716 bad2: 717 IFDEBUG(D_CONN) 718 printf("BAD2 in tp_attach, so 0x%x\n", so); 719 ENDDEBUG 720 so->so_pcb = 0; 721 722 /*bad:*/ 723 IFDEBUG(D_CONN) 724 printf("BAD in tp_attach, so 0x%x\n", so); 725 ENDDEBUG 726 return error; 727 } 728 729 /* 730 * NAME: tp_detach() 731 * 732 * CALLED FROM: 733 * tp.trans, on behalf of a user close request 734 * and when the reference timer goes off 735 * (if the disconnect was initiated by the protocol entity 736 * rather than by the user) 737 * 738 * FUNCTION and ARGUMENTS: 739 * remove the tpcb structure from the list of active or 740 * partially active connections, recycle all the mbufs 741 * associated with the pcb, ref structure, sockbufs, etc. 742 * Only free the ref structure if you know that a ref timer 743 * wasn't set for this tpcb. 744 * 745 * RETURNS: Nada 746 * 747 * SIDE EFFECTS: 748 * 749 * NOTES: 750 * tp_soisdisconnected() was already when this is called 751 */ 752 void 753 tp_detach(tpcb) 754 register struct tp_pcb *tpcb; 755 { 756 void tp_freeref(), tp_rsyflush(); 757 register struct socket *so = tpcb->tp_sock; 758 759 IFDEBUG(D_CONN) 760 printf("tp_detach(tpcb 0x%x, so 0x%x)\n", 761 tpcb,so); 762 ENDDEBUG 763 IFTRACE(D_CONN) 764 tptraceTPCB(TPPTmisc, "tp_detach tpcb so lsufx", 765 tpcb, so, *(u_short *)(tpcb->tp_lsuffix), 0); 766 ENDTRACE 767 768 IFDEBUG(D_CONN) 769 printf("so_snd at 0x%x so_rcv at 0x%x\n", &so->so_snd, &so->so_rcv); 770 dump_mbuf(so->so_snd.sb_mb, "so_snd at detach "); 771 printf("about to call LL detach, nlproto 0x%x, nl_detach 0x%x\n", 772 tpcb->tp_nlproto, tpcb->tp_nlproto->nlp_pcbdetach); 773 ENDDEBUG 774 775 if (tpcb->tp_Xsnd.sb_mb) { 776 printf("Unsent Xdata on detach; would panic"); 777 sbflush(&tpcb->tp_Xsnd); 778 } 779 if (tpcb->tp_ucddata) 780 m_freem(tpcb->tp_ucddata); 781 782 IFDEBUG(D_CONN) 783 printf("reassembly info cnt %d rsyq 0x%x\n", 784 tpcb->tp_rsycnt, tpcb->tp_rsyq); 785 ENDDEBUG 786 if (tpcb->tp_rsyq) 787 tp_rsyflush(tpcb); 788 789 if (tpcb->tp_next) { 790 remque(tpcb); 791 tpcb->tp_next = tpcb->tp_prev = 0; 792 } 793 tpcb->tp_notdetached = 0; 794 795 IFDEBUG(D_CONN) 796 printf("calling (...nlproto->...)(0x%x, so 0x%x)\n", 797 tpcb->tp_npcb, so); 798 printf("so 0x%x so_head 0x%x, qlen %d q0len %d qlimit %d\n", 799 so, so->so_head, 800 so->so_q0len, so->so_qlen, so->so_qlimit); 801 ENDDEBUG 802 803 (tpcb->tp_nlproto->nlp_pcbdetach)(tpcb->tp_npcb); 804 /* does an so->so_pcb = 0; sofree(so) */ 805 806 IFDEBUG(D_CONN) 807 printf("after xxx_pcbdetach\n"); 808 ENDDEBUG 809 810 if (tpcb->tp_state == TP_LISTENING) { 811 register struct tp_pcb **tt; 812 for (tt = &tp_listeners; *tt; tt = &((*tt)->tp_nextlisten)) 813 if (*tt == tpcb) 814 break; 815 if (*tt) 816 *tt = tpcb->tp_nextlisten; 817 else 818 printf("tp_detach from listen: should panic\n"); 819 } 820 if (tpcb->tp_refstate == REF_OPENING ) { 821 /* no connection existed here so no reference timer will be called */ 822 IFDEBUG(D_CONN) 823 printf("SETTING ref %d to REF_FREE\n", tpcb->tp_lref); 824 ENDDEBUG 825 826 tp_freeref(tpcb->tp_lref); 827 } 828 #ifdef TP_PERF_MEAS 829 /* 830 * Get rid of the cluster mbuf allocated for performance measurements, if 831 * there is one. Note that tpcb->tp_perf_on says nothing about whether or 832 * not a cluster mbuf was allocated, so you have to check for a pointer 833 * to one (that is, we need the TP_PERF_MEASs around the following section 834 * of code, not the IFPERFs) 835 */ 836 if (tpcb->tp_p_mbuf) { 837 register struct mbuf *m = tpcb->tp_p_mbuf; 838 struct mbuf *n; 839 IFDEBUG(D_PERF_MEAS) 840 printf("freeing tp_p_meas 0x%x ", tpcb->tp_p_meas); 841 ENDDEBUG 842 do { 843 MFREE(m, n); 844 m = n; 845 } while (n); 846 tpcb->tp_p_meas = 0; 847 tpcb->tp_p_mbuf = 0; 848 } 849 #endif TP_PERF_MEAS 850 851 IFDEBUG(D_CONN) 852 printf( "end of detach, NOT single, tpcb 0x%x\n", tpcb); 853 ENDDEBUG 854 /* free((caddr_t)tpcb, M_PCB); WHere to put this ? */ 855 } 856 857 struct que { 858 struct tp_pcb *next; 859 struct tp_pcb *prev; 860 } tp_bound_pcbs = 861 {(struct tp_pcb *)&tp_bound_pcbs, (struct tp_pcb *)&tp_bound_pcbs}; 862 863 u_short tp_unique; 864 865 tp_tselinuse(tlen, tsel, siso, reuseaddr) 866 caddr_t tsel; 867 register struct sockaddr_iso *siso; 868 { 869 struct tp_pcb *b = tp_bound_pcbs.next, *l = tp_listeners; 870 register struct tp_pcb *t; 871 872 for (;;) { 873 if (b != (struct tp_pcb *)&tp_bound_pcbs) { 874 t = b; b = t->tp_next; 875 } else if (l) { 876 t = l; l = t->tp_nextlisten; 877 } else 878 break; 879 if (tlen == t->tp_lsuffixlen && bcmp(tsel, t->tp_lsuffix, tlen) == 0) { 880 if (t->tp_flags & TPF_GENERAL_ADDR) { 881 if (siso == 0 || reuseaddr == 0) 882 return 1; 883 } else if (siso) { 884 if (siso->siso_family == t->tp_domain && 885 t->tp_nlproto->nlp_cmpnetaddr(t->tp_npcb, siso, TP_LOCAL)) 886 return 1; 887 } else if (reuseaddr == 0) 888 return 1; 889 } 890 } 891 return 0; 892 893 } 894 895 896 tp_pcbbind(tpcb, nam) 897 register struct tp_pcb *tpcb; 898 register struct mbuf *nam; 899 { 900 register struct sockaddr_iso *siso = 0; 901 int tlen = 0, wrapped = 0; 902 caddr_t tsel; 903 u_short tutil; 904 905 if (tpcb->tp_state != TP_CLOSED) 906 return (EINVAL); 907 if (nam) { 908 siso = mtod(nam, struct sockaddr_iso *); 909 switch (siso->siso_family) { 910 default: 911 return (EAFNOSUPPORT); 912 #ifdef ISO 913 case AF_ISO: 914 tlen = siso->siso_tlen; 915 tsel = TSEL(siso); 916 if (siso->siso_nlen == 0) 917 siso = 0; 918 break; 919 #endif 920 #ifdef INET 921 case AF_INET: 922 tsel = (caddr_t)&tutil; 923 if (tutil = ((struct sockaddr_in *)siso)->sin_port) { 924 tlen = 2; 925 } 926 if (((struct sockaddr_in *)siso)->sin_addr.s_addr == 0) 927 siso = 0; 928 } 929 #endif 930 } 931 if (tpcb->tp_lsuffixlen == 0) { 932 if (tlen) { 933 if (tp_tselinuse(tlen, tsel, siso, 934 tpcb->tp_sock->so_options & SO_REUSEADDR)) 935 return (EINVAL); 936 } else { 937 for (tsel = (caddr_t)&tutil, tlen = 2;;){ 938 if (tp_unique++ < ISO_PORT_RESERVED || 939 tp_unique > ISO_PORT_USERRESERVED) { 940 if (wrapped++) 941 return ESRCH; 942 tp_unique = ISO_PORT_RESERVED; 943 } 944 tutil = htons(tp_unique); 945 if (tp_tselinuse(tlen, tsel, siso, 0) == 0) 946 break; 947 } 948 if (siso) switch (siso->siso_family) { 949 #ifdef ISO 950 case AF_ISO: 951 bcopy(tsel, TSEL(siso), tlen); 952 siso->siso_tlen = tlen; 953 break; 954 #endif 955 #ifdef INET 956 case AF_INET: 957 ((struct sockaddr_in *)siso)->sin_port = tutil; 958 #endif 959 } 960 } 961 bcopy(tsel, tpcb->tp_lsuffix, (tpcb->tp_lsuffixlen = tlen)); 962 insque(tpcb, &tp_bound_pcbs); 963 } else { 964 if (tlen || siso == 0) 965 return (EINVAL); 966 } 967 if (siso == 0) { 968 tpcb->tp_flags |= TPF_GENERAL_ADDR; 969 return (0); 970 } 971 return tpcb->tp_nlproto->nlp_pcbbind(tpcb->tp_npcb, nam); 972 } 973