Blame view

net/ipv4/xfrm4_policy.c 7.21 KB
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
   * xfrm4_policy.c
   *
   * Changes:
   *	Kazunori MIYAZAWA @USAGI
   * 	YOSHIFUJI Hideaki @USAGI
   *		Split up af-specific portion
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
8
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
   */
66cdb3ca2   Herbert Xu   [IPSEC]: Move flo...
10
11
  #include <linux/err.h>
  #include <linux/kernel.h>
aabc9761b   Herbert Xu   [IPSEC]: Store id...
12
  #include <linux/inetdevice.h>
cc9ff19da   Timo Teräs   xfrm: use gre key...
13
  #include <linux/if_tunnel.h>
45ff5a3f9   Herbert Xu   [IPSEC]: Set dst-...
14
  #include <net/dst.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
16
  #include <net/xfrm.h>
  #include <net/ip.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
  static struct xfrm_policy_afinfo xfrm4_policy_afinfo;
8f01cb082   David S. Miller   ipv4: xfrm: Elimi...
18
19
20
21
  static struct dst_entry *__xfrm4_dst_lookup(struct net *net, struct flowi4 *fl4,
  					    int tos,
  					    const xfrm_address_t *saddr,
  					    const xfrm_address_t *daddr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
  {
66cdb3ca2   Herbert Xu   [IPSEC]: Move flo...
23
  	struct rtable *rt;
a1e59abf8   Patrick McHardy   [XFRM]: Fix wildc...
24

8f01cb082   David S. Miller   ipv4: xfrm: Elimi...
25
26
27
  	memset(fl4, 0, sizeof(*fl4));
  	fl4->daddr = daddr->a4;
  	fl4->flowi4_tos = tos;
66cdb3ca2   Herbert Xu   [IPSEC]: Move flo...
28
  	if (saddr)
8f01cb082   David S. Miller   ipv4: xfrm: Elimi...
29
  		fl4->saddr = saddr->a4;
66cdb3ca2   Herbert Xu   [IPSEC]: Move flo...
30

8f01cb082   David S. Miller   ipv4: xfrm: Elimi...
31
  	rt = __ip_route_output_key(net, fl4);
b23dd4fe4   David S. Miller   ipv4: Make output...
32
33
34
35
  	if (!IS_ERR(rt))
  		return &rt->dst;
  
  	return ERR_CAST(rt);
66cdb3ca2   Herbert Xu   [IPSEC]: Move flo...
36
  }
8f01cb082   David S. Miller   ipv4: xfrm: Elimi...
37
38
39
40
41
42
43
44
  static struct dst_entry *xfrm4_dst_lookup(struct net *net, int tos,
  					  const xfrm_address_t *saddr,
  					  const xfrm_address_t *daddr)
  {
  	struct flowi4 fl4;
  
  	return __xfrm4_dst_lookup(net, &fl4, tos, saddr, daddr);
  }
fbda33b2b   Alexey Dobriyan   netns xfrm: ->get...
45
46
  static int xfrm4_get_saddr(struct net *net,
  			   xfrm_address_t *saddr, xfrm_address_t *daddr)
66cdb3ca2   Herbert Xu   [IPSEC]: Move flo...
47
48
  {
  	struct dst_entry *dst;
8f01cb082   David S. Miller   ipv4: xfrm: Elimi...
49
  	struct flowi4 fl4;
66cdb3ca2   Herbert Xu   [IPSEC]: Move flo...
50

8f01cb082   David S. Miller   ipv4: xfrm: Elimi...
51
  	dst = __xfrm4_dst_lookup(net, &fl4, 0, NULL, daddr);
66cdb3ca2   Herbert Xu   [IPSEC]: Move flo...
52
53
  	if (IS_ERR(dst))
  		return -EHOSTUNREACH;
8f01cb082   David S. Miller   ipv4: xfrm: Elimi...
54
  	saddr->a4 = fl4.saddr;
66cdb3ca2   Herbert Xu   [IPSEC]: Move flo...
55
56
  	dst_release(dst);
  	return 0;
a1e59abf8   Patrick McHardy   [XFRM]: Fix wildc...
57
  }
05d840257   David S. Miller   xfrm: Mark flowi ...
58
  static int xfrm4_get_tos(const struct flowi *fl)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59
  {
7e1dc7b6f   David S. Miller   net: Use flowi4 a...
60
  	return IPTOS_RT_MASK & fl->u.ip4.flowi4_tos; /* Strip ECN bits */
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
61
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62

a1b051405   Masahide NAKAMURA   [XFRM] IPv6: Fix ...
63
64
65
66
67
  static int xfrm4_init_path(struct xfrm_dst *path, struct dst_entry *dst,
  			   int nfheader_len)
  {
  	return 0;
  }
87c1e12b5   Herbert Xu   ipsec: Fix bogus ...
68
  static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
0c7b3eefb   David S. Miller   xfrm: Mark flowi ...
69
  			  const struct flowi *fl)
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
70
71
  {
  	struct rtable *rt = (struct rtable *)xdst->route;
7e1dc7b6f   David S. Miller   net: Use flowi4 a...
72
  	const struct flowi4 *fl4 = &fl->u.ip4;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73

b73233960   Yan, Zheng   ipv4: fix ipsec f...
74
  	xdst->u.rt.rt_iif = fl4->flowi4_iif;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75

25ee3286d   Herbert Xu   [IPSEC]: Merge co...
76
77
  	xdst->u.dst.dev = dev;
  	dev_hold(dev);
433722622   Miika Komu   [IPSEC]: IPv4 ove...
78

25ee3286d   Herbert Xu   [IPSEC]: Merge co...
79
80
  	/* Sheit... I remember I did this right. Apparently,
  	 * it was magically lost, so this code needs audit */
9917e1e87   David S. Miller   ipv4: Turn rt->rt...
81
  	xdst->u.rt.rt_is_input = rt->rt_is_input;
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
82
83
84
  	xdst->u.rt.rt_flags = rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST |
  					      RTCF_LOCAL);
  	xdst->u.rt.rt_type = rt->rt_type;
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
85
  	xdst->u.rt.rt_gateway = rt->rt_gateway;
155e8336c   Julian Anastasov   ipv4: introduce r...
86
  	xdst->u.rt.rt_uses_gateway = rt->rt_uses_gateway;
5943634fc   David S. Miller   ipv4: Maintain re...
87
  	xdst->u.rt.rt_pmtu = rt->rt_pmtu;
caacf05e5   David S. Miller   ipv4: Properly pu...
88
  	INIT_LIST_HEAD(&xdst->u.rt.rt_uncached);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
92
93
  }
  
  static void
d5422efe6   Herbert Xu   [IPSEC]: Added xf...
94
  _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
  {
b71d1d426   Eric Dumazet   inet: constify ip...
96
  	const struct iphdr *iph = ip_hdr(skb);
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
97
  	u8 *xprth = skb_network_header(skb) + iph->ihl * 4;
7e1dc7b6f   David S. Miller   net: Use flowi4 a...
98
  	struct flowi4 *fl4 = &fl->u.ip4;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
99

7e1dc7b6f   David S. Miller   net: Use flowi4 a...
100
101
  	memset(fl4, 0, sizeof(struct flowi4));
  	fl4->flowi4_mark = skb->mark;
44b451f16   Peter Kosyh   xfrm: fix xfrm by...
102

56f8a75c1   Paul Gortmaker   ip: introduce ip_...
103
  	if (!ip_is_fragment(iph)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
105
  		switch (iph->protocol) {
  		case IPPROTO_UDP:
ba4e58eca   Gerrit Renker   [NET]: Supporting...
106
  		case IPPROTO_UDPLITE:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107
108
  		case IPPROTO_TCP:
  		case IPPROTO_SCTP:
9e999993c   Patrick McHardy   [XFRM]: Handle DC...
109
  		case IPPROTO_DCCP:
c615c9f3f   Wei Yongjun   xfrm4: fix the po...
110
111
  			if (xprth + 4 < skb->data ||
  			    pskb_may_pull(skb, xprth + 4 - skb->data)) {
8c689a6ea   Al Viro   [XFRM]: misc anno...
112
  				__be16 *ports = (__be16 *)xprth;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113

9cce96df5   David S. Miller   net: Put fl4_* ma...
114
115
  				fl4->fl4_sport = ports[!!reverse];
  				fl4->fl4_dport = ports[!reverse];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
117
118
119
120
121
  			}
  			break;
  
  		case IPPROTO_ICMP:
  			if (pskb_may_pull(skb, xprth + 2 - skb->data)) {
  				u8 *icmp = xprth;
9cce96df5   David S. Miller   net: Put fl4_* ma...
122
123
  				fl4->fl4_icmp_type = icmp[0];
  				fl4->fl4_icmp_code = icmp[1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124
125
126
127
128
  			}
  			break;
  
  		case IPPROTO_ESP:
  			if (pskb_may_pull(skb, xprth + 4 - skb->data)) {
4324a1743   Al Viro   [XFRM]: fl_ipsec_...
129
  				__be32 *ehdr = (__be32 *)xprth;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130

9cce96df5   David S. Miller   net: Put fl4_* ma...
131
  				fl4->fl4_ipsec_spi = ehdr[0];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132
133
134
135
136
  			}
  			break;
  
  		case IPPROTO_AH:
  			if (pskb_may_pull(skb, xprth + 8 - skb->data)) {
5e73ea1a3   Daniel Baluta   ipv4: fix checkpa...
137
  				__be32 *ah_hdr = (__be32 *)xprth;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138

9cce96df5   David S. Miller   net: Put fl4_* ma...
139
  				fl4->fl4_ipsec_spi = ah_hdr[1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
141
142
143
144
  			}
  			break;
  
  		case IPPROTO_COMP:
  			if (pskb_may_pull(skb, xprth + 4 - skb->data)) {
4324a1743   Al Viro   [XFRM]: fl_ipsec_...
145
  				__be16 *ipcomp_hdr = (__be16 *)xprth;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146

9cce96df5   David S. Miller   net: Put fl4_* ma...
147
  				fl4->fl4_ipsec_spi = htonl(ntohs(ipcomp_hdr[1]));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
149
  			}
  			break;
cc9ff19da   Timo Teräs   xfrm: use gre key...
150
151
152
153
154
155
156
157
158
  
  		case IPPROTO_GRE:
  			if (pskb_may_pull(skb, xprth + 12 - skb->data)) {
  				__be16 *greflags = (__be16 *)xprth;
  				__be32 *gre_hdr = (__be32 *)xprth;
  
  				if (greflags[0] & GRE_KEY) {
  					if (greflags[0] & GRE_CSUM)
  						gre_hdr++;
9cce96df5   David S. Miller   net: Put fl4_* ma...
159
  					fl4->fl4_gre_key = gre_hdr[1];
cc9ff19da   Timo Teräs   xfrm: use gre key...
160
161
162
  				}
  			}
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
  		default:
9cce96df5   David S. Miller   net: Put fl4_* ma...
164
  			fl4->fl4_ipsec_spi = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
  			break;
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
166
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
  	}
7e1dc7b6f   David S. Miller   net: Use flowi4 a...
168
169
170
171
  	fl4->flowi4_proto = iph->protocol;
  	fl4->daddr = reverse ? iph->saddr : iph->daddr;
  	fl4->saddr = reverse ? iph->daddr : iph->saddr;
  	fl4->flowi4_tos = iph->tos;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
172
  }
569d36452   Daniel Lezcano   [NETNS][DST] dst:...
173
  static inline int xfrm4_garbage_collect(struct dst_ops *ops)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
  {
d7c7544c3   Alexey Dobriyan   netns xfrm: deal ...
175
176
177
  	struct net *net = container_of(ops, struct net, xfrm.xfrm4_dst_ops);
  
  	xfrm4_policy_afinfo.garbage_collect(net);
fc66f95c6   Eric Dumazet   net dst: use a pe...
178
  	return (dst_entries_get_slow(ops) > ops->gc_thresh * 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
  }
6700c2709   David S. Miller   net: Pass optiona...
180
181
  static void xfrm4_update_pmtu(struct dst_entry *dst, struct sock *sk,
  			      struct sk_buff *skb, u32 mtu)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
183
184
  {
  	struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
  	struct dst_entry *path = xdst->route;
6700c2709   David S. Miller   net: Pass optiona...
185
  	path->ops->update_pmtu(path, sk, skb, mtu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186
  }
6700c2709   David S. Miller   net: Pass optiona...
187
188
  static void xfrm4_redirect(struct dst_entry *dst, struct sock *sk,
  			   struct sk_buff *skb)
55be7a9c6   David S. Miller   ipv4: Add redirec...
189
190
191
  {
  	struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
  	struct dst_entry *path = xdst->route;
6700c2709   David S. Miller   net: Pass optiona...
192
  	path->ops->redirect(path, sk, skb);
55be7a9c6   David S. Miller   ipv4: Add redirec...
193
  }
aabc9761b   Herbert Xu   [IPSEC]: Store id...
194
195
196
  static void xfrm4_dst_destroy(struct dst_entry *dst)
  {
  	struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
62fa8a846   David S. Miller   net: Implement re...
197
  	dst_destroy_metrics_generic(dst);
aabc9761b   Herbert Xu   [IPSEC]: Store id...
198
199
200
201
202
203
  	xfrm_dst_destroy(xdst);
  }
  
  static void xfrm4_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
  			     int unregister)
  {
aabc9761b   Herbert Xu   [IPSEC]: Store id...
204
205
  	if (!unregister)
  		return;
aabc9761b   Herbert Xu   [IPSEC]: Store id...
206
207
  	xfrm_dst_ifdown(dst, dev);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
209
  static struct dst_ops xfrm4_dst_ops = {
  	.family =		AF_INET,
09640e636   Harvey Harrison   net: replace uses...
210
  	.protocol =		cpu_to_be16(ETH_P_IP),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
212
  	.gc =			xfrm4_garbage_collect,
  	.update_pmtu =		xfrm4_update_pmtu,
55be7a9c6   David S. Miller   ipv4: Add redirec...
213
  	.redirect =		xfrm4_redirect,
62fa8a846   David S. Miller   net: Implement re...
214
  	.cow_metrics =		dst_cow_metrics_generic,
aabc9761b   Herbert Xu   [IPSEC]: Store id...
215
216
  	.destroy =		xfrm4_dst_destroy,
  	.ifdown =		xfrm4_dst_ifdown,
862b82c6f   Herbert Xu   [IPSEC]: Merge mo...
217
  	.local_out =		__ip_local_out,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
  	.gc_thresh =		1024,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219
220
221
222
  };
  
  static struct xfrm_policy_afinfo xfrm4_policy_afinfo = {
  	.family = 		AF_INET,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223
224
  	.dst_ops =		&xfrm4_dst_ops,
  	.dst_lookup =		xfrm4_dst_lookup,
a1e59abf8   Patrick McHardy   [XFRM]: Fix wildc...
225
  	.get_saddr =		xfrm4_get_saddr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
  	.decode_session =	_decode_session4,
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
227
  	.get_tos =		xfrm4_get_tos,
a1b051405   Masahide NAKAMURA   [XFRM] IPv6: Fix ...
228
  	.init_path =		xfrm4_init_path,
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
229
  	.fill_dst =		xfrm4_fill_dst,
2774c131b   David S. Miller   xfrm: Handle blac...
230
  	.blackhole_route =	ipv4_blackhole_route,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231
  };
f816700aa   Randy Dunlap   xfrm4: fix build ...
232
  #ifdef CONFIG_SYSCTL
a44a4a006   Neil Horman   xfrm: export xfrm...
233
234
  static struct ctl_table xfrm4_policy_table[] = {
  	{
a44a4a006   Neil Horman   xfrm: export xfrm...
235
  		.procname       = "xfrm4_gc_thresh",
d7c7544c3   Alexey Dobriyan   netns xfrm: deal ...
236
  		.data           = &init_net.xfrm.xfrm4_dst_ops.gc_thresh,
a44a4a006   Neil Horman   xfrm: export xfrm...
237
238
239
240
241
242
  		.maxlen         = sizeof(int),
  		.mode           = 0644,
  		.proc_handler   = proc_dointvec,
  	},
  	{ }
  };
8d068875c   Michal Kubecek   xfrm: make gc_thr...
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
  static int __net_init xfrm4_net_init(struct net *net)
  {
  	struct ctl_table *table;
  	struct ctl_table_header *hdr;
  
  	table = xfrm4_policy_table;
  	if (!net_eq(net, &init_net)) {
  		table = kmemdup(table, sizeof(xfrm4_policy_table), GFP_KERNEL);
  		if (!table)
  			goto err_alloc;
  
  		table[0].data = &net->xfrm.xfrm4_dst_ops.gc_thresh;
  	}
  
  	hdr = register_net_sysctl(net, "net/ipv4", table);
  	if (!hdr)
  		goto err_reg;
  
  	net->ipv4.xfrm4_hdr = hdr;
  	return 0;
  
  err_reg:
  	if (!net_eq(net, &init_net))
  		kfree(table);
  err_alloc:
  	return -ENOMEM;
  }
  
  static void __net_exit xfrm4_net_exit(struct net *net)
  {
  	struct ctl_table *table;
  
  	if (net->ipv4.xfrm4_hdr == NULL)
  		return;
  
  	table = net->ipv4.xfrm4_hdr->ctl_table_arg;
  	unregister_net_sysctl_table(net->ipv4.xfrm4_hdr);
  	if (!net_eq(net, &init_net))
  		kfree(table);
  }
  
  static struct pernet_operations __net_initdata xfrm4_net_ops = {
  	.init	= xfrm4_net_init,
  	.exit	= xfrm4_net_exit,
  };
f816700aa   Randy Dunlap   xfrm4: fix build ...
288
  #endif
a44a4a006   Neil Horman   xfrm: export xfrm...
289

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
290
291
292
293
  static void __init xfrm4_policy_init(void)
  {
  	xfrm_policy_register_afinfo(&xfrm4_policy_afinfo);
  }
703fb94ec   Steffen Klassert   xfrm: Fix the gc ...
294
  void __init xfrm4_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
  {
fc66f95c6   Eric Dumazet   net dst: use a pe...
296
  	dst_entries_init(&xfrm4_dst_ops);
d7c7544c3   Alexey Dobriyan   netns xfrm: deal ...
297
298
299
  
  	xfrm4_state_init();
  	xfrm4_policy_init();
f816700aa   Randy Dunlap   xfrm4: fix build ...
300
  #ifdef CONFIG_SYSCTL
8d068875c   Michal Kubecek   xfrm: make gc_thr...
301
  	register_pernet_subsys(&xfrm4_net_ops);
f816700aa   Randy Dunlap   xfrm4: fix build ...
302
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303
  }