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 22 int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb, 23 u8 **prevhdr) 24 { 25 return ip6_find_1stfragopt(skb, prevhdr); 26 } 27 28 EXPORT_SYMBOL(xfrm6_find_1stfragopt); 29 30 static 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 48 int 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 61 int 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 } 79 EXPORT_SYMBOL(xfrm6_prepare_output); 80 81 static 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 91 int 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