Blame view

net/ipv4/xfrm4_mode_beet.c 3.77 KB
0a69452cb   Diego Beltrami   [XFRM]: BEET mode
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  /*
   * xfrm4_mode_beet.c - BEET mode encapsulation for IPv4.
   *
   * Copyright (c) 2006 Diego Beltrami <diego.beltrami@gmail.com>
   *                    Miika Komu     <miika@iki.fi>
   *                    Herbert Xu     <herbert@gondor.apana.org.au>
   *                    Abhinav Pathak <abhinav.pathak@hiit.fi>
   *                    Jeff Ahrenholz <ahrenholz@gmail.com>
   */
  
  #include <linux/init.h>
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/skbuff.h>
  #include <linux/stringify.h>
  #include <net/dst.h>
  #include <net/ip.h>
  #include <net/xfrm.h>
227620e29   Herbert Xu   [IPSEC]: Separate...
19
20
21
22
23
24
25
26
27
28
29
30
31
32
  static void xfrm4_beet_make_header(struct sk_buff *skb)
  {
  	struct iphdr *iph = ip_hdr(skb);
  
  	iph->ihl = 5;
  	iph->version = 4;
  
  	iph->protocol = XFRM_MODE_SKB_CB(skb)->protocol;
  	iph->tos = XFRM_MODE_SKB_CB(skb)->tos;
  
  	iph->id = XFRM_MODE_SKB_CB(skb)->id;
  	iph->frag_off = XFRM_MODE_SKB_CB(skb)->frag_off;
  	iph->ttl = XFRM_MODE_SKB_CB(skb)->ttl;
  }
0a69452cb   Diego Beltrami   [XFRM]: BEET mode
33
34
35
  /* Add encapsulation header.
   *
   * The top IP header will be constructed per draft-nikander-esp-beet-mode-06.txt.
0a69452cb   Diego Beltrami   [XFRM]: BEET mode
36
37
38
   */
  static int xfrm4_beet_output(struct xfrm_state *x, struct sk_buff *skb)
  {
37fedd3aa   Herbert Xu   [IPSEC]: Use IPv6...
39
  	struct ip_beet_phdr *ph;
732c8bd59   Herbert Xu   [IPSEC]: Fix BEET...
40
  	struct iphdr *top_iph;
0a69452cb   Diego Beltrami   [XFRM]: BEET mode
41
  	int hdrlen, optlen;
0a69452cb   Diego Beltrami   [XFRM]: BEET mode
42
  	hdrlen = 0;
732c8bd59   Herbert Xu   [IPSEC]: Fix BEET...
43
  	optlen = XFRM_MODE_SKB_CB(skb)->optlen;
0a69452cb   Diego Beltrami   [XFRM]: BEET mode
44
45
  	if (unlikely(optlen))
  		hdrlen += IPV4_BEET_PHMAXLEN - (optlen & 4);
eb49e6309   Joakim Koskela   ipsec: Interfamil...
46
47
48
49
  	skb_set_network_header(skb, -x->props.header_len -
  			            hdrlen + (XFRM_MODE_SKB_CB(skb)->ihl - sizeof(*top_iph)));
  	if (x->sel.family != AF_INET6)
  		skb->network_header += IPV4_BEET_PHMAXLEN;
37fedd3aa   Herbert Xu   [IPSEC]: Use IPv6...
50
51
  	skb->mac_header = skb->network_header +
  			  offsetof(struct iphdr, protocol);
732c8bd59   Herbert Xu   [IPSEC]: Fix BEET...
52
  	skb->transport_header = skb->network_header + sizeof(*top_iph);
37fedd3aa   Herbert Xu   [IPSEC]: Use IPv6...
53

227620e29   Herbert Xu   [IPSEC]: Separate...
54
  	xfrm4_beet_make_header(skb);
732c8bd59   Herbert Xu   [IPSEC]: Fix BEET...
55
56
  	ph = (struct ip_beet_phdr *)
  		__skb_pull(skb, XFRM_MODE_SKB_CB(skb)->ihl - hdrlen);
0a69452cb   Diego Beltrami   [XFRM]: BEET mode
57

37fedd3aa   Herbert Xu   [IPSEC]: Use IPv6...
58
  	top_iph = ip_hdr(skb);
36cf9acf9   Herbert Xu   [IPSEC]: Separate...
59

0a69452cb   Diego Beltrami   [XFRM]: BEET mode
60
  	if (unlikely(optlen)) {
0a69452cb   Diego Beltrami   [XFRM]: BEET mode
61
  		BUG_ON(optlen < 0);
0a69452cb   Diego Beltrami   [XFRM]: BEET mode
62
  		ph->padlen = 4 - (optlen & 4);
05d224468   Patrick McHardy   [XFRM]: beet: fix...
63
  		ph->hdrlen = optlen / 8;
0a69452cb   Diego Beltrami   [XFRM]: BEET mode
64
  		ph->nexthdr = top_iph->protocol;
04fef9893   Patrick McHardy   [XFRM]: beet: use...
65
66
  		if (ph->padlen)
  			memset(ph + 1, IPOPT_NOP, ph->padlen);
0a69452cb   Diego Beltrami   [XFRM]: BEET mode
67
68
69
70
71
72
73
74
75
76
77
78
79
  
  		top_iph->protocol = IPPROTO_BEETPH;
  		top_iph->ihl = sizeof(struct iphdr) / 4;
  	}
  
  	top_iph->saddr = x->props.saddr.a4;
  	top_iph->daddr = x->id.daddr.a4;
  
  	return 0;
  }
  
  static int xfrm4_beet_input(struct xfrm_state *x, struct sk_buff *skb)
  {
227620e29   Herbert Xu   [IPSEC]: Separate...
80
  	struct iphdr *iph;
0a69452cb   Diego Beltrami   [XFRM]: BEET mode
81
  	int optlen = 0;
0a69452cb   Diego Beltrami   [XFRM]: BEET mode
82
  	int err = -EINVAL;
227620e29   Herbert Xu   [IPSEC]: Separate...
83
  	if (unlikely(XFRM_MODE_SKB_CB(skb)->protocol == IPPROTO_BEETPH)) {
254d0d24e   Patrick McHardy   [XFRM]: beet: fix...
84
  		struct ip_beet_phdr *ph;
227620e29   Herbert Xu   [IPSEC]: Separate...
85
  		int phlen;
0a69452cb   Diego Beltrami   [XFRM]: BEET mode
86
87
88
  
  		if (!pskb_may_pull(skb, sizeof(*ph)))
  			goto out;
227620e29   Herbert Xu   [IPSEC]: Separate...
89
90
  
  		ph = (struct ip_beet_phdr *)skb->data;
0a69452cb   Diego Beltrami   [XFRM]: BEET mode
91

d4b1e8406   Patrick McHardy   [XFRM]: beet: fix...
92
  		phlen = sizeof(*ph) + ph->padlen;
05d224468   Patrick McHardy   [XFRM]: beet: fix...
93
  		optlen = ph->hdrlen * 8 + (IPV4_BEET_PHMAXLEN - phlen);
0a69452cb   Diego Beltrami   [XFRM]: BEET mode
94
95
  		if (optlen < 0 || optlen & 3 || optlen > 250)
  			goto out;
227620e29   Herbert Xu   [IPSEC]: Separate...
96
  		XFRM_MODE_SKB_CB(skb)->protocol = ph->nexthdr;
0a69452cb   Diego Beltrami   [XFRM]: BEET mode
97

322c8a3c3   Adrian Bunk   [IPSEC] xfrm4_bee...
98
  		if (!pskb_may_pull(skb, phlen))
227620e29   Herbert Xu   [IPSEC]: Separate...
99
100
  			goto out;
  		__skb_pull(skb, phlen);
0a69452cb   Diego Beltrami   [XFRM]: BEET mode
101
  	}
227620e29   Herbert Xu   [IPSEC]: Separate...
102
103
104
105
106
107
108
109
  	skb_push(skb, sizeof(*iph));
  	skb_reset_network_header(skb);
  
  	memmove(skb->data - skb->mac_len, skb_mac_header(skb),
  		skb->mac_len);
  	skb_set_mac_header(skb, -skb->mac_len);
  
  	xfrm4_beet_make_header(skb);
0a69452cb   Diego Beltrami   [XFRM]: BEET mode
110

eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
111
  	iph = ip_hdr(skb);
227620e29   Herbert Xu   [IPSEC]: Separate...
112
113
114
  
  	iph->ihl += optlen / 4;
  	iph->tot_len = htons(skb->len);
0a69452cb   Diego Beltrami   [XFRM]: BEET mode
115
116
  	iph->daddr = x->sel.daddr.a4;
  	iph->saddr = x->sel.saddr.a4;
0a69452cb   Diego Beltrami   [XFRM]: BEET mode
117
  	iph->check = 0;
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
118
  	iph->check = ip_fast_csum(skb_network_header(skb), iph->ihl);
0a69452cb   Diego Beltrami   [XFRM]: BEET mode
119
120
121
122
123
124
  	err = 0;
  out:
  	return err;
  }
  
  static struct xfrm_mode xfrm4_beet_mode = {
227620e29   Herbert Xu   [IPSEC]: Separate...
125
126
  	.input2 = xfrm4_beet_input,
  	.input = xfrm_prepare_input,
36cf9acf9   Herbert Xu   [IPSEC]: Separate...
127
128
  	.output2 = xfrm4_beet_output,
  	.output = xfrm4_prepare_output,
0a69452cb   Diego Beltrami   [XFRM]: BEET mode
129
130
  	.owner = THIS_MODULE,
  	.encap = XFRM_MODE_BEET,
1bfcb10f6   Herbert Xu   [IPSEC]: Add miss...
131
  	.flags = XFRM_MODE_FLAG_TUNNEL,
0a69452cb   Diego Beltrami   [XFRM]: BEET mode
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
  };
  
  static int __init xfrm4_beet_init(void)
  {
  	return xfrm_register_mode(&xfrm4_beet_mode, AF_INET);
  }
  
  static void __exit xfrm4_beet_exit(void)
  {
  	int err;
  
  	err = xfrm_unregister_mode(&xfrm4_beet_mode, AF_INET);
  	BUG_ON(err);
  }
  
  module_init(xfrm4_beet_init);
  module_exit(xfrm4_beet_exit);
  MODULE_LICENSE("GPL");
  MODULE_ALIAS_XFRM_MODE(AF_INET, XFRM_MODE_BEET);