]> Pileus Git - ~andy/linux/blobdiff - net/ipv4/af_inet.c
Merge tag 'fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm...
[~andy/linux] / net / ipv4 / af_inet.c
index 70011e029ac13718d72d7172776ac8cb76798ced..19ab78aca547fc7fb45e56607e7adafd0036d947 100644 (file)
 static struct list_head inetsw[SOCK_MAX];
 static DEFINE_SPINLOCK(inetsw_lock);
 
-struct ipv4_config ipv4_config;
-EXPORT_SYMBOL(ipv4_config);
-
 /* New destruction routine */
 
 void inet_sock_destruct(struct sock *sk)
@@ -342,7 +339,7 @@ lookup_protocol:
                        inet->hdrincl = 1;
        }
 
-       if (ipv4_config.no_pmtu_disc)
+       if (net->ipv4.sysctl_ip_no_pmtu_disc)
                inet->pmtudisc = IP_PMTUDISC_DONT;
        else
                inet->pmtudisc = IP_PMTUDISC_WANT;
@@ -1133,7 +1130,7 @@ static int inet_sk_reselect_saddr(struct sock *sk)
        fl4 = &inet->cork.fl.u.ip4;
        rt = ip_route_connect(fl4, daddr, 0, RT_CONN_FLAGS(sk),
                              sk->sk_bound_dev_if, sk->sk_protocol,
-                             inet->inet_sport, inet->inet_dport, sk, false);
+                             inet->inet_sport, inet->inet_dport, sk);
        if (IS_ERR(rt))
                return PTR_ERR(rt);
 
@@ -1299,8 +1296,11 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb,
 
        segs = ERR_PTR(-EPROTONOSUPPORT);
 
-       /* Note : following gso_segment() might change skb->encapsulation */
-       udpfrag = !skb->encapsulation && proto == IPPROTO_UDP;
+       if (skb->encapsulation &&
+           skb_shinfo(skb)->gso_type & (SKB_GSO_SIT|SKB_GSO_IPIP))
+               udpfrag = proto == IPPROTO_UDP && encap;
+       else
+               udpfrag = proto == IPPROTO_UDP && !skb->encapsulation;
 
        ops = rcu_dereference(inet_offloads[proto]);
        if (likely(ops && ops->callbacks.gso_segment))
@@ -1377,8 +1377,12 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head,
                if (!NAPI_GRO_CB(p)->same_flow)
                        continue;
 
-               iph2 = ip_hdr(p);
-
+               iph2 = (struct iphdr *)(p->data + off);
+               /* The above works because, with the exception of the top
+                * (inner most) layer, we only aggregate pkts with the same
+                * hdr length so all the hdrs we'll need to verify will start
+                * at the same offset.
+                */
                if ((iph->protocol ^ iph2->protocol) |
                    ((__force u32)iph->saddr ^ (__force u32)iph2->saddr) |
                    ((__force u32)iph->daddr ^ (__force u32)iph2->daddr)) {
@@ -1390,13 +1394,24 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head,
                NAPI_GRO_CB(p)->flush |=
                        (iph->ttl ^ iph2->ttl) |
                        (iph->tos ^ iph2->tos) |
-                       (__force int)((iph->frag_off ^ iph2->frag_off) & htons(IP_DF)) |
-                       ((u16)(ntohs(iph2->id) + NAPI_GRO_CB(p)->count) ^ id);
+                       ((iph->frag_off ^ iph2->frag_off) & htons(IP_DF));
 
+               /* Save the IP ID check to be included later when we get to
+                * the transport layer so only the inner most IP ID is checked.
+                * This is because some GSO/TSO implementations do not
+                * correctly increment the IP ID for the outer hdrs.
+                */
+               NAPI_GRO_CB(p)->flush_id =
+                           ((u16)(ntohs(iph2->id) + NAPI_GRO_CB(p)->count) ^ id);
                NAPI_GRO_CB(p)->flush |= flush;
        }
 
        NAPI_GRO_CB(skb)->flush |= flush;
+       skb_set_network_header(skb, off);
+       /* The above will be needed by the transport layer if there is one
+        * immediately following this IP hdr.
+        */
+
        skb_gro_pull(skb, sizeof(*iph));
        skb_set_transport_header(skb, skb_gro_offset(skb));
 
@@ -1411,10 +1426,10 @@ out:
        return pp;
 }
 
-static int inet_gro_complete(struct sk_buff *skb)
+static int inet_gro_complete(struct sk_buff *skb, int nhoff)
 {
-       __be16 newlen = htons(skb->len - skb_network_offset(skb));
-       struct iphdr *iph = ip_hdr(skb);
+       __be16 newlen = htons(skb->len - nhoff);
+       struct iphdr *iph = (struct iphdr *)(skb->data + nhoff);
        const struct net_offload *ops;
        int proto = iph->protocol;
        int err = -ENOSYS;
@@ -1427,7 +1442,11 @@ static int inet_gro_complete(struct sk_buff *skb)
        if (WARN_ON(!ops || !ops->callbacks.gro_complete))
                goto out_unlock;
 
-       err = ops->callbacks.gro_complete(skb);
+       /* Only need to add sizeof(*iph) to get to the next hdr below
+        * because any hdr with option will have been flushed in
+        * inet_gro_receive().
+        */
+       err = ops->callbacks.gro_complete(skb, nhoff + sizeof(*iph));
 
 out_unlock:
        rcu_read_unlock();
@@ -1529,6 +1548,7 @@ static const struct net_protocol tcp_protocol = {
        .err_handler    =       tcp_v4_err,
        .no_policy      =       1,
        .netns_ok       =       1,
+       .icmp_strict_tag_validation = 1,
 };
 
 static const struct net_protocol udp_protocol = {