📄 tcpnetd.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 fix from 1.51.1.3 $* $Date: 2002/04/18 13:40:02 $* $Source: M:/psisrc/stack/tcp/rcs/tcpnetd.c $* $Revision: 1.58.1.4 $*************************************************************************** - 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* Contains routines related to the TCP state machine**************************************************************************/#include "std.h"#include "flags.h"#include "ip.h"#include "m.h"#include "select.h"#include "so.h"#include "socket.h"#include "tcp.h"#include "timer.h"#include "nerrno.h"#include "debug.h"#include "fnsmib.h"#include "fnsproto.h"/* #define PRINT_ACKS *//* #define PRINT_RETR_FSM */#define t_start fns_t_start#define t_delete fns_t_deletepflocal st tcp_active(fast m * mp);local void tcp_urgdata(fast m *mp);local void tcp_urgstate (fast m *mp);pflocal st tcp_copen(fast m * mp);local void tcp_estab(fast tcpsv_t * svp);pflocal st tcp_naccept(fast m * mp);pflocal st tcp_nstate(fast m * mp);pflocal st tcp_passive(fast m * mp);pflocal int tcp_process_hold_queue(m *mp);local int tcp_secmatch(fast m * mp);local int tcp_spmatch(fast m * mp);local void tcp_stw(fast tcpsv_t * svp, fast u8 residual);local int tcp_upout(void * lsvp, void * unusedp);local void tcp_update(m * dmp);#ifdef PRINT_ACKSvoid print_insack_table(tcpsv_t *svp);#endif#ifdef TCP_KEEP_ALIVEimport u32 tcp_idle_interval;import boolean tcp_keep_alive;#endifimport u32 nc_hsize, tcp_try_max;#ifdef TRACEimport boolean tcp_tat, tcp_thq, tcp_tnetd;import boolean tcp_tpassive, tcp_trace, tcp_trcv;import boolean tcp_treset, tcp_trslf, tcp_tud, tcp_turgent;#endif#ifdef DEBUGimport boolean tcp_debug;#endif#ifdef MSD_DEBUGimport boolean msd_debug; /*msddebug*/import u32 tcprackz;#endif/************************************************************************* ** Function : ** ** Description : ** ** ** Parameters : None. ** ** Return : None. ** *************************************************************************//* Table VIII. Net deliver in a SYN_SENT state. [107] */pflocal st tcp_active (fast m * mp){ fast tcpsv_t * svp; fast u16 flags; fast TCPH_T * tcphp; fast u32 ackno; use_critical; trace0(tcp_trace, "tcp_active:\n"); if ((svp = mp->m_svp) == (tcpsv_t *)0) { debug0(tcp_debug, "tcp_active: no state vector\n"); return (st)mp->m_dispfn; /* --no action */ } assert(svp->sv_refcnt != 0, "tcp_active: sv not bound\n"); tcphp = (TCPH_T *)mp->m_cp; flags = NetToHost16(&tcphp[TCPH_FLAGS]); ackno = NetToHost32(&tcphp[TCPH_ACKNO]); if (ACK_OFF(flags)) { /* ACK status 1 : NONE */ trace0(tcp_tat, "tcp_active: ACK_OFF\n"); if (RST_ON(flags)) return (st)mp->m_dispfn; /* --no action */ if (tcp_secmatch(mp) == NO) { debug0(tcp_debug, "tcp_active: sending reset, tcp_secmatch failed\n"); return (st)tcp_reset; } if (SYN_OFF(flags)) return (st)mp->m_dispfn; /* --no action */ svp->sv_src.ip_nethost = mp->m_dest.a_ipa.ip_nethost; tcp_rsyn(mp); if (svp->sv_prec < mp->m_prec) svp->sv_prec = (u8)mp->m_prec; /* raise precedence */ tcp_sndack(mp, svp); if (FIN_ON(flags)) /* save_fin 9.4.6.3.38 [154] */ svp->sv_flags |= SV_RFINFLG; return (st)mp->m_dispfn; } if (UC32M(ackno, <=, svp->sv_suna) || UC32M(ackno, >, svp->sv_snxt)) {#ifdef TCP_TRANSACTION_TCP /* RFC 1644 says (section 3.4, R2.1): "If SEG.ACK is not acceptable and cache.CCsent[fh] is non-zero, then simply drop the segment without sending a RST. (The new SYN that the client is (re-)transmitting will eventually acknowledge any outstanding data and FIN at the server.)" */ { if ( (svp->sv_t_tcp_flags & SV_TRANSACTION) && (SYN_ON(flags)) ) { t_tcp_cache_entry_ *ce = t_tcp_find_cache_entry(svp->sv_dest.ip_nethost); if ( (ce) && (ce->ce_ccsent != 0) ) { return (st)mp->m_dispfn; } } /* if */ }#endif /* TCP_TRANSACTION_TCP */ /* ACK status 1 : INVALID */ /* 'tcp_reset' will not send the reset if RST is set */ debug0(tcp_debug, "tcp_active: sending reset, invalid ack\n"); return (st)tcp_reset; } /* ACK status 1 : VALID */ if (RST_ON(flags)) { /* openfail */ /* The peer has refused this connection request for whatever reason. Abort the connection -- application can retry */ /* 'tcp_rslf' changes state to CLOSED */ tcp_rslf(svp, FNS_ECONNREFUSED); return (st)mp->m_dispfn; } critical; if (svp->sv_sop == (so_t *)0) { /* socket has gone away */ debug0(tcp_debug, "tcp_active: sending reset, no socket\n"); normal; return (st)tcp_reset; } if (tcp_secmatch(mp) == NO || svp->sv_prec > mp->m_prec) { debug0(tcp_debug, "tcp_active: sending reset, sec/PREC fails\n"); debug1(tcp_debug, "tcp_active: tcp_secmatch = %d\n", tcp_secmatch(mp)); debug1(tcp_debug, "tcp_active: svp->sv_prec = %d\n", svp->sv_prec); debug1(tcp_debug, "tcp_active: mp->m_prec = %d\n", mp->m_prec); normal; return (st)tcp_reset; } if (SYN_OFF(flags)) { normal; return (st)mp->m_dispfn; /* --no action */ }#ifdef TCP_TRANSACTION_TCP if (svp->sv_t_tcp_flags & SV_TRANSACTION) { TCPO_T *ccecho = tcp_find_option(tcphp, TCPO_CCECHO_KIND); t_tcp_cache_entry_ *ce; /* RFC 1644, section 3.4 R2.2: "If the segment contains a CC.ECHO option whose SEG.CCECHO is different from TCB.CCsend, then the segment is unacceptable and is dropped." */ /* MBM note: Need to do this before call to tcp_rsyn because we don't want to record the other options from the SYN if we are going to reject it due to a bad CC.ECHO */ if (ccecho != ((TCPO_T *) 0) ) { if (NetToHost32(&(ccecho[TCPO_VAL])) != svp->sv_ccsend) { normal; return (st)mp->m_dispfn; } } /* The same RFC, same section, R2.3: "If cache.CCsent[fh] is zero, then it is set to TCB.CCsend. I think this is leaving out an importnat point though -- it fails to specify what to do if the response does not contain a CC.ECHO option. But Stevens Volume 3, section 3.7 clearly states that the per-host cache for a server that is not speaking t/tcp should never be updated, so we will follow that here (otherwise the next time we contact the same host, we would behave as if it we thought it spoke t/tcp */ /* MBM question: What if previously this host did talk t/tcp to us but this time it isn't? Should we now invalidate/free the cache entry for it? I'll leave that question for another time (what if that host had an implementation like ours, where transaction TCP is enabled on a per-connection basis rather than globally -- we wouldn't want to disrupt the cache in that circumstance, would we? */ if (ccecho != ((TCPO_T *) 0) ) { ce = t_tcp_find_cache_entry(svp->sv_dest.ip_nethost); if (ce->ce_ccsent == 0) ce->ce_ccsent = svp->sv_ccsend; } }#endif /* TCP_TRANSACTION_TCP */ normal; /* Parse the information, particularly the options, from this SYN */ tcp_rsyn(mp); svp->sv_prec = (u8)mp->m_prec; /* raise precedence */ /* MBM -- the following was taken out for Fusion 6.5 -- it is done instead in tcp_dink for the outgoing initial SYN. The reason is, for transaction TCP (and theoretically for standard TCP, though our API wouldn't provide a way for it to happen) we could send out multiple data segments following the initial SYN prior to receiving the SYN-ACK we are processing here -- and those segments would not have a proper source address in the IP header. */#if 0 svp->sv_src.ip_nethost = mp->m_dest.a_ipa.ip_nethost;#endif /* send an ack, since by the time this message makes it back to * 'tcp_net_deliver', it will have a length of 0 */ /* MBM note: For transaction TCP, because we are calling tcp_sndack here, this ACK will contain the CC option because our state is still recorded as SYN_SENT even though we've received the SYN-ACK to our SYN (the recorded state doesn't gets changed during the tcp_copen processing. This might technically be a violation of RFC 1644 section 3.4 S3, but I think this is harmless, because in this situation the other end doesn't know T/TCP and will just ignore the CC option (at least, it ignored the CC or CC.NEW option we sent in the initial SYN, otherwise it would not have responded with the SYN-ACK we are now processing. */ /* MBM note: It is possible that this segment (in addition to the SYN we've just processed) also contains data and/or a FIN. If so, "tcp_copen" will lead to the processing of that and generating an ACK -- so sending an ACK here is redundant. So if this segment has anything else to process beyond the SYN, we avoid sending the ACK here. */ if (!(tcp_dl(mp) > 1)) { /* segment contains more "data" than just a SYN */ tcp_sndack(mp, svp); } return (st)tcp_copen; /* conn_open */} /* tcp_active *//************************************************************************//* Extract out-of-band data (if any) from the segment and store it in *//* the state vector's "urgent" buffer *//* (Urgent data notification to application will wait until *//* "tcp_urgstate" *//************************************************************************/local void tcp_urgdata(fast m *mp){ fast TCPH_T * tcphp; fast tcpsv_t * svp; fast u16 urgoff; char *ubp; char *mvp; mp->m_oob = 0; /* if this socket is receiving its urgent data inline, nothing to do here */ if ( (svp = mp->m_svp) == (tcpsv_t *)0) { debug0(tcp_debug, "tcp_urgdata: no state vector\n"); return; } if (svp->sv_urg_mode != SV_URGMODE_OOB) return; /* if there is no urgent pointer within this segment, then there is nothing to do here */ tcphp = (TCPH_T *)(mp->m_cp); if (URG_OFF(NetToHost16(&tcphp[TCPH_FLAGS]))) return; /* Does the urgent pointer point to data within this segment. If not, nothing to do here */ urgoff = NetToHost16(&tcphp[TCPH_URGENT]); /* points one past urgent byte */ ubp = (mp->m_hp + urgoff - 1); if ( ubp > mp->m_tp) return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -