Skip to content

Commit

Permalink
ipv6: Fragment locally generated tunnel-mode IPSec6 packets as needed.
Browse files Browse the repository at this point in the history
This patch modifies IPsec6 to fragment IPv6 packets that are
locally generated as needed.

This version of the patch only fragments in tunnel mode, so that fragment
headers will not be obscured by ESP in transport mode.

Signed-off-by: David L Stevens <dlstevens@us.ibm.com>
Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David Stevens authored and David S. Miller committed Dec 20, 2010
1 parent 4b8fe66 commit ad0081e
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 11 deletions.
10 changes: 10 additions & 0 deletions include/net/ip6_route.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,5 +164,15 @@ static inline int ipv6_unicast_destination(struct sk_buff *skb)
return rt->rt6i_flags & RTF_LOCAL;
}

int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *));

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) ?
skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb));
}

#endif
#endif
12 changes: 2 additions & 10 deletions net/ipv6/ip6_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
#include <net/checksum.h>
#include <linux/mroute6.h>

static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *));
int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *));

int __ip6_local_out(struct sk_buff *skb)
{
Expand Down Expand Up @@ -145,14 +145,6 @@ static int ip6_finish_output2(struct sk_buff *skb)
return -EINVAL;
}

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) ?
skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb));
}

static int ip6_finish_output(struct sk_buff *skb)
{
if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) ||
Expand Down Expand Up @@ -601,7 +593,7 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
return offset;
}

static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
{
struct sk_buff *frag;
struct rt6_info *rt = (struct rt6_info*)skb_dst(skb);
Expand Down
16 changes: 15 additions & 1 deletion net/ipv6/xfrm6_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <linux/netfilter_ipv6.h>
#include <net/dst.h>
#include <net/ipv6.h>
#include <net/ip6_route.h>
#include <net/xfrm.h>

int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb,
Expand Down Expand Up @@ -88,8 +89,21 @@ static int xfrm6_output_finish(struct sk_buff *skb)
return xfrm_output(skb);
}

static int __xfrm6_output(struct sk_buff *skb)
{
struct dst_entry *dst = skb_dst(skb);
struct xfrm_state *x = dst->xfrm;

if ((x && x->props.mode == XFRM_MODE_TUNNEL) &&
((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) ||
dst_allfrag(skb_dst(skb)))) {
return ip6_fragment(skb, xfrm6_output_finish);
}
return xfrm6_output_finish(skb);
}

int xfrm6_output(struct sk_buff *skb)
{
return NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, NULL,
skb_dst(skb)->dev, xfrm6_output_finish);
skb_dst(skb)->dev, __xfrm6_output);
}

0 comments on commit ad0081e

Please sign in to comment.