149268Sbostic /*- 249268Sbostic * Copyright (c) 1991 The Regents of the University of California. 349268Sbostic * All rights reserved. 449268Sbostic * 549268Sbostic * %sccs.include.redist.c% 649268Sbostic * 7*50904Ssklower * @(#)tp_pcb.c 7.15 (Berkeley) 08/28/91 849268Sbostic */ 949268Sbostic 1036408Ssklower /*********************************************************** 1139196Ssklower Copyright IBM Corporation 1987 1236408Ssklower 1336408Ssklower All Rights Reserved 1436408Ssklower 1536408Ssklower Permission to use, copy, modify, and distribute this software and its 1636408Ssklower documentation for any purpose and without fee is hereby granted, 1736408Ssklower provided that the above copyright notice appear in all copies and that 1836408Ssklower both that copyright notice and this permission notice appear in 1936408Ssklower supporting documentation, and that the name of IBM not be 2036408Ssklower used in advertising or publicity pertaining to distribution of the 2136408Ssklower software without specific, written prior permission. 2236408Ssklower 2336408Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 2436408Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 2536408Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 2636408Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 2736408Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 2836408Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 2936408Ssklower SOFTWARE. 3036408Ssklower 3136408Ssklower ******************************************************************/ 3236408Ssklower 3336408Ssklower /* 3436408Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 3536408Ssklower */ 3636408Ssklower /* 3736408Ssklower * ARGO TP 3836408Ssklower * 3936408Ssklower * $Header: tp_pcb.c,v 5.4 88/11/18 17:28:24 nhall Exp $ 4036408Ssklower * $Source: /usr/argo/sys/netiso/RCS/tp_pcb.c,v $ 4136408Ssklower * 4236408Ssklower * 4336408Ssklower * This is the initialization and cleanup stuff - 4436408Ssklower * for the tp machine in general as well as for the individual pcbs. 4536408Ssklower * tp_init() is called at system startup. tp_attach() and tp_getref() are 4636408Ssklower * called when a socket is created. tp_detach() and tp_freeref() 4736408Ssklower * are called during the closing stage and/or when the reference timer 4836408Ssklower * goes off. 4936408Ssklower * tp_soisdisconnecting() and tp_soisdisconnected() are tp-specific 5036408Ssklower * versions of soisconnect* 5136408Ssklower * and are called (obviously) during the closing phase. 5236408Ssklower * 5336408Ssklower */ 5436408Ssklower 5536408Ssklower #include "param.h" 5650648Ssklower #include "systm.h" 5736408Ssklower #include "mbuf.h" 5836408Ssklower #include "socket.h" 5936408Ssklower #include "socketvar.h" 6050648Ssklower #include "domain.h" 6136408Ssklower #include "protosw.h" 6236408Ssklower #include "errno.h" 6336408Ssklower #include "time.h" 6437469Ssklower #include "argo_debug.h" 6537469Ssklower #include "tp_param.h" 6637469Ssklower #include "tp_timer.h" 6737469Ssklower #include "tp_ip.h" 6837469Ssklower #include "tp_stat.h" 6937469Ssklower #include "tp_pcb.h" 7037469Ssklower #include "tp_tpdu.h" 7137469Ssklower #include "tp_trace.h" 7237469Ssklower #include "tp_meas.h" 7337469Ssklower #include "tp_seq.h" 7437469Ssklower #include "tp_clnp.h" 7536408Ssklower 7636408Ssklower struct tp_param tp_param = { 7736408Ssklower 1, /* configured */ 7836408Ssklower }; 7936408Ssklower 8036408Ssklower /* ticks are in units of: 8136408Ssklower * 500 nano-fortnights ;-) or 8236408Ssklower * 500 ms or 8336408Ssklower * 1/2 second 8436408Ssklower */ 8536408Ssklower 8636408Ssklower struct tp_conn_param tp_conn_param[] = { 8736408Ssklower /* ISO_CLNS: TP4 CONNECTION LESS */ 8836408Ssklower { 8936408Ssklower TP_NRETRANS, /* short p_Nretrans; */ 9036408Ssklower 20, /* 10 sec */ /* short p_dr_ticks; */ 9136408Ssklower 9236408Ssklower 20, /* 10 sec */ /* short p_cc_ticks; */ 9336408Ssklower 20, /* 10 sec */ /* short p_dt_ticks; */ 9436408Ssklower 9536408Ssklower 40, /* 20 sec */ /* short p_x_ticks; */ 9636408Ssklower 80, /* 40 sec */ /* short p_cr_ticks;*/ 9736408Ssklower 9836408Ssklower 240, /* 2 min */ /* short p_keepalive_ticks;*/ 9936408Ssklower 10, /* 5 sec */ /* short p_sendack_ticks; */ 10036408Ssklower 10136408Ssklower 600, /* 5 min */ /* short p_ref_ticks; */ 10236408Ssklower 360, /* 3 min */ /* short p_inact_ticks; */ 10336408Ssklower 10436408Ssklower (short) 100, /* short p_lcdtfract */ 10536408Ssklower (short) TP_SOCKBUFSIZE, /* short p_winsize */ 10636408Ssklower TP_TPDUSIZE, /* u_char p_tpdusize */ 10736408Ssklower 10836408Ssklower TPACK_WINDOW, /* 4 bits p_ack_strat */ 10936408Ssklower TPRX_USE_CW | TPRX_FASTSTART, 11036408Ssklower /* 4 bits p_rx_strat*/ 11136408Ssklower TP_CLASS_4 | TP_CLASS_0,/* 5 bits p_class */ 11236408Ssklower 1, /* 1 bit xtd format */ 11336408Ssklower 1, /* 1 bit xpd service */ 11436408Ssklower 1, /* 1 bit use_checksum */ 11536408Ssklower 0, /* 1 bit use net xpd */ 11636408Ssklower 0, /* 1 bit use rcc */ 11736408Ssklower 0, /* 1 bit use efc */ 11838841Ssklower 1, /* no disc indications */ 11936408Ssklower 0, /* don't change params */ 12036408Ssklower ISO_CLNS, /* p_netservice */ 12136408Ssklower }, 12236408Ssklower /* IN_CLNS: TP4 CONNECTION LESS */ 12336408Ssklower { 12436408Ssklower TP_NRETRANS, /* short p_Nretrans; */ 12536408Ssklower 20, /* 10 sec */ /* short p_dr_ticks; */ 12636408Ssklower 12736408Ssklower 20, /* 10 sec */ /* short p_cc_ticks; */ 12836408Ssklower 20, /* 10 sec */ /* short p_dt_ticks; */ 12936408Ssklower 13036408Ssklower 40, /* 20 sec */ /* short p_x_ticks; */ 13136408Ssklower 80, /* 40 sec */ /* short p_cr_ticks;*/ 13236408Ssklower 13336408Ssklower 240, /* 2 min */ /* short p_keepalive_ticks;*/ 13436408Ssklower 10, /* 5 sec */ /* short p_sendack_ticks; */ 13536408Ssklower 13636408Ssklower 600, /* 5 min */ /* short p_ref_ticks; */ 13736408Ssklower 360, /* 3 min */ /* short p_inact_ticks; */ 13836408Ssklower 13936408Ssklower (short) 100, /* short p_lcdtfract */ 14036408Ssklower (short) TP_SOCKBUFSIZE, /* short p_winsize */ 14136408Ssklower TP_TPDUSIZE, /* u_char p_tpdusize */ 14236408Ssklower 14336408Ssklower TPACK_WINDOW, /* 4 bits p_ack_strat */ 14436408Ssklower TPRX_USE_CW | TPRX_FASTSTART, 14536408Ssklower /* 4 bits p_rx_strat*/ 14636408Ssklower TP_CLASS_4, /* 5 bits p_class */ 14736408Ssklower 1, /* 1 bit xtd format */ 14836408Ssklower 1, /* 1 bit xpd service */ 14936408Ssklower 1, /* 1 bit use_checksum */ 15036408Ssklower 0, /* 1 bit use net xpd */ 15136408Ssklower 0, /* 1 bit use rcc */ 15236408Ssklower 0, /* 1 bit use efc */ 15338841Ssklower 1, /* no disc indications */ 15436408Ssklower 0, /* don't change params */ 15536408Ssklower IN_CLNS, /* p_netservice */ 15636408Ssklower }, 15736408Ssklower /* ISO_CONS: TP0 CONNECTION MODE */ 15836408Ssklower { 15936408Ssklower TP_NRETRANS, /* short p_Nretrans; */ 16036408Ssklower 0, /* n/a */ /* short p_dr_ticks; */ 16136408Ssklower 16236408Ssklower 40, /* 20 sec */ /* short p_cc_ticks; */ 16336408Ssklower 0, /* n/a */ /* short p_dt_ticks; */ 16436408Ssklower 16536408Ssklower 0, /* n/a */ /* short p_x_ticks; */ 16636408Ssklower 360, /* 3 min */ /* short p_cr_ticks;*/ 16736408Ssklower 16836408Ssklower 0, /* n/a */ /* short p_keepalive_ticks;*/ 16936408Ssklower 0, /* n/a */ /* short p_sendack_ticks; */ 17036408Ssklower 17136408Ssklower 600, /* for cr/cc to clear *//* short p_ref_ticks; */ 17236408Ssklower 0, /* n/a */ /* short p_inact_ticks; */ 17336408Ssklower 17436408Ssklower /* Use tp4 defaults just in case the user changes ONLY 17536408Ssklower * the class 17636408Ssklower */ 17736408Ssklower (short) 100, /* short p_lcdtfract */ 17836408Ssklower (short) TP0_SOCKBUFSIZE, /* short p_winsize */ 17936408Ssklower TP0_TPDUSIZE, /* 8 bits p_tpdusize */ 18036408Ssklower 18136408Ssklower 0, /* 4 bits p_ack_strat */ 18236408Ssklower 0, /* 4 bits p_rx_strat*/ 18336408Ssklower TP_CLASS_0, /* 5 bits p_class */ 18436408Ssklower 0, /* 1 bit xtd format */ 18536408Ssklower 0, /* 1 bit xpd service */ 18636408Ssklower 0, /* 1 bit use_checksum */ 18736408Ssklower 0, /* 1 bit use net xpd */ 18836408Ssklower 0, /* 1 bit use rcc */ 18936408Ssklower 0, /* 1 bit use efc */ 19036408Ssklower 0, /* no disc indications */ 19136408Ssklower 0, /* don't change params */ 19236408Ssklower ISO_CONS, /* p_netservice */ 19336408Ssklower }, 19436408Ssklower /* ISO_COSNS: TP4 CONNECTION LESS SERVICE over CONSNS */ 19536408Ssklower { 19636408Ssklower TP_NRETRANS, /* short p_Nretrans; */ 19736408Ssklower 40, /* 20 sec */ /* short p_dr_ticks; */ 19836408Ssklower 19936408Ssklower 40, /* 20 sec */ /* short p_cc_ticks; */ 20036408Ssklower 80, /* 40 sec */ /* short p_dt_ticks; */ 20136408Ssklower 20236408Ssklower 120, /* 1 min */ /* short p_x_ticks; */ 20336408Ssklower 360, /* 3 min */ /* short p_cr_ticks;*/ 20436408Ssklower 20536408Ssklower 360, /* 3 min */ /* short p_keepalive_ticks;*/ 20636408Ssklower 20, /* 10 sec */ /* short p_sendack_ticks; */ 20736408Ssklower 20836408Ssklower 600, /* 5 min */ /* short p_ref_ticks; */ 20936408Ssklower 480, /* 4 min */ /* short p_inact_ticks; */ 21036408Ssklower 21136408Ssklower (short) 100, /* short p_lcdtfract */ 21236408Ssklower (short) TP0_SOCKBUFSIZE, /* short p_winsize */ 21336408Ssklower TP0_TPDUSIZE, /* u_char p_tpdusize */ 21436408Ssklower 21536408Ssklower TPACK_WINDOW, /* 4 bits p_ack_strat */ 21636408Ssklower TPRX_USE_CW , /* No fast start */ 21736408Ssklower /* 4 bits p_rx_strat*/ 21836408Ssklower TP_CLASS_4 | TP_CLASS_0,/* 5 bits p_class */ 21936408Ssklower 0, /* 1 bit xtd format */ 22036408Ssklower 1, /* 1 bit xpd service */ 22136408Ssklower 1, /* 1 bit use_checksum */ 22236408Ssklower 0, /* 1 bit use net xpd */ 22336408Ssklower 0, /* 1 bit use rcc */ 22436408Ssklower 0, /* 1 bit use efc */ 22536408Ssklower 0, /* no disc indications */ 22636408Ssklower 0, /* don't change params */ 22736408Ssklower ISO_COSNS, /* p_netservice */ 22836408Ssklower }, 22936408Ssklower }; 23036408Ssklower 23136408Ssklower #ifdef INET 23236408Ssklower int in_putnetaddr(); 23336408Ssklower int in_getnetaddr(); 23444423Ssklower int in_cmpnetaddr(); 23536408Ssklower int in_putsufx(); 23636408Ssklower int in_getsufx(); 23736408Ssklower int in_recycle_tsuffix(); 23836408Ssklower int tpip_mtu(); 23936408Ssklower int in_pcbbind(); 24036408Ssklower int in_pcbconnect(); 24136408Ssklower int in_pcbdisconnect(); 24236408Ssklower int in_pcbdetach(); 24336408Ssklower int in_pcballoc(); 24436408Ssklower int tpip_output(); 24536408Ssklower int tpip_output_dg(); 24636408Ssklower struct inpcb tp_inpcb; 24736408Ssklower #endif INET 24836408Ssklower #ifdef ISO 24936408Ssklower int iso_putnetaddr(); 25036408Ssklower int iso_getnetaddr(); 25144423Ssklower int iso_cmpnetaddr(); 25236408Ssklower int iso_putsufx(); 25336408Ssklower int iso_getsufx(); 25436408Ssklower int iso_recycle_tsuffix(); 25536408Ssklower int tpclnp_mtu(); 25636408Ssklower int iso_pcbbind(); 25736408Ssklower int iso_pcbconnect(); 25836408Ssklower int iso_pcbdisconnect(); 25936408Ssklower int iso_pcbdetach(); 26036408Ssklower int iso_pcballoc(); 26136408Ssklower int tpclnp_output(); 26236408Ssklower int tpclnp_output_dg(); 26336408Ssklower int iso_nlctloutput(); 26436408Ssklower struct isopcb tp_isopcb; 26536408Ssklower #endif ISO 26645900Ssklower #ifdef TPCONS 26736408Ssklower int iso_putnetaddr(); 26836408Ssklower int iso_getnetaddr(); 26944423Ssklower int iso_cmpnetaddr(); 27036408Ssklower int iso_putsufx(); 27136408Ssklower int iso_getsufx(); 27236408Ssklower int iso_recycle_tsuffix(); 27336408Ssklower int iso_pcbbind(); 27445900Ssklower int tpcons_pcbconnect(); 27549258Ssklower int tpclnp_mtu(); 27636408Ssklower int iso_pcbdisconnect(); 27736408Ssklower int iso_pcbdetach(); 27836408Ssklower int iso_pcballoc(); 27936408Ssklower int tpcons_output(); 28036408Ssklower struct isopcb tp_isopcb; 28145900Ssklower #endif TPCONS 28236408Ssklower 28337469Ssklower 28436408Ssklower struct nl_protosw nl_protosw[] = { 28536408Ssklower /* ISO_CLNS */ 28636408Ssklower #ifdef ISO 28744423Ssklower { AF_ISO, iso_putnetaddr, iso_getnetaddr, iso_cmpnetaddr, 28836408Ssklower iso_putsufx, iso_getsufx, 28936408Ssklower iso_recycle_tsuffix, 29036408Ssklower tpclnp_mtu, iso_pcbbind, iso_pcbconnect, 29136408Ssklower iso_pcbdisconnect, iso_pcbdetach, 29236408Ssklower iso_pcballoc, 29336408Ssklower tpclnp_output, tpclnp_output_dg, iso_nlctloutput, 29436408Ssklower (caddr_t) &tp_isopcb, 29536408Ssklower }, 29637469Ssklower #else 29737469Ssklower { 0 }, 29836408Ssklower #endif ISO 29936408Ssklower /* IN_CLNS */ 30036408Ssklower #ifdef INET 30144423Ssklower { AF_INET, in_putnetaddr, in_getnetaddr, in_cmpnetaddr, 30236408Ssklower in_putsufx, in_getsufx, 30336408Ssklower in_recycle_tsuffix, 30436408Ssklower tpip_mtu, in_pcbbind, in_pcbconnect, 30536408Ssklower in_pcbdisconnect, in_pcbdetach, 30636408Ssklower in_pcballoc, 30736408Ssklower tpip_output, tpip_output_dg, /* nl_ctloutput */ NULL, 30836408Ssklower (caddr_t) &tp_inpcb, 30936408Ssklower }, 31037469Ssklower #else 31137469Ssklower { 0 }, 31236408Ssklower #endif INET 31336408Ssklower /* ISO_CONS */ 31445900Ssklower #if defined(ISO) && defined(TPCONS) 31544423Ssklower { AF_ISO, iso_putnetaddr, iso_getnetaddr, iso_cmpnetaddr, 31636408Ssklower iso_putsufx, iso_getsufx, 31736408Ssklower iso_recycle_tsuffix, 31849258Ssklower tpclnp_mtu, iso_pcbbind, tpcons_pcbconnect, 31936408Ssklower iso_pcbdisconnect, iso_pcbdetach, 32036408Ssklower iso_pcballoc, 32145900Ssklower tpcons_output, tpcons_output, iso_nlctloutput, 32236408Ssklower (caddr_t) &tp_isopcb, 32336408Ssklower }, 32437469Ssklower #else 32537469Ssklower { 0 }, 32637469Ssklower #endif ISO_CONS 32737469Ssklower /* End of protosw marker */ 32837469Ssklower { 0 } 32936408Ssklower }; 33036408Ssklower 33136408Ssklower /* 33236408Ssklower * NAME: tp_init() 33336408Ssklower * 33436408Ssklower * CALLED FROM: 33536408Ssklower * autoconf through the protosw structure 33636408Ssklower * 33736408Ssklower * FUNCTION: 33836408Ssklower * initialize tp machine 33936408Ssklower * 34036408Ssklower * RETURNS: Nada 34136408Ssklower * 34236408Ssklower * SIDE EFFECTS: 34336408Ssklower * 34436408Ssklower * NOTES: 34536408Ssklower */ 34637469Ssklower int 34736408Ssklower tp_init() 34836408Ssklower { 34936408Ssklower static int init_done=0; 35036408Ssklower void tp_timerinit(); 35136408Ssklower 35236408Ssklower if (init_done++) 35337469Ssklower return 0; 35436408Ssklower 35536408Ssklower 35636408Ssklower /* FOR INET */ 35736408Ssklower tp_inpcb.inp_next = tp_inpcb.inp_prev = &tp_inpcb; 35836408Ssklower /* FOR ISO */ 35936408Ssklower tp_isopcb.isop_next = tp_isopcb.isop_prev = &tp_isopcb; 36036408Ssklower 36139923Ssklower tp_start_win = 2; 36239923Ssklower 36336408Ssklower tp_timerinit(); 36436408Ssklower bzero((caddr_t)&tp_stat, sizeof(struct tp_stat)); 36537469Ssklower return 0; 36636408Ssklower } 36736408Ssklower 36836408Ssklower /* 36936408Ssklower * NAME: tp_soisdisconnecting() 37036408Ssklower * 37136408Ssklower * CALLED FROM: 37236408Ssklower * tp.trans 37336408Ssklower * 37436408Ssklower * FUNCTION and ARGUMENTS: 37536408Ssklower * Set state of the socket (so) to reflect that fact that we're disconnectING 37636408Ssklower * 37736408Ssklower * RETURNS: Nada 37836408Ssklower * 37936408Ssklower * SIDE EFFECTS: 38036408Ssklower * 38136408Ssklower * NOTES: 38236408Ssklower * This differs from the regular soisdisconnecting() in that the latter 38336408Ssklower * also sets the SS_CANTRECVMORE and SS_CANTSENDMORE flags. 38436408Ssklower * We don't want to set those flags because those flags will cause 38536408Ssklower * a SIGPIPE to be delivered in sosend() and we don't like that. 38636408Ssklower * If anyone else is sleeping on this socket, wake 'em up. 38736408Ssklower */ 38836408Ssklower void 38936408Ssklower tp_soisdisconnecting(so) 39036408Ssklower register struct socket *so; 39136408Ssklower { 39238841Ssklower soisdisconnecting(so); 39338841Ssklower so->so_state &= ~SS_CANTSENDMORE; 39436408Ssklower IFPERF(sototpcb(so)) 39536408Ssklower register struct tp_pcb *tpcb = sototpcb(so); 39636408Ssklower u_int fsufx, lsufx; 39736408Ssklower 39837469Ssklower bcopy ((caddr_t)tpcb->tp_fsuffix, (caddr_t)&fsufx, sizeof(u_int) ); 39937469Ssklower bcopy ((caddr_t)tpcb->tp_lsuffix, (caddr_t)&lsufx, sizeof(u_int) ); 40036408Ssklower 40137469Ssklower tpmeas(tpcb->tp_lref, TPtime_close, &time, fsufx, lsufx, tpcb->tp_fref); 40236408Ssklower tpcb->tp_perf_on = 0; /* turn perf off */ 40336408Ssklower ENDPERF 40436408Ssklower } 40536408Ssklower 40636408Ssklower 40736408Ssklower /* 40836408Ssklower * NAME: tp_soisdisconnected() 40936408Ssklower * 41036408Ssklower * CALLED FROM: 41136408Ssklower * tp.trans 41236408Ssklower * 41336408Ssklower * FUNCTION and ARGUMENTS: 41436408Ssklower * Set state of the socket (so) to reflect that fact that we're disconnectED 41536408Ssklower * Set the state of the reference structure to closed, and 41636408Ssklower * recycle the suffix. 41736408Ssklower * Start a reference timer. 41836408Ssklower * 41936408Ssklower * RETURNS: Nada 42036408Ssklower * 42136408Ssklower * SIDE EFFECTS: 42236408Ssklower * 42336408Ssklower * NOTES: 42436408Ssklower * This differs from the regular soisdisconnected() in that the latter 42536408Ssklower * also sets the SS_CANTRECVMORE and SS_CANTSENDMORE flags. 42636408Ssklower * We don't want to set those flags because those flags will cause 42736408Ssklower * a SIGPIPE to be delivered in sosend() and we don't like that. 42836408Ssklower * If anyone else is sleeping on this socket, wake 'em up. 42936408Ssklower */ 43036408Ssklower void 43136408Ssklower tp_soisdisconnected(tpcb) 43236408Ssklower register struct tp_pcb *tpcb; 43336408Ssklower { 43436408Ssklower register struct socket *so = tpcb->tp_sock; 43536408Ssklower 43638841Ssklower soisdisconnecting(so); 43738841Ssklower so->so_state &= ~SS_CANTSENDMORE; 43836408Ssklower IFPERF(sototpcb(so)) 43937469Ssklower register struct tp_pcb *ttpcb = sototpcb(so); 44036408Ssklower u_int fsufx, lsufx; 44136408Ssklower 44236408Ssklower /* CHOKE */ 44337469Ssklower bcopy ((caddr_t)ttpcb->tp_fsuffix, (caddr_t)&fsufx, sizeof(u_int) ); 44437469Ssklower bcopy ((caddr_t)ttpcb->tp_lsuffix, (caddr_t)&lsufx, sizeof(u_int) ); 44536408Ssklower 44637469Ssklower tpmeas(ttpcb->tp_lref, TPtime_close, 44737469Ssklower &time, &lsufx, &fsufx, ttpcb->tp_fref); 44836408Ssklower tpcb->tp_perf_on = 0; /* turn perf off */ 44936408Ssklower ENDPERF 45036408Ssklower 45136408Ssklower tpcb->tp_refp->tpr_state = REF_FROZEN; 45236408Ssklower tp_recycle_tsuffix( tpcb ); 45336408Ssklower tp_etimeout(tpcb->tp_refp, TM_reference, 0,0,0, (int)tpcb->tp_refer_ticks); 45436408Ssklower } 45536408Ssklower 45636408Ssklower int tp_maxrefopen; /* highest reference # of the set of open tp connections */ 45736408Ssklower 45836408Ssklower /* 45936408Ssklower * NAME: tp_freeref() 46036408Ssklower * 46136408Ssklower * CALLED FROM: 46236408Ssklower * tp.trans when the reference timer goes off, and 46336408Ssklower * from tp_attach() and tp_detach() when a tpcb is partially set up but not 46436408Ssklower * set up enough to have a ref timer set for it, and it's discarded 46536408Ssklower * due to some sort of error or an early close() 46636408Ssklower * 46736408Ssklower * FUNCTION and ARGUMENTS: 46836408Ssklower * Frees the reference represented by (r) for re-use. 46936408Ssklower * 47036408Ssklower * RETURNS: Nothing 47136408Ssklower * 47236408Ssklower * SIDE EFFECTS: 47336408Ssklower * 47436408Ssklower * NOTES: better be called at clock priority !!!!! 47536408Ssklower */ 47636408Ssklower void 47736408Ssklower tp_freeref(r) 47836408Ssklower register struct tp_ref *r; 47936408Ssklower { 48036408Ssklower IFDEBUG(D_TIMER) 48136408Ssklower printf("tp_freeref called for ref %d maxrefopen %d\n", 48236408Ssklower r - tp_ref, tp_maxrefopen); 48336408Ssklower ENDDEBUG 48436408Ssklower IFTRACE(D_TIMER) 48536408Ssklower tptrace(TPPTmisc, "tp_freeref ref tp_maxrefopen", 48636408Ssklower r - tp_ref, tp_maxrefopen, 0, 0); 48736408Ssklower ENDTRACE 48836408Ssklower r->tpr_state = REF_FREE; 48936408Ssklower IFDEBUG(D_CONN) 49036408Ssklower printf("tp_freeref: CLEARING tpr_pcb 0x%x\n", r->tpr_pcb); 49136408Ssklower ENDDEBUG 49236408Ssklower r->tpr_pcb = (struct tp_pcb *)0; 49336408Ssklower 49436408Ssklower r = &tp_ref[tp_maxrefopen]; 49536408Ssklower 49636408Ssklower while( tp_maxrefopen > 0 ) { 49736408Ssklower if(r->tpr_state ) 49836408Ssklower break; 49936408Ssklower tp_maxrefopen--; 50036408Ssklower r--; 50136408Ssklower } 50236408Ssklower IFDEBUG(D_TIMER) 50336408Ssklower printf("tp_freeref ends w/ maxrefopen %d\n", tp_maxrefopen); 50436408Ssklower ENDDEBUG 50536408Ssklower } 50636408Ssklower 50736408Ssklower /* 50836408Ssklower * NAME: tp_getref() 50936408Ssklower * 51036408Ssklower * CALLED FROM: 51136408Ssklower * tp_attach() 51236408Ssklower * 51336408Ssklower * FUNCTION and ARGUMENTS: 51436408Ssklower * obtains the next free reference and allocates the appropriate 51536408Ssklower * ref structure, links that structure to (tpcb) 51636408Ssklower * 51736408Ssklower * RETURN VALUE: 51836408Ssklower * a reference number 51936408Ssklower * or TP_ENOREF 52036408Ssklower * 52136408Ssklower * SIDE EFFECTS: 52236408Ssklower * 52336408Ssklower * NOTES: 52436408Ssklower */ 52536408Ssklower static RefNum 52636408Ssklower tp_getref(tpcb) 52736408Ssklower register struct tp_pcb *tpcb; 52836408Ssklower { 52948733Ssklower register struct tp_ref *r = tp_ref; /* tp_ref[0] is never used */ 53036408Ssklower register int i=1; 53136408Ssklower 53236408Ssklower 53348733Ssklower while ((++r)->tpr_state != REF_FREE) { 53448733Ssklower if (++i == N_TPREF) 53536408Ssklower return TP_ENOREF; 53636408Ssklower } 53736408Ssklower r->tpr_state = REF_OPENING; 53836408Ssklower if (tp_maxrefopen < i) 53936408Ssklower tp_maxrefopen = i; 54036408Ssklower r->tpr_pcb = tpcb; 54136408Ssklower tpcb->tp_refp = r; 54236408Ssklower 54336408Ssklower return i; 54436408Ssklower } 54536408Ssklower 54636408Ssklower /* 54750648Ssklower * NAME: tp_set_npcb() 54850648Ssklower * 54950648Ssklower * CALLED FROM: 55050648Ssklower * tp_attach(), tp_route_to() 55150648Ssklower * 55250648Ssklower * FUNCTION and ARGUMENTS: 55350648Ssklower * given a tpcb, allocate an appropriate lower-lever npcb, freeing 55450648Ssklower * any old ones that might need re-assigning. 55550648Ssklower */ 55650648Ssklower tp_set_npcb(tpcb) 55750648Ssklower register struct tp_pcb *tpcb; 55850648Ssklower { 55950648Ssklower register struct socket *so = tpcb->tp_sock; 56050648Ssklower int error; 56150648Ssklower 56250648Ssklower if (tpcb->tp_nlproto && tpcb->tp_npcb) { 56350648Ssklower short so_state = so->so_state; 56450648Ssklower so->so_state &= ~SS_NOFDREF; 56550648Ssklower tpcb->tp_nlproto->nlp_pcbdetach(tpcb->tp_npcb); 56650648Ssklower so->so_state = so_state; 56750648Ssklower } 56850648Ssklower tpcb->tp_nlproto = &nl_protosw[tpcb->tp_netservice]; 56950648Ssklower /* xx_pcballoc sets so_pcb */ 57050648Ssklower error = tpcb->tp_nlproto->nlp_pcballoc(so, tpcb->tp_nlproto->nlp_pcblist); 57150648Ssklower tpcb->tp_npcb = so->so_pcb; 57250648Ssklower so->so_pcb = (caddr_t)tpcb; 57350648Ssklower return (error); 57450648Ssklower } 57550648Ssklower /* 57636408Ssklower * NAME: tp_attach() 57736408Ssklower * 57836408Ssklower * CALLED FROM: 57936408Ssklower * tp_usrreq, PRU_ATTACH 58036408Ssklower * 58136408Ssklower * FUNCTION and ARGUMENTS: 58236408Ssklower * given a socket (so) and a protocol family (dom), allocate a tpcb 58336408Ssklower * and ref structure, initialize everything in the structures that 58436408Ssklower * needs to be initialized. 58536408Ssklower * 58636408Ssklower * RETURN VALUE: 58736408Ssklower * 0 ok 58836408Ssklower * EINVAL if DEBUG(X) in is on and a disaster has occurred 58936408Ssklower * ENOPROTOOPT if TP hasn't been configured or if the 59036408Ssklower * socket wasn't created with tp as its protocol 59136408Ssklower * EISCONN if this socket is already part of a connection 59236408Ssklower * ETOOMANYREFS if ran out of tp reference numbers. 59336408Ssklower * E* whatever error is returned from soreserve() 59436408Ssklower * for from the network-layer pcb allocation routine 59536408Ssklower * 59636408Ssklower * SIDE EFFECTS: 59736408Ssklower * 59836408Ssklower * NOTES: 59936408Ssklower */ 60050648Ssklower tp_attach(so, protocol) 60150648Ssklower struct socket *so; 60250648Ssklower int protocol; 60336408Ssklower { 60436408Ssklower register struct tp_pcb *tpcb; 60536408Ssklower int error; 60650648Ssklower int dom = so->so_proto->pr_domain->dom_family; 60736408Ssklower extern struct tp_conn_param tp_conn_param[]; 60836408Ssklower 60936408Ssklower IFDEBUG(D_CONN) 61036408Ssklower printf("tp_attach:dom 0x%x so 0x%x ", dom, so); 61136408Ssklower ENDDEBUG 61236408Ssklower IFTRACE(D_CONN) 61336408Ssklower tptrace(TPPTmisc, "tp_attach:dom so", dom, so, 0, 0); 61436408Ssklower ENDTRACE 61536408Ssklower if ( ! tp_param.tpp_configed ) { 61636408Ssklower error = ENOPROTOOPT; /* protocol not available */ 61736408Ssklower goto bad2; 61836408Ssklower } 61936408Ssklower 62036408Ssklower if (so->so_pcb != NULL) { 62136408Ssklower return EISCONN; /* socket already part of a connection*/ 62236408Ssklower } 62336408Ssklower 62436408Ssklower error = soreserve(so, TP_SOCKBUFSIZE, TP_SOCKBUFSIZE); 62536408Ssklower /* later an ioctl will allow reallocation IF still in closed state */ 62636408Ssklower 62736408Ssklower if (error) 62836408Ssklower goto bad2; 62936408Ssklower 63037469Ssklower MALLOC(tpcb, struct tp_pcb *, sizeof(*tpcb), M_PCB, M_NOWAIT); 63137469Ssklower if (tpcb == NULL) { 63236408Ssklower error = ENOBUFS; 63336408Ssklower goto bad2; 63436408Ssklower } 63536408Ssklower bzero( (caddr_t)tpcb, sizeof (struct tp_pcb) ); 63636408Ssklower 63736408Ssklower if ( ((tpcb->tp_lref = tp_getref(tpcb)) & TP_ENOREF) != 0 ) { 63836408Ssklower error = ETOOMANYREFS; 63936408Ssklower goto bad3; 64036408Ssklower } 64136408Ssklower tpcb->tp_sock = so; 64236408Ssklower tpcb->tp_domain = dom; 64350648Ssklower /* tpcb->tp_proto = protocol; someday maybe? */ 64450648Ssklower if (protocol && protocol<ISOPROTO_TP4) { 64536408Ssklower tpcb->tp_netservice = ISO_CONS; 64636408Ssklower tpcb->tp_snduna = (SeqNum) -1;/* kludge so the pseudo-ack from the CR/CC 64736408Ssklower * will generate correct fake-ack values 64836408Ssklower */ 64936408Ssklower } else { 65036408Ssklower tpcb->tp_netservice = (dom== AF_INET)?IN_CLNS:ISO_CLNS; 65136408Ssklower /* the default */ 65236408Ssklower } 65336408Ssklower tpcb->_tp_param = tp_conn_param[tpcb->tp_netservice]; 65436408Ssklower 65536408Ssklower tpcb->tp_cong_win = 1; 65636408Ssklower tpcb->tp_state = TP_CLOSED; 65736408Ssklower tpcb->tp_vers = TP_VERSION; 65836408Ssklower 65936408Ssklower /* Spec says default is 128 octets, 66036408Ssklower * that is, if the tpdusize argument never appears, use 128. 66136408Ssklower * As the initiator, we will always "propose" the 2048 66236408Ssklower * size, that is, we will put this argument in the CR 66336408Ssklower * always, but accept what the other side sends on the CC. 66436408Ssklower * If the initiator sends us something larger on a CR, 66536408Ssklower * we'll respond w/ this. 66636408Ssklower * Our maximum is 4096. See tp_chksum.c comments. 66736408Ssklower */ 66836408Ssklower tpcb->tp_l_tpdusize = 1 << tpcb->tp_tpdusize; 66936408Ssklower 67036408Ssklower tpcb->tp_seqmask = TP_NML_FMT_MASK; 67136408Ssklower tpcb->tp_seqbit = TP_NML_FMT_BIT; 67236408Ssklower tpcb->tp_seqhalf = tpcb->tp_seqbit >> 1; 67336408Ssklower tpcb->tp_sndhiwat = (SeqNum) - 1; /* a kludge but it works */ 67436408Ssklower tpcb->tp_s_subseq = 0; 67536408Ssklower 67636408Ssklower /* attach to a network-layer protoswitch */ 67750648Ssklower if ( error = tp_set_npcb(tpcb)) 67850648Ssklower goto bad4; 67936408Ssklower ASSERT( tpcb->tp_nlproto->nlp_afamily == tpcb->tp_domain); 68036408Ssklower 68150648Ssklower /* nothing to do for iso case */ 68236408Ssklower if( dom == AF_INET ) 68336408Ssklower sotoinpcb(so)->inp_ppcb = (caddr_t) tpcb; 68436408Ssklower 68536408Ssklower return 0; 68636408Ssklower 68736408Ssklower bad4: 68836408Ssklower IFDEBUG(D_CONN) 68936408Ssklower printf("BAD4 in tp_attach, so 0x%x\n", so); 69036408Ssklower ENDDEBUG 69136408Ssklower tp_freeref(tpcb->tp_refp); 69236408Ssklower 69336408Ssklower bad3: 69436408Ssklower IFDEBUG(D_CONN) 69536408Ssklower printf("BAD3 in tp_attach, so 0x%x\n", so); 69636408Ssklower ENDDEBUG 69736408Ssklower 69837469Ssklower free((caddr_t)tpcb, M_PCB); /* never a cluster */ 69936408Ssklower 70036408Ssklower bad2: 70136408Ssklower IFDEBUG(D_CONN) 70236408Ssklower printf("BAD2 in tp_attach, so 0x%x\n", so); 70336408Ssklower ENDDEBUG 70436408Ssklower so->so_pcb = 0; 70536408Ssklower 70637469Ssklower /*bad:*/ 70736408Ssklower IFDEBUG(D_CONN) 70836408Ssklower printf("BAD in tp_attach, so 0x%x\n", so); 70936408Ssklower ENDDEBUG 71036408Ssklower return error; 71136408Ssklower } 71236408Ssklower 71336408Ssklower /* 71436408Ssklower * NAME: tp_detach() 71536408Ssklower * 71636408Ssklower * CALLED FROM: 71736408Ssklower * tp.trans, on behalf of a user close request 71836408Ssklower * and when the reference timer goes off 71936408Ssklower * (if the disconnect was initiated by the protocol entity 72036408Ssklower * rather than by the user) 72136408Ssklower * 72236408Ssklower * FUNCTION and ARGUMENTS: 72336408Ssklower * remove the tpcb structure from the list of active or 72436408Ssklower * partially active connections, recycle all the mbufs 72536408Ssklower * associated with the pcb, ref structure, sockbufs, etc. 72636408Ssklower * Only free the ref structure if you know that a ref timer 72736408Ssklower * wasn't set for this tpcb. 72836408Ssklower * 72936408Ssklower * RETURNS: Nada 73036408Ssklower * 73136408Ssklower * SIDE EFFECTS: 73236408Ssklower * 73336408Ssklower * NOTES: 73436408Ssklower * tp_soisdisconnected() was already when this is called 73536408Ssklower */ 73636408Ssklower void 73736408Ssklower tp_detach(tpcb) 73836408Ssklower register struct tp_pcb *tpcb; 73936408Ssklower { 740*50904Ssklower void tp_freeref(), tp_rsyflush(); 74136408Ssklower register struct socket *so = tpcb->tp_sock; 74236408Ssklower 74336408Ssklower IFDEBUG(D_CONN) 74437469Ssklower printf("tp_detach(tpcb 0x%x, so 0x%x)\n", 74537469Ssklower tpcb,so); 74636408Ssklower ENDDEBUG 74736408Ssklower IFTRACE(D_CONN) 74836408Ssklower tptraceTPCB(TPPTmisc, "tp_detach tpcb so lsufx", 74939196Ssklower tpcb, so, *(u_short *)(tpcb->tp_lsuffix), 0); 75036408Ssklower ENDTRACE 75136408Ssklower 75236408Ssklower IFDEBUG(D_CONN) 75347278Ssklower printf("so_snd at 0x%x so_rcv at 0x%x\n", &so->so_snd, &so->so_rcv); 75447278Ssklower dump_mbuf(so->so_snd.sb_mb, "so_snd at detach "); 75547278Ssklower printf("about to call LL detach, nlproto 0x%x, nl_detach 0x%x\n", 75647278Ssklower tpcb->tp_nlproto, tpcb->tp_nlproto->nlp_pcbdetach); 75747278Ssklower ENDDEBUG 75847278Ssklower 75950648Ssklower if (tpcb->tp_Xsnd.sb_mb) { 76050648Ssklower printf("Unsent Xdata on detach; would panic"); 76150648Ssklower sbflush(&tpcb->tp_Xsnd); 76250648Ssklower } 76347278Ssklower if (tpcb->tp_ucddata) 76447278Ssklower m_freem(tpcb->tp_ucddata); 76547278Ssklower 76647278Ssklower IFDEBUG(D_CONN) 767*50904Ssklower printf("reassembly info cnt %d rsyq 0x%x\n", 768*50904Ssklower tpcb->tp_rsycnt, tpcb->tp_rsyq); 769*50904Ssklower ENDDEBUG 770*50904Ssklower if (tpcb->tp_rsyq) 771*50904Ssklower tp_rsyflush(tpcb); 772*50904Ssklower 773*50904Ssklower IFDEBUG(D_CONN) 77436408Ssklower printf("calling (...nlproto->...)(0x%x, so 0x%x)\n", 77550435Ssklower tpcb->tp_npcb, so); 77636408Ssklower printf("so 0x%x so_head 0x%x, qlen %d q0len %d qlimit %d\n", 77736408Ssklower so, so->so_head, 77836408Ssklower so->so_q0len, so->so_qlen, so->so_qlimit); 77936408Ssklower ENDDEBUG 78036408Ssklower 78150435Ssklower (tpcb->tp_nlproto->nlp_pcbdetach)(tpcb->tp_npcb); 78250648Ssklower /* does an so->so_pcb = 0; sofree(so) */ 78337469Ssklower 78436408Ssklower IFDEBUG(D_CONN) 78536408Ssklower printf("after xxx_pcbdetach\n"); 78636408Ssklower ENDDEBUG 78736408Ssklower 78836408Ssklower if( tpcb->tp_refp->tpr_state == REF_OPENING ) { 78936408Ssklower /* no connection existed here so no reference timer will be called */ 79036408Ssklower IFDEBUG(D_CONN) 79136408Ssklower printf("SETTING ref %d, 0x%x to REF_FREE\n", tpcb->tp_lref, 79236408Ssklower tpcb->tp_refp - &tp_ref[0]); 79336408Ssklower ENDDEBUG 79436408Ssklower 79536408Ssklower tp_freeref(tpcb->tp_refp); 79636408Ssklower } 79750648Ssklower #ifdef TP_PERF_MEAS 79836408Ssklower /* 79936408Ssklower * Get rid of the cluster mbuf allocated for performance measurements, if 80036408Ssklower * there is one. Note that tpcb->tp_perf_on says nothing about whether or 80136408Ssklower * not a cluster mbuf was allocated, so you have to check for a pointer 80236408Ssklower * to one (that is, we need the TP_PERF_MEASs around the following section 80336408Ssklower * of code, not the IFPERFs) 80436408Ssklower */ 80547278Ssklower if (tpcb->tp_p_mbuf) { 80637469Ssklower register struct mbuf *m = tpcb->tp_p_mbuf; 80737469Ssklower struct mbuf *n; 80836408Ssklower IFDEBUG(D_PERF_MEAS) 80936408Ssklower printf("freeing tp_p_meas 0x%x ", tpcb->tp_p_meas); 81036408Ssklower ENDDEBUG 81137469Ssklower do { 81237469Ssklower MFREE(m, n); 81337469Ssklower m = n; 81437469Ssklower } while (n); 81537469Ssklower tpcb->tp_p_meas = 0; 81637469Ssklower tpcb->tp_p_mbuf = 0; 81736408Ssklower } 81836408Ssklower #endif TP_PERF_MEAS 81936408Ssklower 82036408Ssklower IFDEBUG(D_CONN) 82137469Ssklower printf( "end of detach, NOT single, tpcb 0x%x\n", tpcb); 82236408Ssklower ENDDEBUG 82337469Ssklower /* free((caddr_t)tpcb, M_PCB); WHere to put this ? */ 82436408Ssklower } 82550501Ssklower 82650501Ssklower struct que { 82750501Ssklower struct tp_pcb *next; 82850501Ssklower struct tp_pcb *prev; 82950501Ssklower } tp_bound_pcbs = 83050501Ssklower {(struct tp_pcb *)&tp_bound_pcbs, (struct tp_pcb *)&tp_bound_pcbs}; 83150501Ssklower 83250501Ssklower u_short tp_unique; 83350501Ssklower 83450501Ssklower tp_tselinuse(tlen, tsel, siso, reuseaddr) 83550501Ssklower caddr_t tsel; 83650501Ssklower register struct sockaddr_iso *siso; 83750501Ssklower { 83850501Ssklower struct tp_pcb *b = tp_bound_pcbs.next, *l = tp_listeners; 83950501Ssklower register struct tp_pcb *t; 84050501Ssklower 84150501Ssklower for (;;) { 84250501Ssklower if (b != (struct tp_pcb *)&tp_bound_pcbs) { 84350501Ssklower t = b; b = t->tp_next; 84450501Ssklower } else if (l) { 84550501Ssklower t = l; l = t->tp_nextlisten; 84650501Ssklower } else 84750501Ssklower break; 84850501Ssklower if (tlen == t->tp_lsuffixlen && bcmp(tsel, t->tp_lsuffix, tlen) == 0) { 84950501Ssklower if (t->tp_flags & TPF_GENERAL_ADDR) { 85050501Ssklower if (siso == 0 || reuseaddr == 0) 85150501Ssklower return 1; 85250501Ssklower } else if (siso) { 85350501Ssklower if (siso->siso_family == t->tp_domain && 85450501Ssklower t->tp_nlproto->nlp_cmpnetaddr(t->tp_npcb, siso, TP_LOCAL)) 85550501Ssklower return 1; 85650501Ssklower } else if (reuseaddr == 0) 85750501Ssklower return 1; 85850501Ssklower } 85950501Ssklower } 86050501Ssklower return 0; 86150501Ssklower 86250501Ssklower } 86350501Ssklower 86450501Ssklower 86550501Ssklower tp_pcbbind(tpcb, nam) 86650501Ssklower register struct tp_pcb *tpcb; 86750501Ssklower register struct mbuf *nam; 86850501Ssklower { 86950501Ssklower register struct sockaddr_iso *siso = 0; 87050501Ssklower int tlen = 0, wrapped = 0; 87150501Ssklower caddr_t tsel; 87250501Ssklower u_short tutil; 87350501Ssklower 87450501Ssklower if (tpcb->tp_state != TP_CLOSED) 87550501Ssklower return (EINVAL); 87650501Ssklower if (nam) { 87750501Ssklower siso = mtod(nam, struct sockaddr_iso *); 87850501Ssklower switch (siso->siso_family) { 87950501Ssklower default: 88050501Ssklower return (EAFNOSUPPORT); 88150501Ssklower #ifdef ISO 88250501Ssklower case AF_ISO: 88350501Ssklower tlen = siso->siso_tlen; 88450501Ssklower tsel = TSEL(siso); 88550501Ssklower if (siso->siso_nlen == 0) 88650501Ssklower siso = 0; 88750501Ssklower break; 88850501Ssklower #endif 88950501Ssklower #ifdef INET 89050501Ssklower case AF_INET: 89150501Ssklower tsel = (caddr_t)&tutil; 89250501Ssklower if (tutil = ((struct sockaddr_in *)siso)->sin_port) { 89350501Ssklower tlen = 2; 89450501Ssklower } 89550501Ssklower if (((struct sockaddr_in *)siso)->sin_addr.s_addr == 0) 89650501Ssklower siso = 0; 89750501Ssklower } 89850501Ssklower #endif 89950501Ssklower } 90050501Ssklower if (tpcb->tp_lsuffixlen == 0) { 90150501Ssklower if (tlen) { 90250648Ssklower if (tp_tselinuse(tlen, tsel, siso, 90350501Ssklower tpcb->tp_sock->so_options & SO_REUSEADDR)) 90450501Ssklower return (EINVAL); 90550501Ssklower } else for (tsel = (caddr_t)&tp_unique, tlen = 2;;){ 90650501Ssklower if (tp_unique++ < ISO_PORT_RESERVED || 90750501Ssklower tp_unique > ISO_PORT_USERRESERVED) { 90850501Ssklower if (wrapped++) 90950501Ssklower return ESRCH; 91050501Ssklower tp_unique = ISO_PORT_RESERVED; 91150501Ssklower } 91250648Ssklower if (tp_tselinuse(tlen, tsel, siso, 0) == 0) 91350501Ssklower break; 91450501Ssklower } 91550501Ssklower bcopy(tsel, tpcb->tp_lsuffix, (tpcb->tp_lsuffixlen = tlen)); 91650501Ssklower insque(tpcb, &tp_bound_pcbs); 91750501Ssklower } else { 91850501Ssklower if (tlen || siso == 0) 91950501Ssklower return (EINVAL); 92050501Ssklower } 92150501Ssklower if (siso == 0) { 92250501Ssklower tpcb->tp_flags |= TPF_GENERAL_ADDR; 92350501Ssklower return (0); 92450501Ssklower } 92550501Ssklower return tpcb->tp_nlproto->nlp_pcbbind(tpcb->tp_npcb, nam); 92650501Ssklower } 927