📄 tcpsend.c
字号:
/* #define FAST_REXMT_DEBUG *//* #define TRACE_SQXMIT *//** 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 fix from 1.35.2.2 $* $Date: 2002/04/16 12:42:47 $* $Source: M:/psisrc/stack/tcp/rcs/tcpsend.c $* $Revision: 1.38.2.2 $*************************************************************************** - Revision Log - ** Who When Why** FND 09/10/01 Rename t_start to fns_t_start to fix conflict * with pSOS.** FND 01/05/02 Eliminate compiler warning for the first assert()* in tcp_construct_seg_options().**************************************************************************** File Description: TCP - Transmission Control Protocol* Transmit routines**************************************************************************/#include "std.h"#include "m.h"#include "so.h"#include "ip.h"#include "tcp.h"#include "timer.h"#include "fnsmib.h"#include "fnsproto.h"#include "nerrno.h"#include "debug.h"#include "flags.h"#define t_start fns_t_startpflocal st tcp_sqdispfn(fast m * mp);import u32 nc_hsize, tcp_try_max;#ifdef DEBUGimport boolean tcp_debug;#endif#ifdef TRACEimport boolean tcp_trace, tcp_tsqxmit, tcp_turgent;#endif#ifdef MSD_DEBUGimport boolean msd_debug; /*msddebug*/#endif#ifdef NAT_ROUTERimport u32 m_growmax;#endif#if 1static int inv_ctr = 0;export int sctr = 0;#endif/*************************************************************************//*************************************************************************//* TCP segments are "disposed of" via the following function. Its purpose is to gain performance by holding on to mss-sized messages rather than freeing them to the heap, in order to re-use them for subsequent mss-sized messages. This saves freeing to the heap and reallocating them. But also, keeps the heap tied up (if some time were to pass before the message we are holding on to gets re-used) */ pflocal int tcp_sqxmit_termfn(fast m * mp){ fast tcpsv_t *svp = mp->m_svp; use_critical; assert(svp != (tcpsv_t *) 0,"tcp_sqxmit_termfn -- NULL svp"); /* if its an mss-sized message, see if we have capacity to store it for later use, otherwise just let it be freed */ if (mp->m_len == svp->sv_mss_m_len) { critical; if (!(svp->sv_q.q_flags & F_Q_ZAPPED)) { /* don't keep message if we've scheduled the freeing of the state vector */ assert(svp->sv_num_mss_sized_msgs <= MAX_HOLD_MSS_SIZED_MSGS, "Too many mss-sized msgs"); if (svp->sv_num_mss_sized_msgs < MAX_HOLD_MSS_SIZED_MSGS) { svp->sv_tcp_mss_sized_msgs[svp->sv_num_mss_sized_msgs++] = mp; normal; return(0); /* don't let msm free it */ } } normal; } sv_m_detach(mp); return(1); /* let msm free it */} /* tcp_sqxmit_termfn */ /****************************************************************************//* inspect errors and reset the connection if they happen more than thrice * during connection establishment */pflocal st tcp_sqconndispfn (fast m * mp){ fast tcpsv_t * svp; if (mp->m_err && mp->m_err != FNS_EWOULDBLOCK) { svp = mp->m_svp; assert(svp != (tcpsv_t *)0, "tcp_sqconndispfn: 0 svp\n"); /* SYN couldn't get out of the box -- probably because it wasn't routeable at the IP layer. Abort the connection attempt -- application can retry if it wishes. */ if (svp->sv_state < ESTAB) tcp_rslf(svp, mp->m_err); } return (st)smdispose;} /* tcp_sqconndispfn *//****************************************************************************//* Local defines for processing the options part of a TCP header */#define TCP_OPT_INCLUDE_MSS 0x1#define TCP_OPT_INCLUDE_WSF 0x2#define TCP_OPT_INCLUDE_TIMESTAMPS 0x4#define TCP_OPT_INCLUDE_SACK_PERMITTED 0x8#ifdef TCP_SELACK_ENHANCEMENTS #define TCP_OPT_INCLUDE_SACK 0x10#endif /* TCP_SELACK_ENHANCEMENTS */#ifdef TCP_TRANSACTION_TCP#define TCP_OPT_INCLUDE_CC 0x20#define TCP_OPT_INCLUDE_CCNEW 0x40#define TCP_OPT_INCLUDE_CCECHO 0x80#endif /* TCP_TRANSACTION_TCP */#ifdef TCP_SELACK_ENHANCEMENTS /****************************************************************************//* Function to return, given a specified amount of space, how many SACK *//* blocks can be included in a SACK option that would fit into that space. *//* Takes into account the 2-byte overhead plus the 8 bytes per block *//****************************************************************************/static int tcp_num_sack_blocks_room_for(int room){ int num_sack_blocks = 0; room -= TCPO_VAL; while (room >= TCPO_SACK_BLOCK_SIZE) { num_sack_blocks++; room -= TCPO_SACK_BLOCK_SIZE; } /* while */ return(num_sack_blocks);} /* tcp_num_sack_blocks_room_for *//****************************************************************************//* This function adjusts the variables pertaining to TCP options according to the need and capacity for sending selective acknowledgements in this segment. The "optsize_so_far" parameter is input/output. Upon input, it says how much option space is already spoken for. Upon output, it contains' its input value plus the additional amount needed for the selective ack option. Also, "which_options" is input-output. The "selective ack needed" flag is set if it is determined that it is, and all the other bits are left untouched. *//* NOTE: This function should not be called until all the other options that will be included in the segment are already known. */export void tcp_selective_ack_needed(fast tcpsv_t *svp,int *optsize,u16 *which_options){ int sack_block_count; /* If the SACK BLOCK list is empty, don't need a SACK option */ if (svp->sv_num_out_sack_blocks == 0) return; /* How many SACK blocks do we have room for in the space available? */ sack_block_count = tcp_num_sack_blocks_room_for(TCP_MAX_SEG_OPTSIZE - *optsize); /* Do we have room for any at all? */ if (sack_block_count == 0) return; /* If we don't have as many SACK blocks as we have room for, adjust the count down */ if (svp->sv_num_out_sack_blocks < sack_block_count) { sack_block_count = svp->sv_num_out_sack_blocks; } /* if */ /* We do have room for at least one, the amount of additional option space needed is the "header" of the SACK option plus the space for the SACK BLOCKS */ *optsize += (TCPO_VAL + (sack_block_count * TCPO_SACK_BLOCK_SIZE) ); *which_options |= TCP_OPT_INCLUDE_SACK; /* The optsize must be rounded up to the nearest multiple of 4 */ if ( ( *optsize % 4) != 0 ) *optsize += (4 - ( *optsize % 4) ); } /* tcp_selective_ack_needed */#endif /* TCP_SELACK_ENHANCEMENTS *//****************************************************************************//* Function to determine which options to include in a TCP segment. Returns *//* bitflags indicating which option to include */local int tcp_seg_which_options(fast tcpsv_t *svp, int synseg){ int which_options = 0; /* Take care of options that would only be included in a SYN segment */ if (synseg) { /* The MSS option will always be present, and first */ which_options = TCP_OPT_INCLUDE_MSS;#ifdef TCP_WND_SCALE /* If a window scale option is to be included, it will always follow the MSS option. It is to be included if: -- Window scale option is enabled (per socket option) AND -- We are the active side initiating a SYN OR we are responding to a SYN which contained the window scale option */ if (svp->sv_flags2 & SV_WSCALE_PERMITTED) { if ( (svp->sv_state == SYN_SENT) || ( (svp->sv_state == SYN_RECVD) && (svp->sv_flags2 & SV_WSCALE_ENABLED) ) ) which_options |= TCP_OPT_INCLUDE_WSF; } /* if */#endif /* TCP_WND_SCALE */#ifdef TCP_SELACK_ENHANCEMENTS /* If the socket option has been specified that we should permit selective acks, send that option */ if (svp->sv_flags2 & SV_PERMIT_IN_SACKS) { which_options |= TCP_OPT_INCLUDE_SACK_PERMITTED; } /* if */#endif /* TCP_SELACK_ENHANCEMENTS */ } /* if synseg */#ifdef TCP_TIMESTAMPS /* We need a timestamp option if: -- The socket is configured to (via socket options) to generate timestamps, and this is the initiating SYN, so we want to try to negotiate timestamps on this connection -- This is the passive SYN, and the other end has indicated its desire to any segment other than an initiating SYN, and the peer has indicated its desire to use timestamps by including a timestamp option in its SYN (the SV_TIMESTAMPS_ENABLED indicates this) -- Any other segment, if timestamps were negotiated during the exchange of SYNs (i.e., the SV_TIMESTAMPS_ENABLED flag is set) */ { int timestamps_needed; if ( (svp->sv_state == SYN_SENT) && (synseg) ) { /* this is the initiating SYN */ timestamps_needed = TIMESTAMPS_DESIRED(svp); } else { timestamps_needed = (svp->sv_flags2 & SV_TIMESTAMPS_ENABLED); } /* if-else */ if (timestamps_needed) which_options |= TCP_OPT_INCLUDE_TIMESTAMPS; }#endif /* TCP_TIMESTAMPS */#ifdef TCP_TRANSACTION_TCP if (synseg) { if (svp->sv_t_tcp_flags & SV_CCNEW) { which_options |= TCP_OPT_INCLUDE_CCNEW; } else if (svp->sv_t_tcp_flags & SV_CC) { which_options |= TCP_OPT_INCLUDE_CC; } if (svp->sv_t_tcp_flags & SV_CCECHO) { which_options |= TCP_OPT_INCLUDE_CCECHO; } } else { /* not a SYN segment */ /* RFC 1644: section 3.4, S3 */ if (svp->sv_ccrecv != 0) { which_options |= TCP_OPT_INCLUDE_CC; } else if ( (svp->sv_t_tcp_flags & SV_TRANSACTION) && (svp->sv_state == SYN_SENT) ){ /* Take care of case where the request message requires more than one segment because it is larger than the MSS */ t_tcp_cache_entry_ *ce; ce = t_tcp_find_cache_entry(svp->sv_dest.ip_nethost); if ( (ce != (t_tcp_cache_entry_ *) 0) && (ce->ce_ccsent != 0) ) { which_options |= TCP_OPT_INCLUDE_CC; } } }#endif /* TCP_TRANSACTION_TCP */ return(which_options);} /* tcp_seg_which_options *//****************************************************************************//* Function to determine the size of the options field of TCP segment. *//* This, of course, depends on which options we need to send, and that *//* depends on: *//* -- compile time constants determining which options are compiled in */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -