📄 tcpmisc.c
字号:
/* #define DEBUG_IN_SACKS *//** Copyright (c) 1998-2001 by NETsilicon Inc.** This software is copyrighted by and is the sole property of* NETsilicon. All rights, title, ownership, or other interests* in the software remain the property of NETsilicon. This* software may only be used in accordance with the corresponding* license agreement. Any unauthorized use, duplication, transmission,* distribution, or disclosure of this software is expressly forbidden.** This Copyright notice may not be removed or modified without prior* written consent of NETsilicon.** NETsilicon, reserves the right to modify this software* without notice.** NETsilicon* 411 Waverley Oaks Road USA 781.647.1234* Suite 227 http://www.netsilicon.com* Waltham, MA 02452 AmericaSales@netsilicon.com*************************************************************************** $Name: Fusion 6.52 Fusion 6.51 $* $Date: 2002/01/30 17:15:13 $* $Source: M:/psisrc/stack/tcp/rcs/tcpmisc.c $* $Revision: 1.56 $*************************************************************************** - Revision Log - ** Who When Why** FND 01/05/01 Rename t_start/t_delete to fns_t_start/fns_t_delete* to fix conflict with pSOS.**************************************************************************** File Description: TCP - Transmission Control Protocol* Miscellaneous TCP routines**************************************************************************/#include "std.h"#include "ip.h"#include "icmp.h"#include "m.h"#include "netioc.h"#include "pr.h"#include "q.h"#include "select.h"#include "so.h"#include "timer.h"#include "tcp.h"#include "in.h"#include "fnsmib.h"#include "nerrno.h"#include "debug.h"#include "fns_heap.h"#ifdef TCP_KEEP_ALIVE#include "flags.h" /* for give_bs macro expansion */#endif#include "fnsproto.h"#define t_start fns_t_start#define t_delete fns_t_delete#ifdef TCP_QUIETpflocal int tcp_noisy(void * uarg);#endifimport u32 nc_hsize, tcp_max_mss, tcp_rq_max;export int tcp_port;export q tcp_q;#ifdef DEBUGimport boolean tcp_debug;#endif#ifdef TRACEimport int tcp_trace, tcp_tstate, tcp_tsqxmit, tcp_trxmit;#endif#ifdef MSD_DEBUGimport boolean msd_debug; import u32 tcptargz;#endifimport boolean tcp_initialized;import pr_t * tcp_prp;#ifdef TCP_QUIETimport tcb * tcp_quiet;#endif#ifdef NAT_ROUTERimport u32 m_growmax;#endif/* Global tcp retransmit timer limit variables. Initialized from compiler constants (defined in tcp.h), and can be changed via SNMP (API is needed for that). At the time a TCP connection iscreated, the retransmit timer limits for that connection are initialized from these global limit variable (whatever values they have at the time). Then, (before the connection is opened) they can be modified via socket options */export int tcp_initial_rex_delay = INITIAL_REX_DELAY;export int tcp_min_rex_delay = MIN_REX_DELAY;export int tcp_max_rex_delay = MAX_REX_DELAY;/* disconnect the mp from it's state vector. */export int sv_m_detach (m * mp){ use_critical; trace0(tcp_trace, "sv_m_detach:\n"); critical; assert(mp->m_svp != (tcpsv_t *)0, "sv_m_detach: no state vector\n"); smfhist(mp, sv_m_detach); sv_detach(mp->m_svp, mp, false); mp->m_termfn = 0; mp->m_svp = (tcpsv_t *)0; normal; return(1); /* let m_free free the memory, if we're being called from there */} /* sv_m_detach *//***********************************************//* attach a state vector to an m structure */void sv_m_bind (tcpsv_t * svp, m * mp,int (*termfn)(struct m *) ){ use_critical; trace2(tcp_trace, "sv_m_bind: svp == 0x%x, mp == 0x%x\n", svp, mp); critical; sv_bind(svp, sv_m_bind, true); smfhist(mp, sv_m_bind); /* mark the mp's history */ if (mp->m_svp != (tcpsv_t *)0) { /* mp is already bound */ /* detach it from the other state vector first */ sv_m_detach(mp); assert(mp->m_svp == (tcpsv_t *)0, "sv_m_bind: !0 m_svp\n"); } sv_bind(mp->m_svp = svp, mp, false); assert(mp->m_svp == svp, "sv_m_bind: incorrectly bound\n"); mp->m_sop = svp->sv_sop; /* refer to the same socket (if any) */ mp->m_soindx = svp->sv_soindx; trace1(tcp_trace, "sv_m_bind: m_sop = 0x%x\n", mp->m_sop); mp->m_termfn = termfn; sv_detach(svp, sv_m_bind, true); normal;} /* sv_m_bind *//************************************************************************* ** Function : ** ** Description : ** ** ** Parameters : None. ** ** Return : None. ** *************************************************************************/export void tcpabort (fast tcpsv_t * svp, int err){ fast m * mp; fast int hsize; so_t * sop; use_critical;#ifdef MSD_DEBUG if (msd_debug) { sop = sv_valid_sop(svp, sop); if (sop) os_printf("tcpabort[%d] state %d\n", sop->so_index, svp->sv_state); else os_printf("tcpabort[*] state %d\n", svp->sv_state); }#endif if (svp->sv_state >= SYN_RECVD) { critical; hsize = (int)nc_hsize; sop = sv_valid_sop(svp, sop); if (sop != (so_t *)0) hsize += sop->so_hsize; else hsize += IP_MHL + SIZEOF_TCPH_T; normal; if ((mp = m_new(hsize, (int *)0, (u16)0)) != (m *)0) { sv_m_bind(svp, mp, sv_m_detach); mp->m_pflags = RCURRENT; debug1(tcp_debug, "tcpabort: sending reset, err = %d\n", err);#ifdef MSD_DEBUG if (msd_debug) os_printf("tcpabort: sending reset, err %d\n", err);#endif (void)msm(mp, tcp_reset); } }#ifdef MSD_DEBUG if (msd_debug) os_printf("tcpabort: calling tcp_rslf, err %d\n", err);#endif tcp_rslf(svp, err);}/**********************************************************************//* ACKnowledgement timer; emits a time-based acknowledgement, which was * previously requested by 'tcp_schedule_delayed_ack' */export int tcp_acktimer (void * uarg){#define lsvp ((tcpsv_t *)uarg) fast so_t * sop; use_critical; critical; assert((lsvp->sv_q.q_flags & F_Q_ZAPPED) == 0, "tcp_acktimer: called with zapped sv\n");#ifdef MSD_DEBUG if (msd_debug) os_printf("<TACK %d> ",(int)lsvp->sv_ackdelay); #endif sop = sv_valid_sop(lsvp, sop); /* UNLESS there is unacknowledged data waiting to be ACKed, or * the receive window is now fully open, simply bypass the * generation of this (extraneous) ACK */ if (sop && !(lsvp->sv_flags & SV_DATACK) && sop->so_rq.gq_cnt) { normal; return 0; } normal;#ifdef TCP_TRANSACTION_TCP /* If we have delayed a SYN-ACK waiting for application to do a write, this is the end of the delay period. But in order to send the SYN, we need to call tcp_sqxmit rather than tcp_sndack. */ if (TRANSACTION_DELAYING_SYNACK(lsvp)) { tcp_sqxmit(lsvp); } else {#endif /* TCP_TRANSACTION_TCP */ tcp_sndack((m *)0, lsvp);#ifdef TCP_TRANSACTION_TCP }#endif /* TCP_TRANSACTION_TCP */ return 0;#undef lsvp} /* tcp_acktimer */#ifdef NEED_ADJUST_ACK_DELAY/**********************************************************************//* adjust the acknowledgement timer interval based on the given value */export void tcp_adjust_ack_delay (fast tcpsv_t * svp, u32 value){ fast u32 u; if ((u = svp->sv_ackdelay) != (u32)0) { /* The following line of code is meant to "smooth" adjustments in the ack timer delay. It moves the acktimer 1/8 of distance from the present value toward the passed in new value. This is identical to the smoothing algorithm used in "tcp_update" to adjust the round-trip time based on round trip time measurement samples. */ u = (((u << 3) - u) + value) >> 3; } else { u = value; } /* bound the value */ if (u < MS_PER_TICK) u = MS_PER_TICK; else if (u > MAX_ACK_DELAY) u = MAX_ACK_DELAY;#ifdef MSD_DEBUG if (msd_debug && svp->sv_ackdelay != u) os_printf("[ACK %d => %d] ",(int)svp->sv_ackdelay,(int)u);#endif svp->sv_ackdelay = u;} /* tcp_adjust_ack_delay */#endif/****************************************************************************//* Generate a packet with no data and add it to the receive queue, simulating * an EOF. *//* MUST be called in a critical context! */export void tcp_finpkt (m * mp, fast tcpsv_t * svp){ fast m * nmp; so_t * sop; assert(svp->sv_refcnt != 0, "tcp_finpkt: sv not bound\n"); /* compute sop once */ sop = svp->sv_sop; if (sop == (so_t *)0) { /* no socket to give it too... */ debug0(tcp_debug, "tcp_finpkt: no socket\n"); svp->sv_flags &= ~SV_EOF; /* fake it anyway */ return; } if ((nmp = m_new(0, (int *)0, (u16)0)) != (m *)0) { /* "receive" an empty packet *//* Start of MSD WSI change */#ifdef WSI1_ONLY#ifdef MSD_DEBUG if (msd_debug) os_printf("tcp_finpkt: rqcnt==%d\n",sop->so_rq.gq_cnt);#endif /* RSHUTDOWN_NOTIFY when FIN arrives and * no data is waiting to be read. */ if (sop->so_rq.gq_cnt == 0) { /* FIN arrived w/ no data ahead of it to be read. */ so_notify(sop, RSHUTDOWN_NOTIFY); }/* End of MSD WSI change */#endif /* WSI1_ONLY */ /* MBM -- this was moved here from "tcp_naccept" to fix a race condition -- see note in tcp_naccespt which explains it. */#ifndef WSI1_ONLY sop->so_flags |= F_SO_RSHUTDOWN;#endif /* WSI1_ONLY */#ifdef M_HISTORY smfhist(mp, (st (*)(m *))tcp_finpkt);#endif sv_m_bind(svp, nmp, sv_m_detach); if (mp) { sm_wqin(mp, nmp, smrqin); } else { (void)msm(nmp, smrqin); } svp->sv_flags &= ~SV_EOF; } else { svp->sv_flags |= SV_EOF; /* timer will try later */ (void) t_start(svp->sv_rextcb, HALLOC_FIN_DELAY); }} /* tcp_finpkt */#ifdef IP_RFC_1191/***********************************************************************//* Recieve notification of a path MTU change for a specific foreign *//* host. Look thru our open connections for connections to the *//* specified foreigh host, and adjust the send MSS of these connections*//* according to the new path MTU *//***********************************************************************/export int tcp_pmtu_change_notif(u32 hostaddr,u16 new_pmtu){ tcpsv_t *svp; int new_mss = (new_pmtu - (SIZEOF_TCPH_T+IP_MHL) );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -