aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/ip6_route.h9
-rw-r--r--include/uapi/linux/in6.h4
-rw-r--r--net/ipv6/ip6_output.c9
-rw-r--r--net/ipv6/ipv6_sockglue.c2
4 files changed, 18 insertions, 6 deletions
diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
index 017badb1aec7..00e3f12cb2f9 100644
--- a/include/net/ip6_route.h
+++ b/include/net/ip6_route.h
@@ -171,7 +171,14 @@ static inline int ip6_skb_dst_mtu(struct sk_buff *skb)
171 171
172static inline bool ip6_sk_accept_pmtu(const struct sock *sk) 172static inline bool ip6_sk_accept_pmtu(const struct sock *sk)
173{ 173{
174 return inet6_sk(sk)->pmtudisc != IPV6_PMTUDISC_INTERFACE; 174 return inet6_sk(sk)->pmtudisc != IPV6_PMTUDISC_INTERFACE &&
175 inet6_sk(sk)->pmtudisc != IPV6_PMTUDISC_OMIT;
176}
177
178static inline bool ip6_sk_local_df(const struct sock *sk)
179{
180 return inet6_sk(sk)->pmtudisc < IPV6_PMTUDISC_DO ||
181 inet6_sk(sk)->pmtudisc == IPV6_PMTUDISC_OMIT;
175} 182}
176 183
177static inline struct in6_addr *rt6_nexthop(struct rt6_info *rt) 184static inline struct in6_addr *rt6_nexthop(struct rt6_info *rt)
diff --git a/include/uapi/linux/in6.h b/include/uapi/linux/in6.h
index e9a1d2d973b6..0d8e0f0342dc 100644
--- a/include/uapi/linux/in6.h
+++ b/include/uapi/linux/in6.h
@@ -185,6 +185,10 @@ struct in6_flowlabel_req {
185 * also see comments on IP_PMTUDISC_INTERFACE 185 * also see comments on IP_PMTUDISC_INTERFACE
186 */ 186 */
187#define IPV6_PMTUDISC_INTERFACE 4 187#define IPV6_PMTUDISC_INTERFACE 4
188/* weaker version of IPV6_PMTUDISC_INTERFACE, which allows packets to
189 * get fragmented if they exceed the interface mtu
190 */
191#define IPV6_PMTUDISC_OMIT 5
188 192
189/* Flowlabel */ 193/* Flowlabel */
190#define IPV6_FLOWLABEL_MGR 32 194#define IPV6_FLOWLABEL_MGR 32
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 070a2fae2375..be1b7f5a3a54 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1234,8 +1234,10 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
1234 sizeof(struct frag_hdr) : 0) + 1234 sizeof(struct frag_hdr) : 0) +
1235 rt->rt6i_nfheader_len; 1235 rt->rt6i_nfheader_len;
1236 1236
1237 maxnonfragsize = (np->pmtudisc >= IPV6_PMTUDISC_DO) ? 1237 if (ip6_sk_local_df(sk))
1238 mtu : sizeof(struct ipv6hdr) + IPV6_MAXPLEN; 1238 maxnonfragsize = sizeof(struct ipv6hdr) + IPV6_MAXPLEN;
1239 else
1240 maxnonfragsize = mtu;
1239 1241
1240 /* dontfrag active */ 1242 /* dontfrag active */
1241 if ((cork->length + length > mtu - headersize) && dontfrag && 1243 if ((cork->length + length > mtu - headersize) && dontfrag &&
@@ -1543,8 +1545,7 @@ int ip6_push_pending_frames(struct sock *sk)
1543 } 1545 }
1544 1546
1545 /* Allow local fragmentation. */ 1547 /* Allow local fragmentation. */
1546 if (np->pmtudisc < IPV6_PMTUDISC_DO) 1548 skb->local_df = ip6_sk_local_df(sk);
1547 skb->local_df = 1;
1548 1549
1549 *final_dst = fl6->daddr; 1550 *final_dst = fl6->daddr;
1550 __skb_pull(skb, skb_network_header_len(skb)); 1551 __skb_pull(skb, skb_network_header_len(skb));
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 0a00f449de5e..edb58aff4ae7 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -722,7 +722,7 @@ done:
722 case IPV6_MTU_DISCOVER: 722 case IPV6_MTU_DISCOVER:
723 if (optlen < sizeof(int)) 723 if (optlen < sizeof(int))
724 goto e_inval; 724 goto e_inval;
725 if (val < IPV6_PMTUDISC_DONT || val > IPV6_PMTUDISC_INTERFACE) 725 if (val < IPV6_PMTUDISC_DONT || val > IPV6_PMTUDISC_OMIT)
726 goto e_inval; 726 goto e_inval;
727 np->pmtudisc = val; 727 np->pmtudisc = val;
728 retv = 0; 728 retv = 0;