📄 tcpxmit.c
字号:
/** 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/16 16:34:17 $* $Source: M:/psisrc/stack/tcp/rcs/tcpxmit.c $* $Revision: 1.24 $*************************************************************************** - Revision Log - ** Who When Why** FND 01/05/01 Rename t_start to fns_t_start to fix pSOS conflict**************************************************************************** File Description: TCP - Transmission Control Protocol* Transmit routines**************************************************************************/#include "std.h"#include "fr.h"#include "ip.h"#include "pr.h"#include "m.h"#include "so.h"#include "tcp.h"#include "timer.h"#include "fnsmib.h"#include "fnsproto.h"#include "nerrno.h"#include "debug.h"#define t_start fns_t_startimport pr_t * tcp_prp;#ifdef DEBUGimport boolean tcp_debug;#endif#ifdef TRACEimport boolean tcp_trace, tcp_tstate;#endif#ifdef TCP_STATSimport int tcp_txmit;#endifimport q tcp_q;/* This function is used only by tcp_dink *//* Determine the receive window to be advertised in an outgoing packet. Will advertise the amount of unused receive buffer space presently in the socket's receive queue, unless we must presently advertise a receive window of zero to avoid "silly window syndrome". In that case, we will begin advertising the actual buffer space available when that amount becomes at least as large as the lesser of (1) 1/2 the full size of the socket's receive buffer, or (2) The MSS of this connection.*/export u16 tcp_rwind_to_advertise(fast tcpsv_t *svp){ fast so_t * sop; u32 bsa; /* obtain amount of buffer space available on the socket's receive queue */ sop = sv_valid_sop(svp, sop); if (!sop) return(0); /* invalid socket pointer */ bsa = rwnd(sop); /* are we presently recovering from a zero-window situation? */ if ( svp->sv_flags & SV_RECOVZWIN ) { /* yes */ /* has the available buffer space increased beyond the recovery threshold? */ if ( (bsa >= svp->sv_mssd) || (bsa >= (rwndmax(sop)/2)) ) { /* yes */ /* we have recovered, advertise actual available space */ svp->sv_flags &= ~SV_RECOVZWIN; } else { /* no */ /* continue advertising zero window, not recovered yet */ bsa = 0; } } else { /* no, not presently in recovery mode */ if (bsa == 0) /* but we now need to enter recovery mode */ svp->sv_flags |= SV_RECOVZWIN; }#ifdef TCP_WND_SCALE return(bsa >> svp->sv_rwndscale);#else return(bsa);#endif}/*************************************************************//* Function to scan the options field of the outgoing segment*//* and place proper values into the "value" fields of the *//* options whose content is not supposed to be set until *//* "dink" time. *//* Input parameters are pointer to the beginning of the *//* options portion of the TCP header and the state vector. */local void tcp_dink_syn_options(fast TCPH_T *tcphp, fast tcpsv_t *svp){ /* The only one we need to do anything with here is the MSS option */ { TCPO_T *msso; msso = tcp_find_option(tcphp, TCPO_MSS_KIND); if (msso != ((TCPO_T *) 0) ) HostToNet16(&msso[TCPO_VAL], svp->sv_rcv_mss); }} /* tcp_dink_syn_options *//************************************************************//* Final send & checksum generation */export int tcp_dink (m * mp){ fast TCPH_T * tcphp; /* TCP Header Pointer */ fast tcpsv_t * svp; fast PIPH_T * piphp; /* Pseudo IP Header Pointer */ fast u16 flags; fast so_t * sop; fast u16 u1; int if_mtu, send_mss; int mss_source; netdev * ndp; u8 zbsave; u16 checksum; use_critical; trace0(tcp_trace, "tcp_dink:\n");/* we use ndp to get the IP mtu with the new router code */ ndp = mp->m_ndp; tcphp = (TCPH_T *)mp->m_cp; flags = NetToHost16(&tcphp[TCPH_FLAGS]); svp = mp->m_svp; if (SYN_ON(flags)) { if (svp == (tcpsv_t *)0) { debug0(tcp_debug, "tcp_dink: SYN w/o svp\n"); return FNS_ECONNABORTED; } /****************************************************************************/ /* MBM: The following code was put in for Fusion 6.5, replacing the code in "tcp_gsyn" which searched for a duplicate connection, slept (unconditionally, regardless of whether its a blocking socket) until that connection closed or went into the TIME_WAIT state, then killed that connection (i.e., defeating the TIME_WAIT state) -- a complete violation of TCP fundamentals. Now we reject a connection attempt from the application if it will be a duplicate connection. */ /* If this is an initial SYN, we now know the outgoing interface for this connection, and we can check to make sure that this isn't a duplicate connection (i.e., same pair of ipaddress:port endpoints). To do that, we have to look at all of our state vectors to make sure that none of them are active with the same pair of endpoints. */ if (ACK_OFF(flags)) { /* This is the initial SYN */ int remote_port; u32 remote_ipaddr; int local_port; u32 local_ipaddr; tcpsv_t *nsvp; /* If we are not already bound to a local IP address, we will now "bind" ourself to the local IP address ot the interface that was selected by the IP layer to send this SYN out on. */ /* MBM note: This leaves an issue for dealing with later: What if the interface that IP selected has a different IP address than the local IP address that we were previously bound to? Which address should appear in the source-address field of the outgoing packets for this connection? And is it OK for the packets to be routed out a different interface than the one we are "bound" to? */ if (svp->sv_src.ip_nethost == INADDR_ANY) { svp->sv_src.ip_nethost = ndp->nd_ipas[0]; } /* Look for duplicate connection */ remote_port = svp->sv_dest.ip_port; remote_ipaddr = svp->sv_dest.ip_nethost; local_port = svp->sv_src.ip_port; local_ipaddr = svp->sv_src.ip_nethost;#if 0 /* We may not have been bound to a local ip address, in which case we get it from the device table */ if (local_ipaddr == INADDR_ANY) { local_ipaddr = ndp->nd_ipas[0]; }#endif critical; for (nsvp = (tcpsv_t *)tcp_q.q_next; nsvp != (tcpsv_t *) &tcp_q; nsvp = (tcpsv_t *) nsvp->sv_q.q_next) { if (nsvp == svp) continue; if ( (nsvp->sv_dest.ip_port != remote_port) || (nsvp->sv_dest.ip_nethost != remote_ipaddr) || (nsvp->sv_src.ip_port != local_port) || (nsvp->sv_src.ip_nethost != local_ipaddr) ) { continue; } /* We found a duplicate connection. */#ifdef TCP_TRANSACTION_TCP /* If both the current and the previous duplicate connection are t/tcp, then if the previous is presently in th TIME_WAIT state and its duration is less than an MSL, we can "kill" that connection and accept this new one. -- per RFC 1644, section 3.4, O1.2 */ if ( (svp->sv_t_tcp_flags & SV_TRANSACTION) && (nsvp->sv_t_tcp_flags & SV_TRANSACTION) && (nsvp->sv_state == TIME_WAIT) && (nsvp->sv_t_tcp_flags & SV_LESS_THAN_MSL) ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -