]>
Commit | Line | Data |
---|---|---|
b59f45d0 HX |
1 | /* |
2 | * xfrm6_mode_tunnel.c - Tunnel mode encapsulation for IPv6. | |
3 | * | |
4 | * Copyright (C) 2002 USAGI/WIDE Project | |
5 | * Copyright (c) 2004-2006 Herbert Xu <herbert@gondor.apana.org.au> | |
6 | */ | |
7 | ||
5a0e3ad6 | 8 | #include <linux/gfp.h> |
b59f45d0 HX |
9 | #include <linux/init.h> |
10 | #include <linux/kernel.h> | |
11 | #include <linux/module.h> | |
12 | #include <linux/skbuff.h> | |
13 | #include <linux/stringify.h> | |
14 | #include <net/dsfield.h> | |
15 | #include <net/dst.h> | |
16 | #include <net/inet_ecn.h> | |
abbf46ae | 17 | #include <net/ip6_route.h> |
b59f45d0 HX |
18 | #include <net/ipv6.h> |
19 | #include <net/xfrm.h> | |
20 | ||
b59f45d0 HX |
21 | /* Add encapsulation header. |
22 | * | |
ceb1eec8 | 23 | * The top IP header will be constructed per RFC 2401. |
b59f45d0 | 24 | */ |
195ad6a3 | 25 | static int xfrm6_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) |
b59f45d0 | 26 | { |
adf30907 | 27 | struct dst_entry *dst = skb_dst(skb); |
36cf9acf | 28 | struct ipv6hdr *top_iph; |
b59f45d0 HX |
29 | int dsfield; |
30 | ||
f1bd7d65 IT |
31 | skb_set_inner_network_header(skb, skb_network_offset(skb)); |
32 | skb_set_inner_transport_header(skb, skb_transport_offset(skb)); | |
33 | ||
7b277b1a | 34 | skb_set_network_header(skb, -x->props.header_len); |
37fedd3a HX |
35 | skb->mac_header = skb->network_header + |
36 | offsetof(struct ipv6hdr, nexthdr); | |
36cf9acf | 37 | skb->transport_header = skb->network_header + sizeof(*top_iph); |
0660e03f | 38 | top_iph = ipv6_hdr(skb); |
b59f45d0 HX |
39 | |
40 | top_iph->version = 6; | |
36cf9acf HX |
41 | |
42 | memcpy(top_iph->flow_lbl, XFRM_MODE_SKB_CB(skb)->flow_lbl, | |
43 | sizeof(top_iph->flow_lbl)); | |
adf30907 | 44 | top_iph->nexthdr = xfrm_af2proto(skb_dst(skb)->ops->family); |
36cf9acf | 45 | |
a947b0a9 ND |
46 | if (x->props.extra_flags & XFRM_SA_XFLAG_DONT_ENCAP_DSCP) |
47 | dsfield = 0; | |
48 | else | |
49 | dsfield = XFRM_MODE_SKB_CB(skb)->tos; | |
50 | dsfield = INET_ECN_encapsulate(dsfield, XFRM_MODE_SKB_CB(skb)->tos); | |
b59f45d0 HX |
51 | if (x->props.flags & XFRM_STATE_NOECN) |
52 | dsfield &= ~INET_ECN_MASK; | |
53 | ipv6_change_dsfield(top_iph, 0, dsfield); | |
b92cf4aa | 54 | top_iph->hop_limit = ip6_dst_hoplimit(xfrm_dst_child(dst)); |
4e3fd7a0 AD |
55 | top_iph->saddr = *(struct in6_addr *)&x->props.saddr; |
56 | top_iph->daddr = *(struct in6_addr *)&x->id.daddr; | |
b59f45d0 HX |
57 | return 0; |
58 | } | |
59 | ||
b59f45d0 | 60 | static struct xfrm_mode xfrm6_tunnel_mode = { |
195ad6a3 | 61 | .output2 = xfrm6_mode_tunnel_output, |
b59f45d0 HX |
62 | .owner = THIS_MODULE, |
63 | .encap = XFRM_MODE_TUNNEL, | |
1bfcb10f | 64 | .flags = XFRM_MODE_FLAG_TUNNEL, |
b262a695 | 65 | .family = AF_INET6, |
b59f45d0 HX |
66 | }; |
67 | ||
195ad6a3 | 68 | static int __init xfrm6_mode_tunnel_init(void) |
b59f45d0 | 69 | { |
b262a695 | 70 | return xfrm_register_mode(&xfrm6_tunnel_mode); |
b59f45d0 HX |
71 | } |
72 | ||
195ad6a3 | 73 | static void __exit xfrm6_mode_tunnel_exit(void) |
b59f45d0 | 74 | { |
b262a695 | 75 | xfrm_unregister_mode(&xfrm6_tunnel_mode); |
b59f45d0 HX |
76 | } |
77 | ||
195ad6a3 HX |
78 | module_init(xfrm6_mode_tunnel_init); |
79 | module_exit(xfrm6_mode_tunnel_exit); | |
b59f45d0 HX |
80 | MODULE_LICENSE("GPL"); |
81 | MODULE_ALIAS_XFRM_MODE(AF_INET6, XFRM_MODE_TUNNEL); |