?? tcp_input.c
字號:
/* tcp_input.c - TCP input routines *//* Copyright 1984 - 2002 Wind River Systems, Inc. */#include "copyright_wrs.h"/* * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994, 1995 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)tcp_input.c 8.12 (Berkeley) 5/24/95 *//*modification history--------------------01i,06mar02,vvv fixed tcp_input to wake application only when space in send buffer exceeds low water mark (SPR #72177)01h,12oct01,rae merge from truestack ver 01n, base o1f (SPRs 69629, 70328, 70329, WindView, cleanup)01g,11oct00,gnn enabled LAND fix by default.01f,09jan98,vin added LAND attack fix.01e,26sep97,sgv Removed check for PUSH flag in TCP_REASS macro01d,07jul97,vin fixed additional bugs. (timestamp echo fix Stevens VolII Sec 26.6 fig 26.20, connection timer bug Stevens VolII sec 28.6 fig 28.20, simultaneous bug fix Stevens VolII sec 28.8 fig 28.30, removed unnecessary code Stevens VolII sec 29.9 fig 29.22)01c,08mar97,vin added changes to accomodate changes in pcb structure for hash look ups.01c,05feb97,rjc changes for tos routing01b,22nov96,vin added cluster support replaced m_get(..) with mBufClGet(..).01a,03mar96,vin created from BSD4.4lite2. integrated some wrs changes from 02q of tcp_input.c*/#include "vxWorks.h"#include "net/systm.h"#include "net/mbuf.h"#include "net/protosw.h"#include "sys/socket.h"#include "net/socketvar.h"#include "errno.h"#include "net/if.h"#include "net/route.h"#include "netinet/in.h"#include "netinet/in_pcb.h"#include "netinet/in_systm.h"#include "netinet/ip.h"#include "netinet/ip_var.h"#include "netinet/tcp.h"#include "netinet/tcp_fsm.h"#include "netinet/tcp_seq.h"#include "netinet/tcp_timer.h"#include "netinet/tcp_var.h"#include "netinet/tcpip.h"#ifdef BSDDEBUG#include "netinet/tcp_debug.h"#endif /* BSDDEBUG */#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET#include "wvNetLib.h"#endif#endif#ifdef VIRTUAL_STACK#include "netinet/vsLib.h"#elseextern u_long sb_max;IMPORT int tcp_keepinit;IMPORT int tcp_mssdflt;#endif /* VIRTUAL_STACK */IMPORT unsigned long (*pTcpRandHook)(void);extern void _remque ();extern void _insque ();/* XXX LAND attack safe remove this after thorough investigation */UCHAR _landAttackSafe = 1;/* * MIB-II support counts the number of TCP packets sent with the Reset Flag * set. */#ifndef VIRTUAL_STACKlong tcpOutRsts;tcp_seq tcp_iss; /* tcp initial send seq # */unsigned tcp_alpha, tcp_beta; /* retransmission smoothing constants */struct inpcbhead tcb; /* head of queue of active tcpcb's */struct inpcbinfo tcbinfo;struct tcpstat tcpstat; /* tcp statistics */int tcprexmtthresh = 3; /* overridden during protocol initialization */struct tcpiphdr tcp_saveti;struct inpcb *tcp_last_inpcb = NULL;u_long tcp_now; /* for RFC 1323 timestamps */#endif /* VIRTUAL_STACK */#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* Set common fields of event identifiers for this module. */LOCAL UCHAR wvNetModuleId = WV_NET_TCPINPUT_MODULE; /* Value for tcp_input.c */LOCAL UCHAR wvNetLocalFilter = WV_NET_NONE; /* Available event filter */LOCAL ULONG wvNetEventId; /* Event identifier: see wvNetLib.h */#endif /* INCLUDE_WVNET */#endif#define TCP_PAWS_IDLE (24 * 24 * 60 * 60 * PR_SLOWHZ)/* for modulo comparisons of timestamps */#define TSTMP_LT(a,b) ((int)((a)-(b)) < 0)#define TSTMP_GEQ(a,b) ((int)((a)-(b)) >= 0)/* * Insert segment ti into reassembly queue of tcp with * control block tp. Return TH_FIN if reassembly now includes * a segment with FIN. The macro form does the common case inline * (segment is the next to be received on an established connection, * and the queue is empty), avoiding linkage into and removal * from the queue and repetition of various conversions. * Set DELACK for segments received in order, but ack immediately * when segments are out of order (so fast retransmit can work). */#define TCP_REASS(tp, ti, m, so, flags) { \ if ((ti)->ti_seq == (tp)->rcv_nxt && \ (tp)->seg_next == (struct tcpiphdr *)(tp) && \ (tp)->t_state == TCPS_ESTABLISHED) { \ (tp)->t_flags |= TF_DELACK; \ (tp)->rcv_nxt += (ti)->ti_len; \ flags = (ti)->ti_flags & TH_FIN; \ tcpstat.tcps_rcvpack++;\ tcpstat.tcps_rcvbyte += (ti)->ti_len;\ sbappend(&(so)->so_rcv, (m)); \ sorwakeup(so); \ } else { \ (flags) = tcp_reass((tp), (ti), (m)); \ tp->t_flags |= TF_ACKNOW; \ } \}inttcp_reass(tp, ti, m) register struct tcpcb *tp; register struct tcpiphdr *ti; struct mbuf *m;{ register struct tcpiphdr *q; struct socket *so = tp->t_inpcb->inp_socket; int flags; /* * Call with ti==0 after become established to * force pre-ESTABLISHED data up to user socket. */ if (ti == 0) goto present; /* * Find a segment which begins after this one does. */ for (q = tp->seg_next; q != (struct tcpiphdr *)tp; q = (struct tcpiphdr *)q->ti_next) if (SEQ_GT(q->ti_seq, ti->ti_seq)) break; /* * If there is a preceding segment, it may provide some of * our data already. If so, drop the data from the incoming * segment. If it provides all of our data, drop us. */ if ((struct tcpiphdr *)q->ti_prev != (struct tcpiphdr *)tp) { register int i; q = (struct tcpiphdr *)q->ti_prev; /* conversion to int (in i) handles seq wraparound */ i = q->ti_seq + q->ti_len - ti->ti_seq; if (i > 0) { if (i >= ti->ti_len) {#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_INFO event */ WV_NET_PORTIN_EVENT_3 (NET_CORE_EVENT, WV_NET_INFO, 26, 8, tp->t_inpcb->inp_fport, tp->t_inpcb->inp_lport, WV_NETEVENT_TCPIN_DUPSEG, WV_NET_RECV, so->so_fd, ti->ti_seq, ti->ti_len)#endif /* INCLUDE_WVNET */#endif tcpstat.tcps_rcvduppack++; tcpstat.tcps_rcvdupbyte += ti->ti_len; m_freem(m); return (0); } m_adj(m, i); ti->ti_len -= i; ti->ti_seq += i; } q = (struct tcpiphdr *)(q->ti_next); } tcpstat.tcps_rcvoopack++; tcpstat.tcps_rcvoobyte += ti->ti_len; REASS_MBUF(ti) = m; /* XXX */ /* * While we overlap succeeding segments trim them or, * if they are completely covered, dequeue them. */ while (q != (struct tcpiphdr *)tp) { register int i = (ti->ti_seq + ti->ti_len) - q->ti_seq; if (i <= 0) break; if (i < q->ti_len) { q->ti_seq += i; q->ti_len -= i; m_adj(REASS_MBUF(q), i); break; } q = (struct tcpiphdr *)q->ti_next; m = REASS_MBUF((struct tcpiphdr *)q->ti_prev);#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_VERBOSE event */ WV_NET_PORTIN_EVENT_4 (NET_CORE_EVENT, WV_NET_VERBOSE, 37, 20, tp->t_inpcb->inp_fport, tp->t_inpcb->inp_lport, WV_NETEVENT_TCPIN_DUPDATA, WV_NET_RECV, so->so_fd, ti->ti_seq, ((struct tcpiphdr *)q->ti_prev)->ti_seq, ((struct tcpiphdr *)q->ti_prev)->ti_len)#endif /* INCLUDE_WVNET */#endif remque(q->ti_prev); m_freem(m); } /* * Stick new segment in its place. */ insque(ti, q->ti_prev);present: /* * Present data to user, advancing rcv_nxt through * completed sequence space. */ if (TCPS_HAVERCVDSYN(tp->t_state) == 0) return (0); ti = tp->seg_next; if (ti == (struct tcpiphdr *)tp || ti->ti_seq != tp->rcv_nxt) return (0); if (tp->t_state == TCPS_SYN_RECEIVED && ti->ti_len) return (0); do { tp->rcv_nxt += ti->ti_len; flags = ti->ti_flags & TH_FIN; remque(ti); m = REASS_MBUF(ti); ti = (struct tcpiphdr *)ti->ti_next; if (so->so_state & SS_CANTRCVMORE) m_freem(m); else sbappend(&so->so_rcv, m); } while (ti != (struct tcpiphdr *)tp && ti->ti_seq == tp->rcv_nxt); sorwakeup(so); return (flags);}/* * TCP input routine, follows pages 65-76 of the * protocol specification dated September, 1981 very closely. */voidtcp_input(m, iphlen) register struct mbuf *m; int iphlen;{ register struct tcpiphdr *ti; register struct inpcb *inp; u_char *optp = NULL; int optlen = 0; int len, tlen, off; register struct tcpcb *tp = 0; register int tiflags; struct socket *so = NULL; int todrop, acked, ourfinisacked, needoutput = 0; short ostate = 0; struct in_addr laddr; int dropsocket = 0; int iss = 0; u_long tiwin, ts_val, ts_ecr; int ts_present = 0;#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_NOTICE event */ WV_NET_EVENT_0 (NET_CORE_EVENT, WV_NET_NOTICE, 18, 7, WV_NETEVENT_TCPIN_START, WV_NET_RECV)#endif /* INCLUDE_WVNET */#endif tcpstat.tcps_rcvtotal++; /* * Get IP and TCP header together in first mbuf. * Note: IP leaves IP header in first mbuf. */ ti = mtod(m, struct tcpiphdr *); if (iphlen > sizeof (struct ip)) ip_stripoptions(m, (struct mbuf *)0); if (m->m_len < sizeof (struct tcpiphdr)) { if ((m = m_pullup(m, sizeof (struct tcpiphdr))) == 0) { tcpstat.tcps_rcvshort++;#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_VERBOSE event */ WV_NET_EVENT_0 (NET_CORE_EVENT, WV_NET_VERBOSE, 38, 21, WV_NETEVENT_TCPIN_SHORTSEG, WV_NET_RECV)#endif /* INCLUDE_WVNET */#endif return; } ti = mtod(m, struct tcpiphdr *); } /* * Checksum extended TCP header and data. */ tlen = ((struct ip *)ti)->ip_len; len = sizeof (struct ip) + tlen; ti->ti_next = ti->ti_prev = 0; ti->ti_x1 = 0; ti->ti_len = (u_short)tlen; HTONS(ti->ti_len); if ((ti->ti_sum = in_cksum(m, len))) {#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_CRITICAL event */ WV_NET_EVENT_0 (NET_CORE_EVENT, WV_NET_CRITICAL, 30, 2, WV_NETEVENT_TCPIN_BADSUM, WV_NET_RECV)#endif /* INCLUDE_WVNET */#endif tcpstat.tcps_rcvbadsum++; goto drop; } /* * Check that TCP offset makes sense, * pull out TCP options and adjust length. XXX */ off = ti->ti_off << 2; if (off < sizeof (struct tcphdr) || off > tlen) {#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_CRITICAL event */ WV_NET_PORTIN_EVENT_1 (NET_CORE_EVENT, WV_NET_CRITICAL, 31, 3, ti->ti_sport, ti->ti_dport, WV_NETEVENT_TCPIN_BADSEG, WV_NET_RECV, off)#endif /* INCLUDE_WVNET */#endif tcpstat.tcps_rcvbadoff++; goto drop; } tlen -= off; ti->ti_len = tlen; if (off > sizeof (struct tcphdr)) { if (m->m_len < sizeof(struct ip) + off) { if ((m = m_pullup(m, sizeof (struct ip) + off)) == 0) {#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_VERBOSE event */ WV_NET_PORTIN_EVENT_0 (NET_CORE_EVENT, WV_NET_VERBOSE, 38, 21, ti->ti_sport, ti->ti_dport, WV_NETEVENT_TCPIN_SHORTSEG, WV_NET_RECV)#endif /* INCLUDE_WVNET */#endif tcpstat.tcps_rcvshort++; return; } ti = mtod(m, struct tcpiphdr *); } optlen = off - sizeof (struct tcphdr); optp = mtod(m, u_char *) + sizeof (struct tcpiphdr); /* * Do quick retrieval of timestamp options ("options
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -