Blame view

net/ipv6/xfrm6_mode_tunnel.c 3.07 KB
b59f45d0b   Herbert Xu   [IPSEC] xfrm: Abs...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  /*
   * xfrm6_mode_tunnel.c - Tunnel mode encapsulation for IPv6.
   *
   * Copyright (C) 2002 USAGI/WIDE Project
   * Copyright (c) 2004-2006 Herbert Xu <herbert@gondor.apana.org.au>
   */
  
  #include <linux/init.h>
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/skbuff.h>
  #include <linux/stringify.h>
  #include <net/dsfield.h>
  #include <net/dst.h>
  #include <net/inet_ecn.h>
  #include <net/ipv6.h>
  #include <net/xfrm.h>
  
  static inline void ipip6_ecn_decapsulate(struct sk_buff *skb)
  {
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
21
  	struct ipv6hdr *outer_iph = ipv6_hdr(skb);
39b89160d   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
22
  	struct ipv6hdr *inner_iph = ipipv6_hdr(skb);
b59f45d0b   Herbert Xu   [IPSEC] xfrm: Abs...
23
24
25
26
27
28
29
  
  	if (INET_ECN_is_ce(ipv6_get_dsfield(outer_iph)))
  		IP6_ECN_set_ce(inner_iph);
  }
  
  /* Add encapsulation header.
   *
ceb1eec82   Herbert Xu   [IPSEC]: Move IP ...
30
   * The top IP header will be constructed per RFC 2401.
b59f45d0b   Herbert Xu   [IPSEC] xfrm: Abs...
31
   */
195ad6a3a   Herbert Xu   [IPSEC]: Rename t...
32
  static int xfrm6_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
b59f45d0b   Herbert Xu   [IPSEC] xfrm: Abs...
33
34
  {
  	struct dst_entry *dst = skb->dst;
36cf9acf9   Herbert Xu   [IPSEC]: Separate...
35
  	struct ipv6hdr *top_iph;
b59f45d0b   Herbert Xu   [IPSEC] xfrm: Abs...
36
  	int dsfield;
7b277b1a5   Herbert Xu   [IPSEC]: Set skb-...
37
  	skb_set_network_header(skb, -x->props.header_len);
37fedd3aa   Herbert Xu   [IPSEC]: Use IPv6...
38
39
  	skb->mac_header = skb->network_header +
  			  offsetof(struct ipv6hdr, nexthdr);
36cf9acf9   Herbert Xu   [IPSEC]: Separate...
40
  	skb->transport_header = skb->network_header + sizeof(*top_iph);
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
41
  	top_iph = ipv6_hdr(skb);
b59f45d0b   Herbert Xu   [IPSEC] xfrm: Abs...
42
43
  
  	top_iph->version = 6;
36cf9acf9   Herbert Xu   [IPSEC]: Separate...
44
45
46
  
  	memcpy(top_iph->flow_lbl, XFRM_MODE_SKB_CB(skb)->flow_lbl,
  	       sizeof(top_iph->flow_lbl));
df9dcb458   Kazunori MIYAZAWA   [IPSEC]: Fix inte...
47
  	top_iph->nexthdr = xfrm_af2proto(skb->dst->ops->family);
36cf9acf9   Herbert Xu   [IPSEC]: Separate...
48
49
  
  	dsfield = XFRM_MODE_SKB_CB(skb)->tos;
b59f45d0b   Herbert Xu   [IPSEC] xfrm: Abs...
50
51
52
53
  	dsfield = INET_ECN_encapsulate(dsfield, dsfield);
  	if (x->props.flags & XFRM_STATE_NOECN)
  		dsfield &= ~INET_ECN_MASK;
  	ipv6_change_dsfield(top_iph, 0, dsfield);
b59f45d0b   Herbert Xu   [IPSEC] xfrm: Abs...
54
55
56
57
58
  	top_iph->hop_limit = dst_metric(dst->child, RTAX_HOPLIMIT);
  	ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr);
  	ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr);
  	return 0;
  }
195ad6a3a   Herbert Xu   [IPSEC]: Rename t...
59
  static int xfrm6_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
b59f45d0b   Herbert Xu   [IPSEC] xfrm: Abs...
60
61
  {
  	int err = -EINVAL;
39f69c6f9   Arnaldo Carvalho de Melo   [SK_BUFF] xfrm: U...
62
  	const unsigned char *old_mac;
b59f45d0b   Herbert Xu   [IPSEC] xfrm: Abs...
63

227620e29   Herbert Xu   [IPSEC]: Separate...
64
  	if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPV6)
b59f45d0b   Herbert Xu   [IPSEC] xfrm: Abs...
65
66
67
68
69
70
71
  		goto out;
  	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
  		goto out;
  
  	if (skb_cloned(skb) &&
  	    (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
  		goto out;
227620e29   Herbert Xu   [IPSEC]: Separate...
72
73
74
75
76
  	if (x->props.flags & XFRM_STATE_DECAP_DSCP)
  		ipv6_copy_dscp(ipv6_get_dsfield(ipv6_hdr(skb)),
  			       ipipv6_hdr(skb));
  	if (!(x->props.flags & XFRM_STATE_NOECN))
  		ipip6_ecn_decapsulate(skb);
98e399f82   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
77
  	old_mac = skb_mac_header(skb);
39f69c6f9   Arnaldo Carvalho de Melo   [SK_BUFF] xfrm: U...
78
  	skb_set_mac_header(skb, -skb->mac_len);
98e399f82   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
79
  	memmove(skb_mac_header(skb), old_mac, skb->mac_len);
c1d2bbe1c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
80
  	skb_reset_network_header(skb);
b59f45d0b   Herbert Xu   [IPSEC] xfrm: Abs...
81
82
83
84
85
86
87
  	err = 0;
  
  out:
  	return err;
  }
  
  static struct xfrm_mode xfrm6_tunnel_mode = {
195ad6a3a   Herbert Xu   [IPSEC]: Rename t...
88
  	.input2 = xfrm6_mode_tunnel_input,
227620e29   Herbert Xu   [IPSEC]: Separate...
89
  	.input = xfrm_prepare_input,
195ad6a3a   Herbert Xu   [IPSEC]: Rename t...
90
  	.output2 = xfrm6_mode_tunnel_output,
36cf9acf9   Herbert Xu   [IPSEC]: Separate...
91
  	.output = xfrm6_prepare_output,
b59f45d0b   Herbert Xu   [IPSEC] xfrm: Abs...
92
93
  	.owner = THIS_MODULE,
  	.encap = XFRM_MODE_TUNNEL,
1bfcb10f6   Herbert Xu   [IPSEC]: Add miss...
94
  	.flags = XFRM_MODE_FLAG_TUNNEL,
b59f45d0b   Herbert Xu   [IPSEC] xfrm: Abs...
95
  };
195ad6a3a   Herbert Xu   [IPSEC]: Rename t...
96
  static int __init xfrm6_mode_tunnel_init(void)
b59f45d0b   Herbert Xu   [IPSEC] xfrm: Abs...
97
98
99
  {
  	return xfrm_register_mode(&xfrm6_tunnel_mode, AF_INET6);
  }
195ad6a3a   Herbert Xu   [IPSEC]: Rename t...
100
  static void __exit xfrm6_mode_tunnel_exit(void)
b59f45d0b   Herbert Xu   [IPSEC] xfrm: Abs...
101
102
103
104
105
106
  {
  	int err;
  
  	err = xfrm_unregister_mode(&xfrm6_tunnel_mode, AF_INET6);
  	BUG_ON(err);
  }
195ad6a3a   Herbert Xu   [IPSEC]: Rename t...
107
108
  module_init(xfrm6_mode_tunnel_init);
  module_exit(xfrm6_mode_tunnel_exit);
b59f45d0b   Herbert Xu   [IPSEC] xfrm: Abs...
109
110
  MODULE_LICENSE("GPL");
  MODULE_ALIAS_XFRM_MODE(AF_INET6, XFRM_MODE_TUNNEL);