summaryrefslogtreecommitdiffstats
path: root/sys/netinet/tcp_subr.c
diff options
context:
space:
mode:
authorandre <andre@FreeBSD.org>2007-05-13 22:16:13 +0000
committerandre <andre@FreeBSD.org>2007-05-13 22:16:13 +0000
commit25d7c9695a21b0d5638e2880e26fbce735bd36f9 (patch)
treefbfc990be06928fffd46d3d8014bb2017f4a7456 /sys/netinet/tcp_subr.c
parent7785ed9f788559ea9a9e2af3b3090d1d247df6d8 (diff)
downloadFreeBSD-src-25d7c9695a21b0d5638e2880e26fbce735bd36f9.zip
FreeBSD-src-25d7c9695a21b0d5638e2880e26fbce735bd36f9.tar.gz
Complete the (mechanical) move of the TCP reassembly and timewait
functions from their origininal place to their own files. TCP Reassembly from tcp_input.c -> tcp_reass.c TCP Timewait from tcp_subr.c -> tcp_timewait.c
Diffstat (limited to 'sys/netinet/tcp_subr.c')
-rw-r--r--sys/netinet/tcp_subr.c354
1 files changed, 2 insertions, 352 deletions
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index 90c2aba..8d2e8e4 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -162,52 +162,6 @@ 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 uma_zone_t tcptw_zone;
-static int maxtcptw;
-
-static int
-tcptw_auto_size(void)
-{
- int halfrange;
-
- /*
- * Max out at half the ephemeral port range so that TIME_WAIT
- * sockets don't tie up too many ephemeral ports.
- */
- if (ipport_lastauto > ipport_firstauto)
- halfrange = (ipport_lastauto - ipport_firstauto) / 2;
- else
- halfrange = (ipport_firstauto - ipport_lastauto) / 2;
- /* Protect against goofy port ranges smaller than 32. */
- return (imin(imax(halfrange, 32), maxsockets / 5));
-}
-
-static int
-sysctl_maxtcptw(SYSCTL_HANDLER_ARGS)
-{
- int error, new;
-
- if (maxtcptw == 0)
- new = tcptw_auto_size();
- else
- new = maxtcptw;
- error = sysctl_handle_int(oidp, &new, sizeof(int), req);
- if (error == 0 && req->newptr)
- if (new >= 32) {
- maxtcptw = new;
- uma_zone_set_max(tcptw_zone, maxtcptw);
- }
- return (error);
-}
-SYSCTL_PROC(_net_inet_tcp, OID_AUTO, maxtcptw, CTLTYPE_INT|CTLFLAG_RW,
- &maxtcptw, 0, sysctl_maxtcptw, "IU",
- "Maximum number of compressed TCP TIME_WAIT entries");
-
-static int nolocaltimewait = 0;
-SYSCTL_INT(_net_inet_tcp, OID_AUTO, nolocaltimewait, CTLFLAG_RW,
- &nolocaltimewait, 0,
- "Do not create compressed TCP TIME_WAIT entries for local connections");
-
/*
* TCP bandwidth limiting sysctls. Note that the default lower bound of
* 1024 exists only for debugging. A good production default would be
@@ -284,8 +238,7 @@ tcp_zone_change(void *tag)
uma_zone_set_max(tcbinfo.ipi_zone, maxsockets);
uma_zone_set_max(tcpcb_zone, maxsockets);
- if (maxtcptw == 0)
- uma_zone_set_max(tcptw_zone, tcptw_auto_size());
+ tcp_tw_zone_change();
}
static int
@@ -345,14 +298,8 @@ tcp_init(void)
tcpcb_zone = uma_zcreate("tcpcb", sizeof(struct tcpcb_mem),
NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
uma_zone_set_max(tcpcb_zone, maxsockets);
- tcptw_zone = uma_zcreate("tcptw", sizeof(struct tcptw),
- NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
- TUNABLE_INT_FETCH("net.inet.tcp.maxtcptw", &maxtcptw);
- if (maxtcptw == 0)
- uma_zone_set_max(tcptw_zone, tcptw_auto_size());
- else
- uma_zone_set_max(tcptw_zone, maxtcptw);
tcp_timer_init();
+ tcp_tw_init();
syncache_init();
tcp_hc_init();
tcp_reass_init();
@@ -1742,303 +1689,6 @@ ipsec_hdrsiz_tcp(struct tcpcb *tp)
#endif /*IPSEC*/
/*
- * Move a TCP connection into TIME_WAIT state.
- * tcbinfo is locked.
- * inp is locked, and is unlocked before returning.
- */
-void
-tcp_twstart(struct tcpcb *tp)
-{
- struct tcptw *tw;
- struct inpcb *inp = tp->t_inpcb;
- int acknow;
- struct socket *so;
-
- INP_INFO_WLOCK_ASSERT(&tcbinfo); /* tcp_timer_2msl_reset(). */
- INP_LOCK_ASSERT(inp);
-
- if (nolocaltimewait && in_localip(inp->inp_faddr)) {
- tp = tcp_close(tp);
- if (tp != NULL)
- INP_UNLOCK(inp);
- return;
- }
-
- tw = uma_zalloc(tcptw_zone, M_NOWAIT);
- if (tw == NULL) {
- tw = tcp_timer_2msl_tw(1);
- if (tw == NULL) {
- tp = tcp_close(tp);
- if (tp != NULL)
- INP_UNLOCK(inp);
- return;
- }
- }
- tw->tw_inpcb = inp;
-
- /*
- * Recover last window size sent.
- */
- tw->last_win = (tp->rcv_adv - tp->rcv_nxt) >> tp->rcv_scale;
-
- /*
- * Set t_recent if timestamps are used on the connection.
- */
- if ((tp->t_flags & (TF_REQ_TSTMP|TF_RCVD_TSTMP|TF_NOOPT)) ==
- (TF_REQ_TSTMP|TF_RCVD_TSTMP)) {
- tw->t_recent = tp->ts_recent;
- tw->ts_offset = tp->ts_offset;
- } else {
- tw->t_recent = 0;
- tw->ts_offset = 0;
- }
-
- tw->snd_nxt = tp->snd_nxt;
- tw->rcv_nxt = tp->rcv_nxt;
- tw->iss = tp->iss;
- tw->irs = tp->irs;
- tw->t_starttime = tp->t_starttime;
- tw->tw_time = 0;
-
-/* XXX
- * If this code will
- * be used for fin-wait-2 state also, then we may need
- * a ts_recent from the last segment.
- */
- acknow = tp->t_flags & TF_ACKNOW;
-
- /*
- * First, discard tcpcb state, which includes stopping its timers and
- * freeing it. tcp_discardcb() used to also release the inpcb, but
- * that work is now done in the caller.
- *
- * Note: soisdisconnected() call used to be made in tcp_discardcb(),
- * and might not be needed here any longer.
- */
- tcp_discardcb(tp);
- so = inp->inp_socket;
- soisdisconnected(so);
- tw->tw_cred = crhold(so->so_cred);
- SOCK_LOCK(so);
- tw->tw_so_options = so->so_options;
- SOCK_UNLOCK(so);
- if (acknow)
- tcp_twrespond(tw, TH_ACK);
- inp->inp_ppcb = tw;
- inp->inp_vflag |= INP_TIMEWAIT;
- tcp_timer_2msl_reset(tw, 0);
-
- /*
- * If the inpcb owns the sole reference to the socket, then we can
- * detach and free the socket as it is not needed in time wait.
- */
- if (inp->inp_vflag & INP_SOCKREF) {
- KASSERT(so->so_state & SS_PROTOREF,
- ("tcp_twstart: !SS_PROTOREF"));
- inp->inp_vflag &= ~INP_SOCKREF;
- INP_UNLOCK(inp);
- ACCEPT_LOCK();
- SOCK_LOCK(so);
- so->so_state &= ~SS_PROTOREF;
- sofree(so);
- } else
- INP_UNLOCK(inp);
-}
-
-#if 0
-/*
- * The appromixate rate of ISN increase of Microsoft TCP stacks;
- * the actual rate is slightly higher due to the addition of
- * random positive increments.
- *
- * Most other new OSes use semi-randomized ISN values, so we
- * do not need to worry about them.
- */
-#define MS_ISN_BYTES_PER_SECOND 250000
-
-/*
- * Determine if the ISN we will generate has advanced beyond the last
- * sequence number used by the previous connection. If so, indicate
- * that it is safe to recycle this tw socket by returning 1.
- */
-int
-tcp_twrecycleable(struct tcptw *tw)
-{
- tcp_seq new_iss = tw->iss;
- tcp_seq new_irs = tw->irs;
-
- INP_INFO_WLOCK_ASSERT(&tcbinfo);
- new_iss += (ticks - tw->t_starttime) * (ISN_BYTES_PER_SECOND / hz);
- new_irs += (ticks - tw->t_starttime) * (MS_ISN_BYTES_PER_SECOND / hz);
-
- if (SEQ_GT(new_iss, tw->snd_nxt) && SEQ_GT(new_irs, tw->rcv_nxt))
- return (1);
- else
- return (0);
-}
-#endif
-
-void
-tcp_twclose(struct tcptw *tw, int reuse)
-{
- struct socket *so;
- struct inpcb *inp;
-
- /*
- * At this point, we are in one of two situations:
- *
- * (1) We have no socket, just an inpcb<->twtcp pair. We can free
- * all state.
- *
- * (2) We have a socket -- if we own a reference, release it and
- * notify the socket layer.
- */
- inp = tw->tw_inpcb;
- KASSERT((inp->inp_vflag & INP_TIMEWAIT), ("tcp_twclose: !timewait"));
- KASSERT(intotw(inp) == tw, ("tcp_twclose: inp_ppcb != tw"));
- INP_INFO_WLOCK_ASSERT(&tcbinfo); /* tcp_timer_2msl_stop(). */
- INP_LOCK_ASSERT(inp);
-
- tw->tw_inpcb = NULL;
- tcp_timer_2msl_stop(tw);
- inp->inp_ppcb = NULL;
- in_pcbdrop(inp);
-
- so = inp->inp_socket;
- if (so != NULL) {
- /*
- * If there's a socket, handle two cases: first, we own a
- * strong reference, which we will now release, or we don't
- * in which case another reference exists (XXXRW: think
- * about this more), and we don't need to take action.
- */
- if (inp->inp_vflag & INP_SOCKREF) {
- inp->inp_vflag &= ~INP_SOCKREF;
- INP_UNLOCK(inp);
- ACCEPT_LOCK();
- SOCK_LOCK(so);
- KASSERT(so->so_state & SS_PROTOREF,
- ("tcp_twclose: INP_SOCKREF && !SS_PROTOREF"));
- so->so_state &= ~SS_PROTOREF;
- sofree(so);
- } else {
- /*
- * If we don't own the only reference, the socket and
- * inpcb need to be left around to be handled by
- * tcp_usr_detach() later.
- */
- INP_UNLOCK(inp);
- }
- } else {
-#ifdef INET6
- if (inp->inp_vflag & INP_IPV6PROTO)
- in6_pcbfree(inp);
- else
-#endif
- in_pcbfree(inp);
- }
- tcpstat.tcps_closed++;
- crfree(tw->tw_cred);
- tw->tw_cred = NULL;
- if (reuse)
- return;
- uma_zfree(tcptw_zone, tw);
-}
-
-int
-tcp_twrespond(struct tcptw *tw, int flags)
-{
- struct inpcb *inp = tw->tw_inpcb;
- struct tcphdr *th;
- struct mbuf *m;
- struct ip *ip = NULL;
- u_int hdrlen, optlen;
- int error;
- struct tcpopt to;
-#ifdef INET6
- struct ip6_hdr *ip6 = NULL;
- int isipv6 = inp->inp_inc.inc_isipv6;
-#endif
-
- INP_LOCK_ASSERT(inp);
-
- m = m_gethdr(M_DONTWAIT, MT_DATA);
- if (m == NULL)
- return (ENOBUFS);
- m->m_data += max_linkhdr;
-
-#ifdef MAC
- mac_create_mbuf_from_inpcb(inp, m);
-#endif
-
-#ifdef INET6
- if (isipv6) {
- hdrlen = sizeof(struct ip6_hdr) + sizeof(struct tcphdr);
- ip6 = mtod(m, struct ip6_hdr *);
- th = (struct tcphdr *)(ip6 + 1);
- tcpip_fillheaders(inp, ip6, th);
- } else
-#endif
- {
- hdrlen = sizeof(struct tcpiphdr);
- ip = mtod(m, struct ip *);
- th = (struct tcphdr *)(ip + 1);
- tcpip_fillheaders(inp, ip, th);
- }
- to.to_flags = 0;
-
- /*
- * Send a timestamp and echo-reply if both our side and our peer
- * have sent timestamps in our SYN's and this is not a RST.
- */
- if (tw->t_recent && flags == TH_ACK) {
- to.to_flags |= TOF_TS;
- to.to_tsval = ticks + tw->ts_offset;
- to.to_tsecr = tw->t_recent;
- }
- optlen = tcp_addoptions(&to, (u_char *)(th + 1));
-
- m->m_len = hdrlen + optlen;
- m->m_pkthdr.len = m->m_len;
-
- KASSERT(max_linkhdr + m->m_len <= MHLEN, ("tcptw: mbuf too small"));
-
- th->th_seq = htonl(tw->snd_nxt);
- th->th_ack = htonl(tw->rcv_nxt);
- th->th_off = (sizeof(struct tcphdr) + optlen) >> 2;
- th->th_flags = flags;
- th->th_win = htons(tw->last_win);
-
-#ifdef INET6
- if (isipv6) {
- th->th_sum = in6_cksum(m, IPPROTO_TCP, sizeof(struct ip6_hdr),
- sizeof(struct tcphdr) + optlen);
- ip6->ip6_hlim = in6_selecthlim(inp, NULL);
- error = ip6_output(m, inp->in6p_outputopts, NULL,
- (tw->tw_so_options & SO_DONTROUTE), NULL, NULL, inp);
- } else
-#endif
- {
- th->th_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr,
- htons(sizeof(struct tcphdr) + optlen + IPPROTO_TCP));
- m->m_pkthdr.csum_flags = CSUM_TCP;
- m->m_pkthdr.csum_data = offsetof(struct tcphdr, th_sum);
- ip->ip_len = m->m_pkthdr.len;
- if (path_mtu_discovery)
- ip->ip_off |= IP_DF;
- error = ip_output(m, inp->inp_options, NULL,
- ((tw->tw_so_options & SO_DONTROUTE) ? IP_ROUTETOIF : 0),
- NULL, inp);
- }
- if (flags & TH_ACK)
- tcpstat.tcps_sndacks++;
- else
- tcpstat.tcps_sndctrl++;
- tcpstat.tcps_sndtotal++;
- return (error);
-}
-
-/*
* TCP BANDWIDTH DELAY PRODUCT WINDOW LIMITING
*
* This code attempts to calculate the bandwidth-delay product as a
OpenPOWER on IntegriCloud