linux/net/ipv6/xfrm6_output.c
<<
>>
Prefs
   1/*
   2 * xfrm6_output.c - Common IPsec encapsulation code for IPv6.
   3 * Copyright (C) 2002 USAGI/WIDE Project
   4 * Copyright (c) 2004 Herbert Xu <herbert@gondor.apana.org.au>
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public License
   8 * as published by the Free Software Foundation; either version
   9 * 2 of the License, or (at your option) any later version.
  10 */
  11
  12#include <linux/if_ether.h>
  13#include <linux/kernel.h>
  14#include <linux/module.h>
  15#include <linux/skbuff.h>
  16#include <linux/icmpv6.h>
  17#include <linux/netfilter_ipv6.h>
  18#include <net/dst.h>
  19#include <net/ipv6.h>
  20#include <net/xfrm.h>
  21
  22int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb,
  23                          u8 **prevhdr)
  24{
  25        return ip6_find_1stfragopt(skb, prevhdr);
  26}
  27
  28EXPORT_SYMBOL(xfrm6_find_1stfragopt);
  29
  30static int xfrm6_tunnel_check_size(struct sk_buff *skb)
  31{
  32        int mtu, ret = 0;
  33        struct dst_entry *dst = skb_dst(skb);
  34
  35        mtu = dst_mtu(dst);
  36        if (mtu < IPV6_MIN_MTU)
  37                mtu = IPV6_MIN_MTU;
  38
  39        if (!skb->local_df && skb->len > mtu) {
  40                skb->dev = dst->dev;
  41                icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
  42                ret = -EMSGSIZE;
  43        }
  44
  45        return ret;
  46}
  47
  48int xfrm6_extract_output(struct xfrm_state *x, struct sk_buff *skb)
  49{
  50        int err;
  51
  52        err = xfrm6_tunnel_check_size(skb);
  53        if (err)
  54                return err;
  55
  56        XFRM_MODE_SKB_CB(skb)->protocol = ipv6_hdr(skb)->nexthdr;
  57
  58        return xfrm6_extract_header(skb);
  59}
  60
  61int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
  62{
  63        int err;
  64
  65        err = xfrm_inner_extract_output(x, skb);
  66        if (err)
  67                return err;
  68
  69        memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
  70#ifdef CONFIG_NETFILTER
  71        IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
  72#endif
  73
  74        skb->protocol = htons(ETH_P_IPV6);
  75        skb->local_df = 1;
  76
  77        return x->outer_mode->output2(x, skb);
  78}
  79EXPORT_SYMBOL(xfrm6_prepare_output);
  80
  81static int xfrm6_output_finish(struct sk_buff *skb)
  82{
  83#ifdef CONFIG_NETFILTER
  84        IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
  85#endif
  86
  87        skb->protocol = htons(ETH_P_IPV6);
  88        return xfrm_output(skb);
  89}
  90
  91int xfrm6_output(struct sk_buff *skb)
  92{
  93        return NF_HOOK(PF_INET6, NF_INET_POST_ROUTING, skb, NULL, skb_dst(skb)->dev,
  94                       xfrm6_output_finish);
  95}
  96