tcp_subr.c

来自「eCos操作系统源码」· C语言 代码 · 共 1,397 行 · 第 1/3 页

C
1,397
字号
//==========================================================================////      src/sys/netinet/tcp_subr.c////==========================================================================//####BSDCOPYRIGHTBEGIN####//// -------------------------------------------//// Portions of this software may have been derived from OpenBSD, // FreeBSD or other sources, and are covered by the appropriate// copyright disclaimers included herein.//// Portions created by Red Hat are// Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.//// -------------------------------------------////####BSDCOPYRIGHTEND####//==========================================================================/* * Copyright (c) 1982, 1986, 1988, 1990, 1993, 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_subr.c	8.2 (Berkeley) 5/24/95 * $FreeBSD: src/sys/netinet/tcp_subr.c,v 1.73.2.22 2001/08/22 00:59:12 silby Exp $ */#include <sys/param.h>#include <sys/malloc.h>#include <sys/sysctl.h>#include <sys/mbuf.h>#ifdef INET6#include <sys/domain.h>#endif#include <sys/socket.h>#include <sys/socketvar.h>#include <sys/protosw.h>#include <net/route.h>#include <net/if.h>#define _IP_VHL#include <netinet/in.h>#include <netinet/in_systm.h>#include <netinet/ip.h>#ifdef INET6#include <netinet/ip6.h>#endif#include <netinet/in_pcb.h>#ifdef INET6#include <netinet6/in6_pcb.h>#endif#include <netinet/in_var.h>#include <netinet/ip_var.h>#ifdef INET6#include <netinet6/ip6_var.h>#endif#include <netinet/tcp.h>#include <netinet/tcp_fsm.h>#include <netinet/tcp_seq.h>#include <netinet/tcp_timer.h>#include <netinet/tcp_var.h>#ifdef INET6#include <netinet6/tcp6_var.h>#include <netinet6/ip6protosw.h>#endif#include <netinet/tcpip.h>#ifdef TCPDEBUG#include <netinet/tcp_debug.h>#endif#ifdef IPSEC#include <netinet6/ipsec.h>#endif /*IPSEC*/#include <sys/md5.h>int 	tcp_mssdflt = TCP_MSS;SYSCTL_INT(_net_inet_tcp, TCPCTL_MSSDFLT, mssdflt, CTLFLAG_RW,     &tcp_mssdflt , 0, "Default TCP Maximum Segment Size");#ifdef INET6int	tcp_v6mssdflt = TCP6_MSS;SYSCTL_INT(_net_inet_tcp, TCPCTL_V6MSSDFLT, v6mssdflt,	CTLFLAG_RW, &tcp_v6mssdflt , 0,	"Default TCP Maximum Segment Size for IPv6");#endif#if 0static int 	tcp_rttdflt = TCPTV_SRTTDFLT / PR_SLOWHZ;SYSCTL_INT(_net_inet_tcp, TCPCTL_RTTDFLT, rttdflt, CTLFLAG_RW,     &tcp_rttdflt , 0, "Default maximum TCP Round Trip Time");#endifstatic int	tcp_do_rfc1323 = 1;SYSCTL_INT(_net_inet_tcp, TCPCTL_DO_RFC1323, rfc1323, CTLFLAG_RW,     &tcp_do_rfc1323 , 0, "Enable rfc1323 (high performance TCP) extensions");static int	tcp_do_rfc1644 = 0;SYSCTL_INT(_net_inet_tcp, TCPCTL_DO_RFC1644, rfc1644, CTLFLAG_RW,     &tcp_do_rfc1644 , 0, "Enable rfc1644 (TTCP) extensions");static int	tcp_tcbhashsize = 0;SYSCTL_INT(_net_inet_tcp, OID_AUTO, tcbhashsize, CTLFLAG_RD,     &tcp_tcbhashsize, 0, "Size of TCP control-block hashtable");static int	do_tcpdrain = 1;SYSCTL_INT(_net_inet_tcp, OID_AUTO, do_tcpdrain, CTLFLAG_RW, &do_tcpdrain, 0,     "Enable tcp_drain routine for extra help when low on mbufs");SYSCTL_INT(_net_inet_tcp, OID_AUTO, pcbcount, CTLFLAG_RD,     &tcbinfo.ipi_count, 0, "Number of active PCBs");static int	icmp_may_rst = 1;SYSCTL_INT(_net_inet_tcp, OID_AUTO, icmp_may_rst, CTLFLAG_RW, &icmp_may_rst, 0,     "Certain ICMP unreachable messages may abort connections in SYN_SENT");static int	tcp_strict_rfc1948 = 0;SYSCTL_INT(_net_inet_tcp, OID_AUTO, strict_rfc1948, CTLFLAG_RW,    &tcp_strict_rfc1948, 0, "Determines if RFC1948 is followed exactly");static int	tcp_isn_reseed_interval = 0;SYSCTL_INT(_net_inet_tcp, OID_AUTO, isn_reseed_interval, CTLFLAG_RW,    &tcp_isn_reseed_interval, 0, "Seconds between reseeding of ISN secret");    static void	tcp_cleartaocache __P((void));static void	tcp_notify __P((struct inpcb *, int));/* * Target size of TCP PCB hash tables. Must be a power of two. * * Note that this can be overridden by the kernel environment * variable net.inet.tcp.tcbhashsize */#ifndef TCBHASHSIZE#define TCBHASHSIZE	512#endif/* * This is the actual shape of what we allocate using the zone * allocator.  Doing it this way allows us to protect both structures * using the same generation count, and also eliminates the overhead * of allocating tcpcbs separately.  By hiding the structure here, * we avoid changing most of the rest of the code (although it needs * to be changed, eventually, for greater efficiency). */#define	ALIGNMENT	32#define	ALIGNM1		(ALIGNMENT - 1)struct	inp_tp {	union {		struct	inpcb inp;		char	align[(sizeof(struct inpcb) + ALIGNM1) & ~ALIGNM1];	} inp_tp_u;	struct	tcpcb tcb;	struct	callout inp_tp_rexmt, inp_tp_persist, inp_tp_keep, inp_tp_2msl;	struct	callout inp_tp_delack;};#undef ALIGNMENT#undef ALIGNM1/* * Tcp initialization */voidtcp_init(){	int hashsize = TCBHASHSIZE;		tcp_ccgen = 1;	tcp_cleartaocache();	tcp_delacktime = TCPTV_DELACK;	tcp_keepinit = TCPTV_KEEP_INIT;	tcp_keepidle = TCPTV_KEEP_IDLE;	tcp_keepintvl = TCPTV_KEEPINTVL;	tcp_maxpersistidle = TCPTV_KEEP_IDLE;	tcp_msl = TCPTV_MSL;	tcp_rexmit_min = TCPTV_MIN;	LIST_INIT(&tcb);	tcbinfo.listhead = &tcb;	tcp_tcbhashsize = hashsize;	tcbinfo.hashbase = hashinit(hashsize, M_PCB, &tcbinfo.hashmask);	tcbinfo.porthashbase = hashinit(hashsize, M_PCB,					&tcbinfo.porthashmask);	tcbinfo.ipi_zone = zinit("tcpcb", sizeof(struct inp_tp), maxsockets,				 ZONE_INTERRUPT, 0);#ifdef INET6#define TCP_MINPROTOHDR (sizeof(struct ip6_hdr) + sizeof(struct tcphdr))#else /* INET6 */#define TCP_MINPROTOHDR (sizeof(struct tcpiphdr))#endif /* INET6 */	if (max_protohdr < TCP_MINPROTOHDR)		max_protohdr = TCP_MINPROTOHDR;	if (max_linkhdr + TCP_MINPROTOHDR > MHLEN)		panic("tcp_init");#undef TCP_MINPROTOHDR}/* * Fill in the IP and TCP headers for an outgoing packet, given the tcpcb. * tcp_template used to store this data in mbufs, but we now recopy it out * of the tcpcb each time to conserve mbufs. */voidtcp_fillheaders(tp, ip_ptr, tcp_ptr)	struct tcpcb *tp;	void *ip_ptr;	void *tcp_ptr;{	struct inpcb *inp = tp->t_inpcb;	struct tcphdr *tcp_hdr = (struct tcphdr *)tcp_ptr;#ifdef INET6	if ((inp->inp_vflag & INP_IPV6) != 0) {		struct ip6_hdr *ip6;		ip6 = (struct ip6_hdr *)ip_ptr;		ip6->ip6_flow = (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) |			(inp->in6p_flowinfo & IPV6_FLOWINFO_MASK);		ip6->ip6_vfc = (ip6->ip6_vfc & ~IPV6_VERSION_MASK) |			(IPV6_VERSION & IPV6_VERSION_MASK);		ip6->ip6_nxt = IPPROTO_TCP;		ip6->ip6_plen = sizeof(struct tcphdr);		ip6->ip6_src = inp->in6p_laddr;		ip6->ip6_dst = inp->in6p_faddr;		tcp_hdr->th_sum = 0;	} else#endif	{	struct ip *ip = (struct ip *) ip_ptr;	ip->ip_vhl = IP_VHL_BORING;	ip->ip_tos = 0;	ip->ip_len = 0;	ip->ip_id = 0;	ip->ip_off = 0;	ip->ip_ttl = 0;	ip->ip_sum = 0;	ip->ip_p = IPPROTO_TCP;	ip->ip_src = inp->inp_laddr;	ip->ip_dst = inp->inp_faddr;	tcp_hdr->th_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr,		htons(sizeof(struct tcphdr) + IPPROTO_TCP));	}	tcp_hdr->th_sport = inp->inp_lport;	tcp_hdr->th_dport = inp->inp_fport;	tcp_hdr->th_seq = 0;	tcp_hdr->th_ack = 0;	tcp_hdr->th_x2 = 0;	tcp_hdr->th_off = 5;	tcp_hdr->th_flags = 0;	tcp_hdr->th_win = 0;	tcp_hdr->th_urp = 0;}/* * Create template to be used to send tcp packets on a connection. * Allocates an mbuf and fills in a skeletal tcp/ip header.  The only * use for this function is in keepalives, which use tcp_respond. */struct tcptemp *tcp_maketemplate(tp)	struct tcpcb *tp;{	struct mbuf *m;	struct tcptemp *n;	m = m_get(M_DONTWAIT, MT_HEADER);	if (m == NULL)		return (0);	m->m_len = sizeof(struct tcptemp);	n = mtod(m, struct tcptemp *);	tcp_fillheaders(tp, (void *)&n->tt_ipgen, (void *)&n->tt_t);	return (n);}/* * Send a single message to the TCP at address specified by * the given TCP/IP header.  If m == 0, then we make a copy * of the tcpiphdr at ti and send directly to the addressed host. * This is used to force keep alive messages out using the TCP * template for a connection.  If flags are given then we send * a message back to the TCP which originated the * segment ti, * and discard the mbuf containing it and any other attached mbufs. * * In any case the ack and sequence number of the transmitted * segment are as specified by the parameters. * * NOTE: If m != NULL, then ti must point to *inside* the mbuf. */voidtcp_respond(tp, ipgen, th, m, ack, seq, flags)	struct tcpcb *tp;	void *ipgen;	register struct tcphdr *th;	register struct mbuf *m;	tcp_seq ack, seq;	int flags;{	register int tlen;	int win = 0;	struct route *ro = 0;	struct route sro;	struct ip *ip;	struct tcphdr *nth;#ifdef INET6#ifdef NEW_STRUCT_ROUTE	struct route *ro6 = 0;	struct route sro6;#else	struct route_in6 *ro6 = 0;	struct route_in6 sro6;#endif	struct ip6_hdr *ip6;	int isipv6;#endif /* INET6 */	int ipflags = 0;#ifdef INET6	isipv6 = IP_VHL_V(((struct ip *)ipgen)->ip_vhl) == 6;	ip6 = ipgen;#endif /* INET6 */	ip = ipgen;	if (tp) {		if (!(flags & TH_RST)) {			win = sbspace(&tp->t_inpcb->inp_socket->so_rcv);			if (win > (long)TCP_MAXWIN << tp->rcv_scale)				win = (long)TCP_MAXWIN << tp->rcv_scale;		}#ifdef INET6		if (isipv6)			ro6 = &tp->t_inpcb->in6p_route;		else#endif /* INET6 */		ro = &tp->t_inpcb->inp_route;	} else {#ifdef INET6		if (isipv6) {			ro6 = &sro6;			bzero(ro6, sizeof *ro6);		} else#endif /* INET6 */	      {		ro = &sro;		bzero(ro, sizeof *ro);	      }	}	if (m == 0) {		m = m_gethdr(M_DONTWAIT, MT_HEADER);		if (m == NULL)			return;		tlen = 0;		m->m_data += max_linkhdr;#ifdef INET6		if (isipv6) {			bcopy((caddr_t)ip6, mtod(m, caddr_t), 			      sizeof(struct ip6_hdr));			ip6 = mtod(m, struct ip6_hdr *);			nth = (struct tcphdr *)(ip6 + 1);		} else#endif /* INET6 */	      {		bcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip));		ip = mtod(m, struct ip *);		nth = (struct tcphdr *)(ip + 1);	      }		bcopy((caddr_t)th, (caddr_t)nth, sizeof(struct tcphdr));		flags = TH_ACK;	} else {		m_freem(m->m_next);		m->m_next = 0;		m->m_data = (caddr_t)ipgen;		/* m_len is set later */		tlen = 0;#define xchg(a,b,type) { type t; t=a; a=b; b=t; }#ifdef INET6		if (isipv6) {			xchg(ip6->ip6_dst, ip6->ip6_src, struct in6_addr);			nth = (struct tcphdr *)(ip6 + 1);		} else#endif /* INET6 */	      {		xchg(ip->ip_dst.s_addr, ip->ip_src.s_addr, n_long);		nth = (struct tcphdr *)(ip + 1);	      }		if (th != nth) {			/*			 * this is usually a case when an extension header			 * exists between the IPv6 header and the			 * TCP header.			 */			nth->th_sport = th->th_sport;			nth->th_dport = th->th_dport;		}		xchg(nth->th_dport, nth->th_sport, n_short);#undef xchg	}#ifdef INET6	if (isipv6) {		ip6->ip6_plen = htons((u_short)(sizeof (struct tcphdr) +						tlen));		tlen += sizeof (struct ip6_hdr) + sizeof (struct tcphdr);	} else#endif      {	tlen += sizeof (struct tcpiphdr);	ip->ip_len = tlen;	ip->ip_ttl = ip_defttl;      }	m->m_len = tlen;	m->m_pkthdr.len = tlen;	m->m_pkthdr.rcvif = (struct ifnet *) 0;	nth->th_seq = htonl(seq);	nth->th_ack = htonl(ack);	nth->th_x2 = 0;	nth->th_off = sizeof (struct tcphdr) >> 2;	nth->th_flags = flags;	if (tp)		nth->th_win = htons((u_short) (win >> tp->rcv_scale));	else		nth->th_win = htons((u_short)win);	nth->th_urp = 0;#ifdef INET6	if (isipv6) {		nth->th_sum = 0;		nth->th_sum = in6_cksum(m, IPPROTO_TCP,					sizeof(struct ip6_hdr),					tlen - sizeof(struct ip6_hdr));		ip6->ip6_hlim = in6_selecthlim(tp ? tp->t_inpcb : NULL,					       ro6 && ro6->ro_rt ?					       ro6->ro_rt->rt_ifp :					       NULL);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?