]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - net/ipv4/tcp_input.c
Merge tag 'gpio-v5.4-2' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux...
[linux.git] / net / ipv4 / tcp_input.c
index 8a1cd93dbb09d2f06ff6e2f39b496ca28341093f..3578357abe30e92f818e5b9acf3317be1d997af5 100644 (file)
@@ -3782,6 +3782,49 @@ static void smc_parse_options(const struct tcphdr *th,
 #endif
 }
 
+/* Try to parse the MSS option from the TCP header. Return 0 on failure, clamped
+ * value on success.
+ */
+static u16 tcp_parse_mss_option(const struct tcphdr *th, u16 user_mss)
+{
+       const unsigned char *ptr = (const unsigned char *)(th + 1);
+       int length = (th->doff * 4) - sizeof(struct tcphdr);
+       u16 mss = 0;
+
+       while (length > 0) {
+               int opcode = *ptr++;
+               int opsize;
+
+               switch (opcode) {
+               case TCPOPT_EOL:
+                       return mss;
+               case TCPOPT_NOP:        /* Ref: RFC 793 section 3.1 */
+                       length--;
+                       continue;
+               default:
+                       if (length < 2)
+                               return mss;
+                       opsize = *ptr++;
+                       if (opsize < 2) /* "silly options" */
+                               return mss;
+                       if (opsize > length)
+                               return mss;     /* fail on partial options */
+                       if (opcode == TCPOPT_MSS && opsize == TCPOLEN_MSS) {
+                               u16 in_mss = get_unaligned_be16(ptr);
+
+                               if (in_mss) {
+                                       if (user_mss && user_mss < in_mss)
+                                               in_mss = user_mss;
+                                       mss = in_mss;
+                               }
+                       }
+                       ptr += opsize - 2;
+                       length -= opsize;
+               }
+       }
+       return mss;
+}
+
 /* Look for tcp options. Normally only called on SYN and SYNACK packets.
  * But, this can also be called on packets in the established flow when
  * the fast version below fails.
@@ -4512,6 +4555,7 @@ static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb)
        tp->pred_flags = 0;
        inet_csk_schedule_ack(sk);
 
+       tp->rcv_ooopack += max_t(u16, 1, skb_shinfo(skb)->gso_segs);
        NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPOFOQUEUE);
        seq = TCP_SKB_CB(skb)->seq;
        end_seq = TCP_SKB_CB(skb)->end_seq;
@@ -6422,9 +6466,7 @@ EXPORT_SYMBOL(inet_reqsk_alloc);
 /*
  * Return true if a syncookie should be sent
  */
-static bool tcp_syn_flood_action(const struct sock *sk,
-                                const struct sk_buff *skb,
-                                const char *proto)
+static bool tcp_syn_flood_action(const struct sock *sk, const char *proto)
 {
        struct request_sock_queue *queue = &inet_csk(sk)->icsk_accept_queue;
        const char *msg = "Dropping request";
@@ -6444,7 +6486,7 @@ static bool tcp_syn_flood_action(const struct sock *sk,
            net->ipv4.sysctl_tcp_syncookies != 2 &&
            xchg(&queue->synflood_warned, 1) == 0)
                net_info_ratelimited("%s: Possible SYN flooding on port %d. %s.  Check SNMP counters.\n",
-                                    proto, ntohs(tcp_hdr(skb)->dest), msg);
+                                    proto, sk->sk_num, msg);
 
        return want_cookie;
 }
@@ -6466,6 +6508,36 @@ static void tcp_reqsk_record_syn(const struct sock *sk,
        }
 }
 
+/* If a SYN cookie is required and supported, returns a clamped MSS value to be
+ * used for SYN cookie generation.
+ */
+u16 tcp_get_syncookie_mss(struct request_sock_ops *rsk_ops,
+                         const struct tcp_request_sock_ops *af_ops,
+                         struct sock *sk, struct tcphdr *th)
+{
+       struct tcp_sock *tp = tcp_sk(sk);
+       u16 mss;
+
+       if (sock_net(sk)->ipv4.sysctl_tcp_syncookies != 2 &&
+           !inet_csk_reqsk_queue_is_full(sk))
+               return 0;
+
+       if (!tcp_syn_flood_action(sk, rsk_ops->slab_name))
+               return 0;
+
+       if (sk_acceptq_is_full(sk)) {
+               NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
+               return 0;
+       }
+
+       mss = tcp_parse_mss_option(th, tp->rx_opt.user_mss);
+       if (!mss)
+               mss = af_ops->mss_clamp;
+
+       return mss;
+}
+EXPORT_SYMBOL_GPL(tcp_get_syncookie_mss);
+
 int tcp_conn_request(struct request_sock_ops *rsk_ops,
                     const struct tcp_request_sock_ops *af_ops,
                     struct sock *sk, struct sk_buff *skb)
@@ -6487,7 +6559,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
         */
        if ((net->ipv4.sysctl_tcp_syncookies == 2 ||
             inet_csk_reqsk_queue_is_full(sk)) && !isn) {
-               want_cookie = tcp_syn_flood_action(sk, skb, rsk_ops->slab_name);
+               want_cookie = tcp_syn_flood_action(sk, rsk_ops->slab_name);
                if (!want_cookie)
                        goto drop;
        }