ipv6: support IPV6_PMTU_INTERFACE on sockets
authorHannes Frederic Sowa <hannes@stressinduktion.org>
Sun, 15 Dec 2013 02:41:14 +0000 (03:41 +0100)
committerDavid S. Miller <davem@davemloft.net>
Wed, 18 Dec 2013 22:37:05 +0000 (17:37 -0500)
IPV6_PMTU_INTERFACE is the same as IPV6_PMTU_PROBE for ipv6. Add it
nontheless for symmetry with IPv4 sockets. Also drop incoming MTU
information if this mode is enabled.

The additional bit in ipv6_pinfo just eats in the padding behind the
bitfield. There are no changes to the layout of the struct at all.

Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/linux/ipv6.h
include/net/ip6_route.h
include/uapi/linux/in6.h
net/dccp/ipv6.c
net/ipv6/ip6_output.c
net/ipv6/ipv6_sockglue.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp.c
net/sctp/input.c

index 3fde066455535ca98044c8548660e5e6a2279a9d..7e1ded0d8e45120ba1ef3657868d02e9b570b8f6 100644 (file)
@@ -191,7 +191,7 @@ struct ipv6_pinfo {
        /* sockopt flags */
        __u16                   recverr:1,
                                sndflow:1,
-                               pmtudisc:2,
+                               pmtudisc:3,
                                ipv6only:1,
                                srcprefs:3,     /* 001: prefer temporary address
                                                 * 010: prefer public address
index 733747ce163c1a08a91a24eb5277832f5c04d6ee..c2626ce1f2ad73a336eccf11dcb8760287fe5085 100644 (file)
@@ -178,10 +178,15 @@ static inline int ip6_skb_dst_mtu(struct sk_buff *skb)
 {
        struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL;
 
-       return (np && np->pmtudisc == IPV6_PMTUDISC_PROBE) ?
+       return (np && np->pmtudisc >= IPV6_PMTUDISC_PROBE) ?
               skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb));
 }
 
+static inline bool ip6_sk_accept_pmtu(const struct sock *sk)
+{
+       return inet6_sk(sk)->pmtudisc != IPV6_PMTUDISC_INTERFACE;
+}
+
 static inline struct in6_addr *rt6_nexthop(struct rt6_info *rt)
 {
        return &rt->rt6i_gateway;
index 440d5c479145ca5924e45f3b6013eecdadfd38b4..f94f1d013bf27d0a2d77dce9b61f6a00233d0c8e 100644 (file)
@@ -188,6 +188,10 @@ enum {
 #define IPV6_PMTUDISC_WANT             1
 #define IPV6_PMTUDISC_DO               2
 #define IPV6_PMTUDISC_PROBE            3
+/* same as IPV6_PMTUDISC_PROBE, provided for symetry with IPv4
+ * also see comments on IP_PMTUDISC_INTERFACE
+ */
+#define IPV6_PMTUDISC_INTERFACE                4
 
 /* Flowlabel */
 #define IPV6_FLOWLABEL_MGR     32
index 2b90a786e475f78ab7084765bfeedc608632255a..629019e6f8e93ff3d811849e661f43bada8bb4b3 100644 (file)
@@ -141,6 +141,9 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        if (type == ICMPV6_PKT_TOOBIG) {
                struct dst_entry *dst = NULL;
 
+               if (!ip6_sk_accept_pmtu(sk))
+                       goto out;
+
                if (sock_owned_by_user(sk))
                        goto out;
                if ((1 << sk->sk_state) & (DCCPF_LISTEN | DCCPF_CLOSED))
index 9a311cc79672440cfaff2812f5e300817e789fa9..bc4e1bcdf4c0c028da17e4207ead7cf0f6a03691 100644 (file)
@@ -1165,10 +1165,10 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
                np->cork.hop_limit = hlimit;
                np->cork.tclass = tclass;
                if (rt->dst.flags & DST_XFRM_TUNNEL)
-                       mtu = np->pmtudisc == IPV6_PMTUDISC_PROBE ?
+                       mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ?
                              rt->dst.dev->mtu : dst_mtu(&rt->dst);
                else
-                       mtu = np->pmtudisc == IPV6_PMTUDISC_PROBE ?
+                       mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ?
                              rt->dst.dev->mtu : dst_mtu(rt->dst.path);
                if (np->frag_size < mtu) {
                        if (np->frag_size)
@@ -1270,7 +1270,7 @@ alloc_new_skb:
                        if (skb == NULL || skb_prev == NULL)
                                ip6_append_data_mtu(&mtu, &maxfraglen,
                                                    fragheaderlen, skb, rt,
-                                                   np->pmtudisc ==
+                                                   np->pmtudisc >=
                                                    IPV6_PMTUDISC_PROBE);
 
                        skb_prev = skb;
index 759fbf96515b70f3018fddf9e19773af3301bbe4..af0ecb94b3b44cefe2d1575ebec2e46b3d2d1979 100644 (file)
@@ -722,7 +722,7 @@ done:
        case IPV6_MTU_DISCOVER:
                if (optlen < sizeof(int))
                        goto e_inval;
-               if (val < IP_PMTUDISC_DONT || val > IP_PMTUDISC_PROBE)
+               if (val < IPV6_PMTUDISC_DONT || val > IPV6_PMTUDISC_INTERFACE)
                        goto e_inval;
                np->pmtudisc = val;
                retv = 0;
index da046a5d7ffb56153b76d37dbd063db9281907ff..d955487f2c542a39addec78760edf681628d0455 100644 (file)
@@ -397,6 +397,9 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
                if (sk->sk_state == TCP_LISTEN)
                        goto out;
 
+               if (!ip6_sk_accept_pmtu(sk))
+                       goto out;
+
                tp->mtu_info = ntohl(info);
                if (!sock_owned_by_user(sk))
                        tcp_v6_mtu_reduced(sk);
index 089c741a399217b2c7dd90f7783df4aa89eb5424..65ed5cd79264a12e0409c1c4c5c4c43c2be8df98 100644 (file)
@@ -538,8 +538,11 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        if (sk == NULL)
                return;
 
-       if (type == ICMPV6_PKT_TOOBIG)
+       if (type == ICMPV6_PKT_TOOBIG) {
+               if (!ip6_sk_accept_pmtu(sk))
+                       goto out;
                ip6_sk_update_pmtu(skb, sk, info);
+       }
        if (type == NDISC_REDIRECT) {
                ip6_sk_redirect(skb, sk);
                goto out;
index 2a192a7c5d81b3380d5ae497cb3789eb9c8134be..042ec6c9ae24a6106aba1d7c345e3d653359dbfe 100644 (file)
@@ -389,6 +389,9 @@ void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc,
        if (!t || (t->pathmtu <= pmtu))
                return;
 
+       if (!ip6_sk_accept_pmtu(sk))
+               return;
+
        if (sock_owned_by_user(sk)) {
                asoc->pmtu_pending = 1;
                t->pmtu_pending = 1;