skb->sk socket can be of AF_INET or AF_INET6 address family. Thus we
always have to make sure we a referring to the correct interpretation
of skb->sk.
We only depend on header defines to query the mtu, so we don't introduce
a new dependency to ipv6 by this change.
Cc: Steffen Klassert <steffen.klassert@secunet.com>
Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
+static inline int ip_skb_dst_mtu(struct sk_buff *skb)
+{
+ struct inet_sock *inet = skb->sk ? inet_sk(skb->sk) : NULL;
+
+ return (inet && inet->pmtudisc == IP_PMTUDISC_PROBE) ?
+ skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb));
+}
+
#include <net/route.h>
#include <net/ipv6.h>
#include <net/ip6_fib.h>
#include <net/route.h>
#include <net/ipv6.h>
#include <net/ip6_fib.h>
+#include <net/ip6_route.h>
#include <net/flow.h>
#include <linux/interrupt.h>
#include <net/flow.h>
#include <linux/interrupt.h>
+static inline int xfrm_skb_dst_mtu(struct sk_buff *skb)
+{
+ struct sock *sk = skb->sk;
+
+ if (sk && sk->sk_family == AF_INET6)
+ return ip6_skb_dst_mtu(skb);
+ else if (sk && sk->sk_family == AF_INET)
+ return ip_skb_dst_mtu(skb);
+ return dst_mtu(skb_dst(skb));
+}
+
-static inline int ip_skb_dst_mtu(struct sk_buff *skb)
-{
- struct inet_sock *inet = skb->sk ? inet_sk(skb->sk) : NULL;
-
- return (inet && inet->pmtudisc == IP_PMTUDISC_PROBE) ?
- skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb));
-}
-
static int ip_finish_output(struct sk_buff *skb)
{
#if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM)
static int ip_finish_output(struct sk_buff *skb)
{
#if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM)
static int xfrm4_tunnel_check_size(struct sk_buff *skb)
{
int mtu, ret = 0;
static int xfrm4_tunnel_check_size(struct sk_buff *skb)
{
int mtu, ret = 0;
if (IPCB(skb)->flags & IPSKB_XFRM_TUNNEL_SIZE)
goto out;
if (IPCB(skb)->flags & IPSKB_XFRM_TUNNEL_SIZE)
goto out;
if (!(ip_hdr(skb)->frag_off & htons(IP_DF)) || skb->local_df)
goto out;
if (!(ip_hdr(skb)->frag_off & htons(IP_DF)) || skb->local_df)
goto out;
- dst = skb_dst(skb);
- mtu = dst_mtu(dst);
+ mtu = xfrm_skb_dst_mtu(skb);
if (skb->len > mtu) {
if (skb->sk)
xfrm_local_error(skb, mtu);
if (skb->len > mtu) {
if (skb->sk)
xfrm_local_error(skb, mtu);
{
struct dst_entry *dst = skb_dst(skb);
struct xfrm_state *x = dst->xfrm;
{
struct dst_entry *dst = skb_dst(skb);
struct xfrm_state *x = dst->xfrm;
- int mtu = ip6_skb_dst_mtu(skb);
+ int mtu = xfrm_skb_dst_mtu(skb);
+
+ if (mtu < IPV6_MIN_MTU)
+ mtu = IPV6_MIN_MTU;
if (skb->len > mtu && xfrm6_local_dontfrag(skb)) {
xfrm6_local_rxpmtu(skb, mtu);
if (skb->len > mtu && xfrm6_local_dontfrag(skb)) {
xfrm6_local_rxpmtu(skb, mtu);