Commit 93b36cf3 authored by Hannes Frederic Sowa's avatar Hannes Frederic Sowa Committed by David S. Miller

ipv6: support IPV6_PMTU_INTERFACE on sockets

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: default avatarHannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent cd174e67
...@@ -191,7 +191,7 @@ struct ipv6_pinfo { ...@@ -191,7 +191,7 @@ struct ipv6_pinfo {
/* sockopt flags */ /* sockopt flags */
__u16 recverr:1, __u16 recverr:1,
sndflow:1, sndflow:1,
pmtudisc:2, pmtudisc:3,
ipv6only:1, ipv6only:1,
srcprefs:3, /* 001: prefer temporary address srcprefs:3, /* 001: prefer temporary address
* 010: prefer public address * 010: prefer public address
......
...@@ -178,10 +178,15 @@ static inline int ip6_skb_dst_mtu(struct sk_buff *skb) ...@@ -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; 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)); 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) static inline struct in6_addr *rt6_nexthop(struct rt6_info *rt)
{ {
return &rt->rt6i_gateway; return &rt->rt6i_gateway;
......
...@@ -188,6 +188,10 @@ enum { ...@@ -188,6 +188,10 @@ enum {
#define IPV6_PMTUDISC_WANT 1 #define IPV6_PMTUDISC_WANT 1
#define IPV6_PMTUDISC_DO 2 #define IPV6_PMTUDISC_DO 2
#define IPV6_PMTUDISC_PROBE 3 #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 */ /* Flowlabel */
#define IPV6_FLOWLABEL_MGR 32 #define IPV6_FLOWLABEL_MGR 32
......
...@@ -141,6 +141,9 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -141,6 +141,9 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
if (type == ICMPV6_PKT_TOOBIG) { if (type == ICMPV6_PKT_TOOBIG) {
struct dst_entry *dst = NULL; struct dst_entry *dst = NULL;
if (!ip6_sk_accept_pmtu(sk))
goto out;
if (sock_owned_by_user(sk)) if (sock_owned_by_user(sk))
goto out; goto out;
if ((1 << sk->sk_state) & (DCCPF_LISTEN | DCCPF_CLOSED)) if ((1 << sk->sk_state) & (DCCPF_LISTEN | DCCPF_CLOSED))
......
...@@ -1165,10 +1165,10 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, ...@@ -1165,10 +1165,10 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
np->cork.hop_limit = hlimit; np->cork.hop_limit = hlimit;
np->cork.tclass = tclass; np->cork.tclass = tclass;
if (rt->dst.flags & DST_XFRM_TUNNEL) 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); rt->dst.dev->mtu : dst_mtu(&rt->dst);
else else
mtu = np->pmtudisc == IPV6_PMTUDISC_PROBE ? mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ?
rt->dst.dev->mtu : dst_mtu(rt->dst.path); rt->dst.dev->mtu : dst_mtu(rt->dst.path);
if (np->frag_size < mtu) { if (np->frag_size < mtu) {
if (np->frag_size) if (np->frag_size)
...@@ -1270,7 +1270,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, ...@@ -1270,7 +1270,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
if (skb == NULL || skb_prev == NULL) if (skb == NULL || skb_prev == NULL)
ip6_append_data_mtu(&mtu, &maxfraglen, ip6_append_data_mtu(&mtu, &maxfraglen,
fragheaderlen, skb, rt, fragheaderlen, skb, rt,
np->pmtudisc == np->pmtudisc >=
IPV6_PMTUDISC_PROBE); IPV6_PMTUDISC_PROBE);
skb_prev = skb; skb_prev = skb;
......
...@@ -722,7 +722,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, ...@@ -722,7 +722,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
case IPV6_MTU_DISCOVER: case IPV6_MTU_DISCOVER:
if (optlen < sizeof(int)) if (optlen < sizeof(int))
goto e_inval; goto e_inval;
if (val < IP_PMTUDISC_DONT || val > IP_PMTUDISC_PROBE) if (val < IPV6_PMTUDISC_DONT || val > IPV6_PMTUDISC_INTERFACE)
goto e_inval; goto e_inval;
np->pmtudisc = val; np->pmtudisc = val;
retv = 0; retv = 0;
......
...@@ -397,6 +397,9 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -397,6 +397,9 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
if (sk->sk_state == TCP_LISTEN) if (sk->sk_state == TCP_LISTEN)
goto out; goto out;
if (!ip6_sk_accept_pmtu(sk))
goto out;
tp->mtu_info = ntohl(info); tp->mtu_info = ntohl(info);
if (!sock_owned_by_user(sk)) if (!sock_owned_by_user(sk))
tcp_v6_mtu_reduced(sk); tcp_v6_mtu_reduced(sk);
......
...@@ -538,8 +538,11 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -538,8 +538,11 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
if (sk == NULL) if (sk == NULL)
return; 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); ip6_sk_update_pmtu(skb, sk, info);
}
if (type == NDISC_REDIRECT) { if (type == NDISC_REDIRECT) {
ip6_sk_redirect(skb, sk); ip6_sk_redirect(skb, sk);
goto out; goto out;
......
...@@ -389,6 +389,9 @@ void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc, ...@@ -389,6 +389,9 @@ void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc,
if (!t || (t->pathmtu <= pmtu)) if (!t || (t->pathmtu <= pmtu))
return; return;
if (!ip6_sk_accept_pmtu(sk))
return;
if (sock_owned_by_user(sk)) { if (sock_owned_by_user(sk)) {
asoc->pmtu_pending = 1; asoc->pmtu_pending = 1;
t->pmtu_pending = 1; t->pmtu_pending = 1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment