The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netinet/tcp_timewait.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-3-Clause
    3  *
    4  * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995
    5  *      The Regents of the University of California.  All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. Neither the name of the University nor the names of its contributors
   16  *    may be used to endorse or promote products derived from this software
   17  *    without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29  * SUCH DAMAGE.
   30  *
   31  *      @(#)tcp_subr.c  8.2 (Berkeley) 5/24/95
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 __FBSDID("$FreeBSD$");
   36 
   37 #include "opt_inet.h"
   38 #include "opt_inet6.h"
   39 #include "opt_ipsec.h"
   40 
   41 #include <sys/param.h>
   42 #include <sys/systm.h>
   43 #include <sys/callout.h>
   44 #include <sys/kernel.h>
   45 #include <sys/sysctl.h>
   46 #include <sys/malloc.h>
   47 #include <sys/mbuf.h>
   48 #include <sys/priv.h>
   49 #include <sys/proc.h>
   50 #include <sys/socket.h>
   51 #include <sys/socketvar.h>
   52 #include <sys/syslog.h>
   53 #include <sys/protosw.h>
   54 #include <sys/random.h>
   55 
   56 #include <vm/uma.h>
   57 
   58 #include <net/route.h>
   59 #include <net/if.h>
   60 #include <net/if_var.h>
   61 #include <net/vnet.h>
   62 
   63 #include <netinet/in.h>
   64 #include <netinet/in_kdtrace.h>
   65 #include <netinet/in_pcb.h>
   66 #include <netinet/in_systm.h>
   67 #include <netinet/in_var.h>
   68 #include <netinet/ip.h>
   69 #include <netinet/ip_icmp.h>
   70 #include <netinet/ip_var.h>
   71 #ifdef INET6
   72 #include <netinet/ip6.h>
   73 #include <netinet6/in6_pcb.h>
   74 #include <netinet6/ip6_var.h>
   75 #include <netinet6/scope6_var.h>
   76 #include <netinet6/nd6.h>
   77 #endif
   78 #include <netinet/tcp.h>
   79 #include <netinet/tcp_fsm.h>
   80 #include <netinet/tcp_seq.h>
   81 #include <netinet/tcp_timer.h>
   82 #include <netinet/tcp_var.h>
   83 #include <netinet/tcp_hpts.h>
   84 #include <netinet/tcpip.h>
   85 
   86 #include <netinet/udp.h>
   87 #include <netinet/udp_var.h>
   88 
   89 #include <netipsec/ipsec_support.h>
   90 
   91 #include <machine/in_cksum.h>
   92 
   93 #include <security/mac/mac_framework.h>
   94 
   95 VNET_DEFINE_STATIC(bool, nolocaltimewait) = true;
   96 #define V_nolocaltimewait       VNET(nolocaltimewait)
   97 SYSCTL_BOOL(_net_inet_tcp, OID_AUTO, nolocaltimewait,
   98     CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(nolocaltimewait), true,
   99     "Do not create TCP TIME_WAIT state for local connections");
  100 
  101 /*
  102  * Move a TCP connection into TIME_WAIT state.
  103  *    inp is locked, and is unlocked before returning.
  104  *
  105  * This function used to free tcpcb and allocate a compressed TCP time-wait
  106  * structure tcptw.  This served well for 20 years but is no longer relevant
  107  * on modern machines in the modern internet.  However, the function remains
  108  * so that TCP stacks require less modification and we don't burn the bridge
  109  * to go back to using compressed time-wait.
  110  */
  111 void
  112 tcp_twstart(struct tcpcb *tp)
  113 {
  114         struct inpcb *inp = tptoinpcb(tp);
  115 #ifdef INET6
  116         bool isipv6 = inp->inp_inc.inc_flags & INC_ISIPV6;
  117 #endif
  118 
  119         NET_EPOCH_ASSERT();
  120         INP_WLOCK_ASSERT(inp);
  121 
  122         /* A dropped inp should never transition to TIME_WAIT state. */
  123         KASSERT((inp->inp_flags & INP_DROPPED) == 0, ("tcp_twstart: "
  124             "(inp->inp_flags & INP_DROPPED) != 0"));
  125 
  126         tcp_state_change(tp, TCPS_TIME_WAIT);
  127         soisdisconnected(inp->inp_socket);
  128 
  129         if (tp->t_flags & TF_ACKNOW)
  130                 tcp_output(tp);
  131 
  132         if (V_nolocaltimewait && (
  133 #ifdef INET6
  134             isipv6 ? in6_localaddr(&inp->in6p_faddr) :
  135 #endif
  136 #ifdef INET
  137             in_localip(inp->inp_faddr)
  138 #else
  139             false
  140 #endif
  141             )) {
  142                 if ((tp = tcp_close(tp)) != NULL)
  143                         INP_WUNLOCK(inp);
  144                 return;
  145         }
  146 
  147         tcp_timer_activate(tp, TT_2MSL, 2 * V_tcp_msl);
  148         INP_WUNLOCK(inp);
  149 }
  150 
  151 /*
  152  * Returns true if the TIME_WAIT state was killed and we should start over,
  153  * looking for a pcb in the listen state.  Otherwise returns false and frees
  154  * the mbuf.
  155  *
  156  * For pure SYN-segments the PCB shall be read-locked and the tcpopt pointer
  157  * may be NULL.  For the rest write-lock and valid tcpopt.
  158  */
  159 bool
  160 tcp_twcheck(struct inpcb *inp, struct tcpopt *to, struct tcphdr *th,
  161     struct mbuf *m, int tlen)
  162 {
  163         struct tcpcb *tp = intotcpcb(inp);
  164         char *s;
  165         int thflags;
  166         tcp_seq seq;
  167 
  168         NET_EPOCH_ASSERT();
  169         INP_LOCK_ASSERT(inp);
  170 
  171         thflags = tcp_get_flags(th);
  172 #ifdef INVARIANTS
  173         if ((thflags & (TH_SYN | TH_ACK)) == TH_SYN)
  174                 INP_RLOCK_ASSERT(inp);
  175         else {
  176                 INP_WLOCK_ASSERT(inp);
  177                 KASSERT(to != NULL,
  178                     ("%s: called without options on a non-SYN segment",
  179                     __func__));
  180         }
  181 #endif
  182 
  183         /*
  184          * NOTE: for FIN_WAIT_2 (to be added later),
  185          * must validate sequence number before accepting RST
  186          */
  187 
  188         /*
  189          * If the segment contains RST:
  190          *      Drop the segment - see Stevens, vol. 2, p. 964 and
  191          *      RFC 1337.
  192          */
  193         if (thflags & TH_RST)
  194                 goto drop;
  195 
  196 #if 0
  197 /* PAWS not needed at the moment */
  198         /*
  199          * RFC 1323 PAWS: If we have a timestamp reply on this segment
  200          * and it's less than ts_recent, drop it.
  201          */
  202         if ((to.to_flags & TOF_TS) != 0 && tp->ts_recent &&
  203             TSTMP_LT(to.to_tsval, tp->ts_recent)) {
  204                 if ((thflags & TH_ACK) == 0)
  205                         goto drop;
  206                 goto ack;
  207         }
  208         /*
  209          * ts_recent is never updated because we never accept new segments.
  210          */
  211 #endif
  212 
  213         /* Honor the drop_synfin sysctl variable. */
  214         if ((thflags & TH_SYN) && (thflags & TH_FIN) && V_drop_synfin) {
  215                 if ((s = tcp_log_addrs(&inp->inp_inc, th, NULL, NULL))) {
  216                         log(LOG_DEBUG, "%s; %s: "
  217                             "SYN|FIN segment ignored (based on "
  218                             "sysctl setting)\n", s, __func__);
  219                         free(s, M_TCPLOG);
  220                 }
  221                 goto drop;
  222         }
  223 
  224         /*
  225          * If a new connection request is received
  226          * while in TIME_WAIT, drop the old connection
  227          * and start over if the sequence numbers
  228          * are above the previous ones.
  229          * Allow UDP port number changes in this case.
  230          */
  231         if (((thflags & (TH_SYN | TH_ACK)) == TH_SYN) &&
  232             SEQ_GT(th->th_seq, tp->rcv_nxt)) {
  233                 /*
  234                  * In case we can't upgrade our lock just pretend we have
  235                  * lost this packet.
  236                  */
  237                 if (INP_TRY_UPGRADE(inp) == 0)
  238                         goto drop;
  239                 if ((tp = tcp_close(tp)) != NULL)
  240                         INP_WUNLOCK(inp);
  241                 TCPSTAT_INC(tcps_tw_recycles);
  242                 return (true);
  243         }
  244 
  245         /*
  246          * Send RST if UDP port numbers don't match
  247          */
  248         if (tp->t_port != m->m_pkthdr.tcp_tun_port) {
  249                 if (tcp_get_flags(th) & TH_ACK) {
  250                         tcp_respond(tp, mtod(m, void *), th, m,
  251                             (tcp_seq)0, th->th_ack, TH_RST);
  252                 } else {
  253                         if (tcp_get_flags(th) & TH_SYN)
  254                                 tlen++;
  255                         if (tcp_get_flags(th) & TH_FIN)
  256                                 tlen++;
  257                         tcp_respond(tp, mtod(m, void *), th, m,
  258                             th->th_seq+tlen, (tcp_seq)0, TH_RST|TH_ACK);
  259                 }
  260                 INP_UNLOCK(inp);
  261                 TCPSTAT_INC(tcps_tw_resets);
  262                 return (false);
  263         }
  264 
  265         /*
  266          * Drop the segment if it does not contain an ACK.
  267          */
  268         if ((thflags & TH_ACK) == 0)
  269                 goto drop;
  270 
  271         INP_WLOCK_ASSERT(inp);
  272 
  273         /*
  274          * If timestamps were negotiated during SYN/ACK and a
  275          * segment without a timestamp is received, silently drop
  276          * the segment, unless the missing timestamps are tolerated.
  277          * See section 3.2 of RFC 7323.
  278          */
  279         if (((to->to_flags & TOF_TS) == 0) && (tp->ts_recent != 0) &&
  280             (V_tcp_tolerate_missing_ts == 0)) {
  281                 goto drop;
  282         }
  283 
  284         /*
  285          * Reset the 2MSL timer if this is a duplicate FIN.
  286          */
  287         if (thflags & TH_FIN) {
  288                 seq = th->th_seq + tlen + (thflags & TH_SYN ? 1 : 0);
  289                 if (seq + 1 == tp->rcv_nxt)
  290                         tcp_timer_activate(tp, TT_2MSL, 2 * V_tcp_msl);
  291         }
  292 
  293         /*
  294          * Acknowledge the segment if it has data or is not a duplicate ACK.
  295          */
  296         if (thflags != TH_ACK || tlen != 0 ||
  297             th->th_seq != tp->rcv_nxt || th->th_ack != tp->snd_nxt) {
  298                 TCP_PROBE5(receive, NULL, NULL, m, NULL, th);
  299                 tcp_respond(tp, mtod(m, void *), th, m, tp->rcv_nxt,
  300                     tp->snd_nxt, TH_ACK);
  301                 INP_UNLOCK(inp);
  302                 TCPSTAT_INC(tcps_tw_responds);
  303                 return (false);
  304         }
  305 drop:
  306         TCP_PROBE5(receive, NULL, NULL, m, NULL, th);
  307         INP_UNLOCK(inp);
  308         m_freem(m);
  309         return (false);
  310 }

Cache object: 7833c826d84710ed02b190ea70433105


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.