Blame view

net/key/af_key.c 99.8 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  /*
   * net/key/af_key.c	An implementation of PF_KEYv2 sockets.
   *
   *		This program is free software; you can redistribute it and/or
   *		modify it under the terms of the GNU General Public License
   *		as published by the Free Software Foundation; either version
   *		2 of the License, or (at your option) any later version.
   *
   * Authors:	Maxim Giryaev	<gem@asplinux.ru>
   *		David S. Miller	<davem@redhat.com>
   *		Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
   *		Kunihiro Ishiguro <kunihiro@ipinfusion.com>
   *		Kazunori MIYAZAWA / USAGI Project <miyazawa@linux-ipv6.org>
   *		Derek Atkins <derek@ihtfp.com>
   */
4fc268d24   Randy Dunlap   [PATCH] capable/c...
16
  #include <linux/capability.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
19
20
21
22
23
24
25
26
27
  #include <linux/module.h>
  #include <linux/kernel.h>
  #include <linux/socket.h>
  #include <linux/pfkeyv2.h>
  #include <linux/ipsec.h>
  #include <linux/skbuff.h>
  #include <linux/rtnetlink.h>
  #include <linux/in.h>
  #include <linux/in6.h>
  #include <linux/proc_fs.h>
  #include <linux/init.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
28
  #include <linux/slab.h>
457c4cbc5   Eric W. Biederman   [NET]: Make /proc...
29
  #include <net/net_namespace.h>
3fa87a321   Alexey Dobriyan   netns PF_KEY: part 1
30
  #include <net/netns/generic.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
33
34
35
36
  #include <net/xfrm.h>
  
  #include <net/sock.h>
  
  #define _X2KEY(x) ((x) == XFRM_INF ? 0 : (x))
  #define _KEY2X(x) ((x) == 0 ? XFRM_INF : (x))
f99189b18   Eric Dumazet   netns: net_identi...
37
  static int pfkey_net_id __read_mostly;
3fa87a321   Alexey Dobriyan   netns PF_KEY: part 1
38
39
40
41
42
  struct netns_pfkey {
  	/* List of all pfkey sockets. */
  	struct hlist_head table;
  	atomic_t socks_nr;
  };
7f6b9dbd5   stephen hemminger   af_key: locking c...
43
  static DEFINE_MUTEX(pfkey_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44

bd55775c8   Jamal Hadi Salim   xfrm: SA lookups ...
45
46
  #define DUMMY_MARK 0
  static struct xfrm_mark dummy_mark = {0, 0};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
48
49
50
51
  struct pfkey_sock {
  	/* struct sock must be the first member of struct pfkey_sock */
  	struct sock	sk;
  	int		registered;
  	int		promisc;
83321d6b9   Timo Teras   [AF_KEY]: Dump SA...
52
53
54
55
56
57
58
59
60
61
  
  	struct {
  		uint8_t		msg_version;
  		uint32_t	msg_pid;
  		int		(*dump)(struct pfkey_sock *sk);
  		void		(*done)(struct pfkey_sock *sk);
  		union {
  			struct xfrm_policy_walk	policy;
  			struct xfrm_state_walk	state;
  		} u;
12a169e7d   Herbert Xu   ipsec: Put dumper...
62
  		struct sk_buff	*skb;
83321d6b9   Timo Teras   [AF_KEY]: Dump SA...
63
  	} dump;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
65
66
67
68
69
  };
  
  static inline struct pfkey_sock *pfkey_sk(struct sock *sk)
  {
  	return (struct pfkey_sock *)sk;
  }
4c93fbb06   David S. Miller   pfkey: Use const ...
70
  static int pfkey_can_dump(const struct sock *sk)
83321d6b9   Timo Teras   [AF_KEY]: Dump SA...
71
72
73
74
75
  {
  	if (3 * atomic_read(&sk->sk_rmem_alloc) <= 2 * sk->sk_rcvbuf)
  		return 1;
  	return 0;
  }
052382048   Timo Teras   af_key: Free dump...
76
  static void pfkey_terminate_dump(struct pfkey_sock *pfk)
83321d6b9   Timo Teras   [AF_KEY]: Dump SA...
77
  {
052382048   Timo Teras   af_key: Free dump...
78
  	if (pfk->dump.dump) {
12a169e7d   Herbert Xu   ipsec: Put dumper...
79
80
81
82
  		if (pfk->dump.skb) {
  			kfree_skb(pfk->dump.skb);
  			pfk->dump.skb = NULL;
  		}
052382048   Timo Teras   af_key: Free dump...
83
84
85
86
  		pfk->dump.done(pfk);
  		pfk->dump.dump = NULL;
  		pfk->dump.done = NULL;
  	}
83321d6b9   Timo Teras   [AF_KEY]: Dump SA...
87
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88
89
  static void pfkey_sock_destruct(struct sock *sk)
  {
3fa87a321   Alexey Dobriyan   netns PF_KEY: part 1
90
91
  	struct net *net = sock_net(sk);
  	struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
052382048   Timo Teras   af_key: Free dump...
92
  	pfkey_terminate_dump(pfkey_sk(sk));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93
94
95
  	skb_queue_purge(&sk->sk_receive_queue);
  
  	if (!sock_flag(sk, SOCK_DEAD)) {
207024b94   stephen hemminger   pfkey: add severi...
96
97
  		pr_err("Attempt to release alive pfkey socket: %p
  ", sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
99
  		return;
  	}
547b792ca   Ilpo Järvinen   net: convert BUG_...
100
101
  	WARN_ON(atomic_read(&sk->sk_rmem_alloc));
  	WARN_ON(atomic_read(&sk->sk_wmem_alloc));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102

3fa87a321   Alexey Dobriyan   netns PF_KEY: part 1
103
  	atomic_dec(&net_pfkey->socks_nr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
  }
90ddc4f04   Eric Dumazet   [NET]: move struc...
105
  static const struct proto_ops pfkey_ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106
107
108
  
  static void pfkey_insert(struct sock *sk)
  {
3fa87a321   Alexey Dobriyan   netns PF_KEY: part 1
109
110
  	struct net *net = sock_net(sk);
  	struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
7f6b9dbd5   stephen hemminger   af_key: locking c...
111
112
113
  	mutex_lock(&pfkey_mutex);
  	sk_add_node_rcu(sk, &net_pfkey->table);
  	mutex_unlock(&pfkey_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
115
116
117
  }
  
  static void pfkey_remove(struct sock *sk)
  {
7f6b9dbd5   stephen hemminger   af_key: locking c...
118
119
120
  	mutex_lock(&pfkey_mutex);
  	sk_del_node_init_rcu(sk);
  	mutex_unlock(&pfkey_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
122
123
124
125
126
127
  }
  
  static struct proto key_proto = {
  	.name	  = "KEY",
  	.owner	  = THIS_MODULE,
  	.obj_size = sizeof(struct pfkey_sock),
  };
3f378b684   Eric Paris   net: pass kern to...
128
129
  static int pfkey_create(struct net *net, struct socket *sock, int protocol,
  			int kern)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130
  {
3fa87a321   Alexey Dobriyan   netns PF_KEY: part 1
131
  	struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132
133
134
135
136
137
138
139
140
141
142
  	struct sock *sk;
  	int err;
  
  	if (!capable(CAP_NET_ADMIN))
  		return -EPERM;
  	if (sock->type != SOCK_RAW)
  		return -ESOCKTNOSUPPORT;
  	if (protocol != PF_KEY_V2)
  		return -EPROTONOSUPPORT;
  
  	err = -ENOMEM;
6257ff217   Pavel Emelyanov   [NET]: Forget the...
143
  	sk = sk_alloc(net, PF_KEY, GFP_KERNEL, &key_proto);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
145
  	if (sk == NULL)
  		goto out;
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
146

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
148
149
150
151
  	sock->ops = &pfkey_ops;
  	sock_init_data(sock, sk);
  
  	sk->sk_family = PF_KEY;
  	sk->sk_destruct = pfkey_sock_destruct;
3fa87a321   Alexey Dobriyan   netns PF_KEY: part 1
152
  	atomic_inc(&net_pfkey->socks_nr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
  
  	pfkey_insert(sk);
  
  	return 0;
  out:
  	return err;
  }
  
  static int pfkey_release(struct socket *sock)
  {
  	struct sock *sk = sock->sk;
  
  	if (!sk)
  		return 0;
  
  	pfkey_remove(sk);
  
  	sock_orphan(sk);
  	sock->sk = NULL;
  	skb_queue_purge(&sk->sk_write_queue);
7f6b9dbd5   stephen hemminger   af_key: locking c...
173
174
  
  	synchronize_rcu();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
176
177
178
179
180
  	sock_put(sk);
  
  	return 0;
  }
  
  static int pfkey_broadcast_one(struct sk_buff *skb, struct sk_buff **skb2,
dd0fc66fb   Al Viro   [PATCH] gfp flags...
181
  			       gfp_t allocation, struct sock *sk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
  {
  	int err = -ENOBUFS;
  
  	sock_hold(sk);
  	if (*skb2 == NULL) {
  		if (atomic_read(&skb->users) != 1) {
  			*skb2 = skb_clone(skb, allocation);
  		} else {
  			*skb2 = skb;
  			atomic_inc(&skb->users);
  		}
  	}
  	if (*skb2 != NULL) {
  		if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) {
  			skb_orphan(*skb2);
  			skb_set_owner_r(*skb2, sk);
  			skb_queue_tail(&sk->sk_receive_queue, *skb2);
  			sk->sk_data_ready(sk, (*skb2)->len);
  			*skb2 = NULL;
  			err = 0;
  		}
  	}
  	sock_put(sk);
  	return err;
  }
  
  /* Send SKB to all pfkey sockets matching selected criteria.  */
  #define BROADCAST_ALL		0
  #define BROADCAST_ONE		1
  #define BROADCAST_REGISTERED	2
  #define BROADCAST_PROMISC_ONLY	4
dd0fc66fb   Al Viro   [PATCH] gfp flags...
213
  static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation,
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
214
215
  			   int broadcast_flags, struct sock *one_sk,
  			   struct net *net)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216
  {
3fa87a321   Alexey Dobriyan   netns PF_KEY: part 1
217
  	struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
219
220
221
222
223
224
225
226
227
  	struct sock *sk;
  	struct hlist_node *node;
  	struct sk_buff *skb2 = NULL;
  	int err = -ESRCH;
  
  	/* XXX Do we need something like netlink_overrun?  I think
  	 * XXX PF_KEY socket apps will not mind current behavior.
  	 */
  	if (!skb)
  		return -ENOMEM;
7f6b9dbd5   stephen hemminger   af_key: locking c...
228
229
  	rcu_read_lock();
  	sk_for_each_rcu(sk, node, &net_pfkey->table) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
  		struct pfkey_sock *pfk = pfkey_sk(sk);
  		int err2;
  
  		/* Yes, it means that if you are meant to receive this
  		 * pfkey message you receive it twice as promiscuous
  		 * socket.
  		 */
  		if (pfk->promisc)
  			pfkey_broadcast_one(skb, &skb2, allocation, sk);
  
  		/* the exact target will be processed later */
  		if (sk == one_sk)
  			continue;
  		if (broadcast_flags != BROADCAST_ALL) {
  			if (broadcast_flags & BROADCAST_PROMISC_ONLY)
  				continue;
  			if ((broadcast_flags & BROADCAST_REGISTERED) &&
  			    !pfk->registered)
  				continue;
  			if (broadcast_flags & BROADCAST_ONE)
  				continue;
  		}
  
  		err2 = pfkey_broadcast_one(skb, &skb2, allocation, sk);
  
  		/* Error is cleare after succecful sending to at least one
  		 * registered KM */
  		if ((broadcast_flags & BROADCAST_REGISTERED) && err)
  			err = err2;
  	}
7f6b9dbd5   stephen hemminger   af_key: locking c...
260
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261
262
263
  
  	if (one_sk != NULL)
  		err = pfkey_broadcast_one(skb, &skb2, allocation, one_sk);
6f9610686   Wei Yongjun   af_key: remove so...
264
  	kfree_skb(skb2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265
266
267
  	kfree_skb(skb);
  	return err;
  }
052382048   Timo Teras   af_key: Free dump...
268
269
  static int pfkey_do_dump(struct pfkey_sock *pfk)
  {
12a169e7d   Herbert Xu   ipsec: Put dumper...
270
  	struct sadb_msg *hdr;
052382048   Timo Teras   af_key: Free dump...
271
272
273
274
275
  	int rc;
  
  	rc = pfk->dump.dump(pfk);
  	if (rc == -ENOBUFS)
  		return 0;
12a169e7d   Herbert Xu   ipsec: Put dumper...
276
277
278
279
280
281
282
283
  	if (pfk->dump.skb) {
  		if (!pfkey_can_dump(&pfk->sk))
  			return 0;
  
  		hdr = (struct sadb_msg *) pfk->dump.skb->data;
  		hdr->sadb_msg_seq = 0;
  		hdr->sadb_msg_errno = rc;
  		pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE,
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
284
  				&pfk->sk, sock_net(&pfk->sk));
12a169e7d   Herbert Xu   ipsec: Put dumper...
285
286
  		pfk->dump.skb = NULL;
  	}
052382048   Timo Teras   af_key: Free dump...
287
288
289
  	pfkey_terminate_dump(pfk);
  	return rc;
  }
4c93fbb06   David S. Miller   pfkey: Use const ...
290
291
  static inline void pfkey_hdr_dup(struct sadb_msg *new,
  				 const struct sadb_msg *orig)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
293
294
  {
  	*new = *orig;
  }
4c93fbb06   David S. Miller   pfkey: Use const ...
295
  static int pfkey_error(const struct sadb_msg *orig, int err, struct sock *sk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
  {
  	struct sk_buff *skb = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_KERNEL);
  	struct sadb_msg *hdr;
  
  	if (!skb)
  		return -ENOBUFS;
  
  	/* Woe be to the platform trying to support PFKEY yet
  	 * having normal errnos outside the 1-255 range, inclusive.
  	 */
  	err = -err;
  	if (err == ERESTARTSYS ||
  	    err == ERESTARTNOHAND ||
  	    err == ERESTARTNOINTR)
  		err = EINTR;
  	if (err >= 512)
  		err = EINVAL;
09a626600   Kris Katterjohn   [NET]: Change som...
313
  	BUG_ON(err <= 0 || err >= 256);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
315
316
317
318
319
  
  	hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg));
  	pfkey_hdr_dup(hdr, orig);
  	hdr->sadb_msg_errno = (uint8_t) err;
  	hdr->sadb_msg_len = (sizeof(struct sadb_msg) /
  			     sizeof(uint64_t));
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
320
  	pfkey_broadcast(skb, GFP_KERNEL, BROADCAST_ONE, sk, sock_net(sk));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
  
  	return 0;
  }
  
  static u8 sadb_ext_min_len[] = {
  	[SADB_EXT_RESERVED]		= (u8) 0,
  	[SADB_EXT_SA]			= (u8) sizeof(struct sadb_sa),
  	[SADB_EXT_LIFETIME_CURRENT]	= (u8) sizeof(struct sadb_lifetime),
  	[SADB_EXT_LIFETIME_HARD]	= (u8) sizeof(struct sadb_lifetime),
  	[SADB_EXT_LIFETIME_SOFT]	= (u8) sizeof(struct sadb_lifetime),
  	[SADB_EXT_ADDRESS_SRC]		= (u8) sizeof(struct sadb_address),
  	[SADB_EXT_ADDRESS_DST]		= (u8) sizeof(struct sadb_address),
  	[SADB_EXT_ADDRESS_PROXY]	= (u8) sizeof(struct sadb_address),
  	[SADB_EXT_KEY_AUTH]		= (u8) sizeof(struct sadb_key),
  	[SADB_EXT_KEY_ENCRYPT]		= (u8) sizeof(struct sadb_key),
  	[SADB_EXT_IDENTITY_SRC]		= (u8) sizeof(struct sadb_ident),
  	[SADB_EXT_IDENTITY_DST]		= (u8) sizeof(struct sadb_ident),
  	[SADB_EXT_SENSITIVITY]		= (u8) sizeof(struct sadb_sens),
  	[SADB_EXT_PROPOSAL]		= (u8) sizeof(struct sadb_prop),
  	[SADB_EXT_SUPPORTED_AUTH]	= (u8) sizeof(struct sadb_supported),
  	[SADB_EXT_SUPPORTED_ENCRYPT]	= (u8) sizeof(struct sadb_supported),
  	[SADB_EXT_SPIRANGE]		= (u8) sizeof(struct sadb_spirange),
  	[SADB_X_EXT_KMPRIVATE]		= (u8) sizeof(struct sadb_x_kmprivate),
  	[SADB_X_EXT_POLICY]		= (u8) sizeof(struct sadb_x_policy),
  	[SADB_X_EXT_SA2]		= (u8) sizeof(struct sadb_x_sa2),
  	[SADB_X_EXT_NAT_T_TYPE]		= (u8) sizeof(struct sadb_x_nat_t_type),
  	[SADB_X_EXT_NAT_T_SPORT]	= (u8) sizeof(struct sadb_x_nat_t_port),
  	[SADB_X_EXT_NAT_T_DPORT]	= (u8) sizeof(struct sadb_x_nat_t_port),
  	[SADB_X_EXT_NAT_T_OA]		= (u8) sizeof(struct sadb_address),
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
350
  	[SADB_X_EXT_SEC_CTX]		= (u8) sizeof(struct sadb_x_sec_ctx),
13c1d1893   Arnaud Ebalard   xfrm: MIGRATE enh...
351
  	[SADB_X_EXT_KMADDRESS]		= (u8) sizeof(struct sadb_x_kmaddress),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
353
354
  };
  
  /* Verify sadb_address_{len,prefixlen} against sa_family.  */
4c93fbb06   David S. Miller   pfkey: Use const ...
355
  static int verify_address_len(const void *p)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
356
  {
4c93fbb06   David S. Miller   pfkey: Use const ...
357
358
359
  	const struct sadb_address *sp = p;
  	const struct sockaddr *addr = (const struct sockaddr *)(sp + 1);
  	const struct sockaddr_in *sin;
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
360
  #if IS_ENABLED(CONFIG_IPV6)
4c93fbb06   David S. Miller   pfkey: Use const ...
361
  	const struct sockaddr_in6 *sin6;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362
363
364
365
366
  #endif
  	int len;
  
  	switch (addr->sa_family) {
  	case AF_INET:
356f89e12   Ilpo Järvinen   [NET] Cleanup: DI...
367
  		len = DIV_ROUND_UP(sizeof(*sp) + sizeof(*sin), sizeof(uint64_t));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
369
370
371
  		if (sp->sadb_address_len != len ||
  		    sp->sadb_address_prefixlen > 32)
  			return -EINVAL;
  		break;
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
372
  #if IS_ENABLED(CONFIG_IPV6)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373
  	case AF_INET6:
356f89e12   Ilpo Järvinen   [NET] Cleanup: DI...
374
  		len = DIV_ROUND_UP(sizeof(*sp) + sizeof(*sin6), sizeof(uint64_t));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
  		if (sp->sadb_address_len != len ||
  		    sp->sadb_address_prefixlen > 128)
  			return -EINVAL;
  		break;
  #endif
  	default:
  		/* It is user using kernel to keep track of security
  		 * associations for another protocol, such as
  		 * OSPF/RSVP/RIPV2/MIP.  It is user's job to verify
  		 * lengths.
  		 *
  		 * XXX Actually, association/policy database is not yet
  		 * XXX able to cope with arbitrary sockaddr families.
  		 * XXX When it can, remove this -EINVAL.  -DaveM
  		 */
  		return -EINVAL;
  		break;
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
392
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393
394
395
  
  	return 0;
  }
4c93fbb06   David S. Miller   pfkey: Use const ...
396
  static inline int pfkey_sec_ctx_len(const struct sadb_x_sec_ctx *sec_ctx)
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
397
  {
356f89e12   Ilpo Järvinen   [NET] Cleanup: DI...
398
399
400
  	return DIV_ROUND_UP(sizeof(struct sadb_x_sec_ctx) +
  			    sec_ctx->sadb_x_ctx_len,
  			    sizeof(uint64_t));
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
401
  }
4c93fbb06   David S. Miller   pfkey: Use const ...
402
  static inline int verify_sec_ctx_len(const void *p)
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
403
  {
4c93fbb06   David S. Miller   pfkey: Use const ...
404
  	const struct sadb_x_sec_ctx *sec_ctx = p;
298bb6217   Stephen Rothwell   [AF_KEY]: suppres...
405
  	int len = sec_ctx->sadb_x_ctx_len;
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
406

298bb6217   Stephen Rothwell   [AF_KEY]: suppres...
407
  	if (len > PAGE_SIZE)
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
408
409
410
411
412
413
414
415
416
  		return -EINVAL;
  
  	len = pfkey_sec_ctx_len(sec_ctx);
  
  	if (sec_ctx->sadb_x_sec_len != len)
  		return -EINVAL;
  
  	return 0;
  }
4c93fbb06   David S. Miller   pfkey: Use const ...
417
  static inline struct xfrm_user_sec_ctx *pfkey_sadb2xfrm_user_sec_ctx(const struct sadb_x_sec_ctx *sec_ctx)
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
  {
  	struct xfrm_user_sec_ctx *uctx = NULL;
  	int ctx_size = sec_ctx->sadb_x_ctx_len;
  
  	uctx = kmalloc((sizeof(*uctx)+ctx_size), GFP_KERNEL);
  
  	if (!uctx)
  		return NULL;
  
  	uctx->len = pfkey_sec_ctx_len(sec_ctx);
  	uctx->exttype = sec_ctx->sadb_x_sec_exttype;
  	uctx->ctx_doi = sec_ctx->sadb_x_ctx_doi;
  	uctx->ctx_alg = sec_ctx->sadb_x_ctx_alg;
  	uctx->ctx_len = sec_ctx->sadb_x_ctx_len;
  	memcpy(uctx + 1, sec_ctx + 1,
  	       uctx->ctx_len);
  
  	return uctx;
  }
4c93fbb06   David S. Miller   pfkey: Use const ...
437
438
  static int present_and_same_family(const struct sadb_address *src,
  				   const struct sadb_address *dst)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
  {
4c93fbb06   David S. Miller   pfkey: Use const ...
440
  	const struct sockaddr *s_addr, *d_addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
441
442
443
  
  	if (!src || !dst)
  		return 0;
4c93fbb06   David S. Miller   pfkey: Use const ...
444
445
  	s_addr = (const struct sockaddr *)(src + 1);
  	d_addr = (const struct sockaddr *)(dst + 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
446
447
448
  	if (s_addr->sa_family != d_addr->sa_family)
  		return 0;
  	if (s_addr->sa_family != AF_INET
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
449
  #if IS_ENABLED(CONFIG_IPV6)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
450
451
452
453
454
455
456
  	    && s_addr->sa_family != AF_INET6
  #endif
  		)
  		return 0;
  
  	return 1;
  }
4c93fbb06   David S. Miller   pfkey: Use const ...
457
  static int parse_exthdrs(struct sk_buff *skb, const struct sadb_msg *hdr, void **ext_hdrs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458
  {
4c93fbb06   David S. Miller   pfkey: Use const ...
459
  	const char *p = (char *) hdr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
460
461
462
463
464
  	int len = skb->len;
  
  	len -= sizeof(*hdr);
  	p += sizeof(*hdr);
  	while (len > 0) {
4c93fbb06   David S. Miller   pfkey: Use const ...
465
  		const struct sadb_ext *ehdr = (const struct sadb_ext *) p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
  		uint16_t ext_type;
  		int ext_len;
  
  		ext_len  = ehdr->sadb_ext_len;
  		ext_len *= sizeof(uint64_t);
  		ext_type = ehdr->sadb_ext_type;
  		if (ext_len < sizeof(uint64_t) ||
  		    ext_len > len ||
  		    ext_type == SADB_EXT_RESERVED)
  			return -EINVAL;
  
  		if (ext_type <= SADB_EXT_MAX) {
  			int min = (int) sadb_ext_min_len[ext_type];
  			if (ext_len < min)
  				return -EINVAL;
  			if (ext_hdrs[ext_type-1] != NULL)
  				return -EINVAL;
  			if (ext_type == SADB_EXT_ADDRESS_SRC ||
  			    ext_type == SADB_EXT_ADDRESS_DST ||
  			    ext_type == SADB_EXT_ADDRESS_PROXY ||
  			    ext_type == SADB_X_EXT_NAT_T_OA) {
  				if (verify_address_len(p))
  					return -EINVAL;
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
489
  			}
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
490
491
492
493
  			if (ext_type == SADB_X_EXT_SEC_CTX) {
  				if (verify_sec_ctx_len(p))
  					return -EINVAL;
  			}
4c93fbb06   David S. Miller   pfkey: Use const ...
494
  			ext_hdrs[ext_type-1] = (void *) p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
  		}
  		p   += ext_len;
  		len -= ext_len;
  	}
  
  	return 0;
  }
  
  static uint16_t
  pfkey_satype2proto(uint8_t satype)
  {
  	switch (satype) {
  	case SADB_SATYPE_UNSPEC:
  		return IPSEC_PROTO_ANY;
  	case SADB_SATYPE_AH:
  		return IPPROTO_AH;
  	case SADB_SATYPE_ESP:
  		return IPPROTO_ESP;
  	case SADB_X_SATYPE_IPCOMP:
  		return IPPROTO_COMP;
  		break;
  	default:
  		return 0;
  	}
  	/* NOTREACHED */
  }
  
  static uint8_t
  pfkey_proto2satype(uint16_t proto)
  {
  	switch (proto) {
  	case IPPROTO_AH:
  		return SADB_SATYPE_AH;
  	case IPPROTO_ESP:
  		return SADB_SATYPE_ESP;
  	case IPPROTO_COMP:
  		return SADB_X_SATYPE_IPCOMP;
  		break;
  	default:
  		return 0;
  	}
  	/* NOTREACHED */
  }
  
  /* BTW, this scheme means that there is no way with PFKEY2 sockets to
   * say specifically 'just raw sockets' as we encode them as 255.
   */
  
  static uint8_t pfkey_proto_to_xfrm(uint8_t proto)
  {
a02cec215   Eric Dumazet   net: return opera...
545
  	return proto == IPSEC_PROTO_ANY ? 0 : proto;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546
547
548
549
  }
  
  static uint8_t pfkey_proto_from_xfrm(uint8_t proto)
  {
a02cec215   Eric Dumazet   net: return opera...
550
  	return proto ? proto : IPSEC_PROTO_ANY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551
  }
9e8b4ed8b   YOSHIFUJI Hideaki   key: Introduce pf...
552
553
554
555
556
  static inline int pfkey_sockaddr_len(sa_family_t family)
  {
  	switch (family) {
  	case AF_INET:
  		return sizeof(struct sockaddr_in);
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
557
  #if IS_ENABLED(CONFIG_IPV6)
9e8b4ed8b   YOSHIFUJI Hideaki   key: Introduce pf...
558
559
560
561
562
563
  	case AF_INET6:
  		return sizeof(struct sockaddr_in6);
  #endif
  	}
  	return 0;
  }
5f95ac911   YOSHIFUJI Hideaki   key: Share common...
564
565
  static
  int pfkey_sockaddr_extract(const struct sockaddr *sa, xfrm_address_t *xaddr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566
  {
5f95ac911   YOSHIFUJI Hideaki   key: Share common...
567
  	switch (sa->sa_family) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
568
  	case AF_INET:
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
569
  		xaddr->a4 =
5f95ac911   YOSHIFUJI Hideaki   key: Share common...
570
  			((struct sockaddr_in *)sa)->sin_addr.s_addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
571
  		return AF_INET;
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
572
  #if IS_ENABLED(CONFIG_IPV6)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
573
  	case AF_INET6:
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
574
  		memcpy(xaddr->a6,
5f95ac911   YOSHIFUJI Hideaki   key: Share common...
575
  		       &((struct sockaddr_in6 *)sa)->sin6_addr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
576
577
578
  		       sizeof(struct in6_addr));
  		return AF_INET6;
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
579
  	}
5f95ac911   YOSHIFUJI Hideaki   key: Share common...
580
581
582
583
  	return 0;
  }
  
  static
4c93fbb06   David S. Miller   pfkey: Use const ...
584
  int pfkey_sadb_addr2xfrm_addr(const struct sadb_address *addr, xfrm_address_t *xaddr)
5f95ac911   YOSHIFUJI Hideaki   key: Share common...
585
586
587
  {
  	return pfkey_sockaddr_extract((struct sockaddr *)(addr + 1),
  				      xaddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
588
  }
4c93fbb06   David S. Miller   pfkey: Use const ...
589
  static struct  xfrm_state *pfkey_xfrm_state_lookup(struct net *net, const struct sadb_msg *hdr, void * const *ext_hdrs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
590
  {
4c93fbb06   David S. Miller   pfkey: Use const ...
591
592
  	const struct sadb_sa *sa;
  	const struct sadb_address *addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
593
594
595
  	uint16_t proto;
  	unsigned short family;
  	xfrm_address_t *xaddr;
ea1107338   Joe Perches   net: Remove casts...
596
  	sa = ext_hdrs[SADB_EXT_SA - 1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
597
598
599
600
601
602
603
604
  	if (sa == NULL)
  		return NULL;
  
  	proto = pfkey_satype2proto(hdr->sadb_msg_satype);
  	if (proto == 0)
  		return NULL;
  
  	/* sadb_address_len should be checked by caller */
ea1107338   Joe Perches   net: Remove casts...
605
  	addr = ext_hdrs[SADB_EXT_ADDRESS_DST - 1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
606
607
  	if (addr == NULL)
  		return NULL;
4c93fbb06   David S. Miller   pfkey: Use const ...
608
  	family = ((const struct sockaddr *)(addr + 1))->sa_family;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
609
610
  	switch (family) {
  	case AF_INET:
4c93fbb06   David S. Miller   pfkey: Use const ...
611
  		xaddr = (xfrm_address_t *)&((const struct sockaddr_in *)(addr + 1))->sin_addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
612
  		break;
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
613
  #if IS_ENABLED(CONFIG_IPV6)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
614
  	case AF_INET6:
4c93fbb06   David S. Miller   pfkey: Use const ...
615
  		xaddr = (xfrm_address_t *)&((const struct sockaddr_in6 *)(addr + 1))->sin6_addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
616
617
618
619
620
621
622
623
  		break;
  #endif
  	default:
  		xaddr = NULL;
  	}
  
  	if (!xaddr)
  		return NULL;
bd55775c8   Jamal Hadi Salim   xfrm: SA lookups ...
624
  	return xfrm_state_lookup(net, DUMMY_MARK, xaddr, sa->sadb_sa_spi, proto, family);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
625
626
627
  }
  
  #define PFKEY_ALIGN8(a) (1 + (((a) - 1) | (8 - 1)))
9e8b4ed8b   YOSHIFUJI Hideaki   key: Introduce pf...
628

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
629
630
631
  static int
  pfkey_sockaddr_size(sa_family_t family)
  {
9e8b4ed8b   YOSHIFUJI Hideaki   key: Introduce pf...
632
  	return PFKEY_ALIGN8(pfkey_sockaddr_len(family));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
633
  }
55569ce25   Kazunori MIYAZAWA   [KEY]: Fix conver...
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
  static inline int pfkey_mode_from_xfrm(int mode)
  {
  	switch(mode) {
  	case XFRM_MODE_TRANSPORT:
  		return IPSEC_MODE_TRANSPORT;
  	case XFRM_MODE_TUNNEL:
  		return IPSEC_MODE_TUNNEL;
  	case XFRM_MODE_BEET:
  		return IPSEC_MODE_BEET;
  	default:
  		return -1;
  	}
  }
  
  static inline int pfkey_mode_to_xfrm(int mode)
  {
  	switch(mode) {
  	case IPSEC_MODE_ANY:	/*XXX*/
  	case IPSEC_MODE_TRANSPORT:
  		return XFRM_MODE_TRANSPORT;
  	case IPSEC_MODE_TUNNEL:
  		return XFRM_MODE_TUNNEL;
  	case IPSEC_MODE_BEET:
  		return XFRM_MODE_BEET;
  	default:
  		return -1;
  	}
  }
183cad127   David S. Miller   xfrm: Const'ify p...
662
  static unsigned int pfkey_sockaddr_fill(const xfrm_address_t *xaddr, __be16 port,
4c93fbb06   David S. Miller   pfkey: Use const ...
663
664
  					struct sockaddr *sa,
  					unsigned short family)
e5b56652c   YOSHIFUJI Hideaki   key: Share common...
665
666
667
668
669
670
671
672
673
674
675
  {
  	switch (family) {
  	case AF_INET:
  	    {
  		struct sockaddr_in *sin = (struct sockaddr_in *)sa;
  		sin->sin_family = AF_INET;
  		sin->sin_port = port;
  		sin->sin_addr.s_addr = xaddr->a4;
  		memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
  		return 32;
  	    }
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
676
  #if IS_ENABLED(CONFIG_IPV6)
e5b56652c   YOSHIFUJI Hideaki   key: Share common...
677
678
679
680
681
682
  	case AF_INET6:
  	    {
  		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
  		sin6->sin6_family = AF_INET6;
  		sin6->sin6_port = port;
  		sin6->sin6_flowinfo = 0;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
683
  		sin6->sin6_addr = *(struct in6_addr *)xaddr->a6;
e5b56652c   YOSHIFUJI Hideaki   key: Share common...
684
685
686
687
688
689
690
  		sin6->sin6_scope_id = 0;
  		return 128;
  	    }
  #endif
  	}
  	return 0;
  }
4c93fbb06   David S. Miller   pfkey: Use const ...
691
  static struct sk_buff *__pfkey_xfrm_state2msg(const struct xfrm_state *x,
050f009e1   Herbert Xu   [IPSEC]: Lock sta...
692
  					      int add_keys, int hsc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
693
694
695
696
697
698
699
700
  {
  	struct sk_buff *skb;
  	struct sadb_msg *hdr;
  	struct sadb_sa *sa;
  	struct sadb_lifetime *lifetime;
  	struct sadb_address *addr;
  	struct sadb_key *key;
  	struct sadb_x_sa2 *sa2;
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
701
702
703
  	struct sadb_x_sec_ctx *sec_ctx;
  	struct xfrm_sec_ctx *xfrm_ctx;
  	int ctx_size = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
704
705
706
707
708
  	int size;
  	int auth_key_size = 0;
  	int encrypt_key_size = 0;
  	int sockaddr_size;
  	struct xfrm_encap_tmpl *natt = NULL;
55569ce25   Kazunori MIYAZAWA   [KEY]: Fix conver...
709
  	int mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
710
711
712
713
714
715
716
717
  
  	/* address family check */
  	sockaddr_size = pfkey_sockaddr_size(x->props.family);
  	if (!sockaddr_size)
  		return ERR_PTR(-EINVAL);
  
  	/* base, SA, (lifetime (HSC),) address(SD), (address(P),)
  	   key(AE), (identity(SD),) (sensitivity)> */
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
718
  	size = sizeof(struct sadb_msg) +sizeof(struct sadb_sa) +
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
719
720
721
  		sizeof(struct sadb_lifetime) +
  		((hsc & 1) ? sizeof(struct sadb_lifetime) : 0) +
  		((hsc & 2) ? sizeof(struct sadb_lifetime) : 0) +
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
722
  			sizeof(struct sadb_address)*2 +
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
723
724
  				sockaddr_size*2 +
  					sizeof(struct sadb_x_sa2);
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
725
726
727
728
729
  
  	if ((xfrm_ctx = x->security)) {
  		ctx_size = PFKEY_ALIGN8(xfrm_ctx->ctx_len);
  		size += sizeof(struct sadb_x_sec_ctx) + ctx_size;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730
  	/* identity & sensitivity */
81b302a32   YOSHIFUJI Hideaki   key: Use xfrm_add...
731
  	if (xfrm_addr_cmp(&x->sel.saddr, &x->props.saddr, x->props.family))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
732
733
734
735
  		size += sizeof(struct sadb_address) + sockaddr_size;
  
  	if (add_keys) {
  		if (x->aalg && x->aalg->alg_key_len) {
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
736
737
  			auth_key_size =
  				PFKEY_ALIGN8((x->aalg->alg_key_len + 7) / 8);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
738
739
740
  			size += sizeof(struct sadb_key) + auth_key_size;
  		}
  		if (x->ealg && x->ealg->alg_key_len) {
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
741
742
  			encrypt_key_size =
  				PFKEY_ALIGN8((x->ealg->alg_key_len+7) / 8);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
  			size += sizeof(struct sadb_key) + encrypt_key_size;
  		}
  	}
  	if (x->encap)
  		natt = x->encap;
  
  	if (natt && natt->encap_type) {
  		size += sizeof(struct sadb_x_nat_t_type);
  		size += sizeof(struct sadb_x_nat_t_port);
  		size += sizeof(struct sadb_x_nat_t_port);
  	}
  
  	skb =  alloc_skb(size + 16, GFP_ATOMIC);
  	if (skb == NULL)
  		return ERR_PTR(-ENOBUFS);
  
  	/* call should fill header later */
  	hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg));
  	memset(hdr, 0, size);	/* XXX do we need this ? */
  	hdr->sadb_msg_len = size / sizeof(uint64_t);
  
  	/* sa */
  	sa = (struct sadb_sa *)  skb_put(skb, sizeof(struct sadb_sa));
  	sa->sadb_sa_len = sizeof(struct sadb_sa)/sizeof(uint64_t);
  	sa->sadb_sa_exttype = SADB_EXT_SA;
  	sa->sadb_sa_spi = x->id.spi;
  	sa->sadb_sa_replay = x->props.replay_window;
4f09f0bbc   Herbert Xu   [IPSEC] Fix xfrm ...
770
771
772
773
774
775
  	switch (x->km.state) {
  	case XFRM_STATE_VALID:
  		sa->sadb_sa_state = x->km.dying ?
  			SADB_SASTATE_DYING : SADB_SASTATE_MATURE;
  		break;
  	case XFRM_STATE_ACQ:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
776
  		sa->sadb_sa_state = SADB_SASTATE_LARVAL;
4f09f0bbc   Herbert Xu   [IPSEC] Fix xfrm ...
777
778
  		break;
  	default:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
779
  		sa->sadb_sa_state = SADB_SASTATE_DEAD;
4f09f0bbc   Herbert Xu   [IPSEC] Fix xfrm ...
780
781
  		break;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
  	sa->sadb_sa_auth = 0;
  	if (x->aalg) {
  		struct xfrm_algo_desc *a = xfrm_aalg_get_byname(x->aalg->alg_name, 0);
  		sa->sadb_sa_auth = a ? a->desc.sadb_alg_id : 0;
  	}
  	sa->sadb_sa_encrypt = 0;
  	BUG_ON(x->ealg && x->calg);
  	if (x->ealg) {
  		struct xfrm_algo_desc *a = xfrm_ealg_get_byname(x->ealg->alg_name, 0);
  		sa->sadb_sa_encrypt = a ? a->desc.sadb_alg_id : 0;
  	}
  	/* KAME compatible: sadb_sa_encrypt is overloaded with calg id */
  	if (x->calg) {
  		struct xfrm_algo_desc *a = xfrm_calg_get_byname(x->calg->alg_name, 0);
  		sa->sadb_sa_encrypt = a ? a->desc.sadb_alg_id : 0;
  	}
  
  	sa->sadb_sa_flags = 0;
  	if (x->props.flags & XFRM_STATE_NOECN)
  		sa->sadb_sa_flags |= SADB_SAFLAGS_NOECN;
  	if (x->props.flags & XFRM_STATE_DECAP_DSCP)
  		sa->sadb_sa_flags |= SADB_SAFLAGS_DECAP_DSCP;
dd87147ee   Herbert Xu   [IPSEC]: Add XFRM...
804
805
  	if (x->props.flags & XFRM_STATE_NOPMTUDISC)
  		sa->sadb_sa_flags |= SADB_SAFLAGS_NOPMTUDISC;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
806
807
808
  
  	/* hard time */
  	if (hsc & 2) {
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
809
  		lifetime = (struct sadb_lifetime *)  skb_put(skb,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
810
811
812
813
814
815
816
817
818
819
820
  							     sizeof(struct sadb_lifetime));
  		lifetime->sadb_lifetime_len =
  			sizeof(struct sadb_lifetime)/sizeof(uint64_t);
  		lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD;
  		lifetime->sadb_lifetime_allocations =  _X2KEY(x->lft.hard_packet_limit);
  		lifetime->sadb_lifetime_bytes = _X2KEY(x->lft.hard_byte_limit);
  		lifetime->sadb_lifetime_addtime = x->lft.hard_add_expires_seconds;
  		lifetime->sadb_lifetime_usetime = x->lft.hard_use_expires_seconds;
  	}
  	/* soft time */
  	if (hsc & 1) {
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
821
  		lifetime = (struct sadb_lifetime *)  skb_put(skb,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
  							     sizeof(struct sadb_lifetime));
  		lifetime->sadb_lifetime_len =
  			sizeof(struct sadb_lifetime)/sizeof(uint64_t);
  		lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT;
  		lifetime->sadb_lifetime_allocations =  _X2KEY(x->lft.soft_packet_limit);
  		lifetime->sadb_lifetime_bytes = _X2KEY(x->lft.soft_byte_limit);
  		lifetime->sadb_lifetime_addtime = x->lft.soft_add_expires_seconds;
  		lifetime->sadb_lifetime_usetime = x->lft.soft_use_expires_seconds;
  	}
  	/* current time */
  	lifetime = (struct sadb_lifetime *)  skb_put(skb,
  						     sizeof(struct sadb_lifetime));
  	lifetime->sadb_lifetime_len =
  		sizeof(struct sadb_lifetime)/sizeof(uint64_t);
  	lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT;
  	lifetime->sadb_lifetime_allocations = x->curlft.packets;
  	lifetime->sadb_lifetime_bytes = x->curlft.bytes;
  	lifetime->sadb_lifetime_addtime = x->curlft.add_time;
  	lifetime->sadb_lifetime_usetime = x->curlft.use_time;
  	/* src address */
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
842
  	addr = (struct sadb_address*) skb_put(skb,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
843
  					      sizeof(struct sadb_address)+sockaddr_size);
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
844
  	addr->sadb_address_len =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
845
846
847
  		(sizeof(struct sadb_address)+sockaddr_size)/
  			sizeof(uint64_t);
  	addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
848
849
  	/* "if the ports are non-zero, then the sadb_address_proto field,
  	   normally zero, MUST be filled in with the transport
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
850
  	   protocol's number." - RFC2367 */
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
851
  	addr->sadb_address_proto = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
852
  	addr->sadb_address_reserved = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
853

e5b56652c   YOSHIFUJI Hideaki   key: Share common...
854
855
856
857
858
  	addr->sadb_address_prefixlen =
  		pfkey_sockaddr_fill(&x->props.saddr, 0,
  				    (struct sockaddr *) (addr + 1),
  				    x->props.family);
  	if (!addr->sadb_address_prefixlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
859
860
861
  		BUG();
  
  	/* dst address */
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
862
  	addr = (struct sadb_address*) skb_put(skb,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
863
  					      sizeof(struct sadb_address)+sockaddr_size);
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
864
  	addr->sadb_address_len =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
865
866
867
  		(sizeof(struct sadb_address)+sockaddr_size)/
  			sizeof(uint64_t);
  	addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
868
  	addr->sadb_address_proto = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
869
  	addr->sadb_address_reserved = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
870

e5b56652c   YOSHIFUJI Hideaki   key: Share common...
871
872
873
874
875
876
  	addr->sadb_address_prefixlen =
  		pfkey_sockaddr_fill(&x->id.daddr, 0,
  				    (struct sockaddr *) (addr + 1),
  				    x->props.family);
  	if (!addr->sadb_address_prefixlen)
  		BUG();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
877

e5b56652c   YOSHIFUJI Hideaki   key: Share common...
878
879
880
881
882
883
884
885
886
887
888
889
  	if (xfrm_addr_cmp(&x->sel.saddr, &x->props.saddr,
  			  x->props.family)) {
  		addr = (struct sadb_address*) skb_put(skb,
  			sizeof(struct sadb_address)+sockaddr_size);
  		addr->sadb_address_len =
  			(sizeof(struct sadb_address)+sockaddr_size)/
  			sizeof(uint64_t);
  		addr->sadb_address_exttype = SADB_EXT_ADDRESS_PROXY;
  		addr->sadb_address_proto =
  			pfkey_proto_from_xfrm(x->sel.proto);
  		addr->sadb_address_prefixlen = x->sel.prefixlen_s;
  		addr->sadb_address_reserved = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
890

e5b56652c   YOSHIFUJI Hideaki   key: Share common...
891
892
893
  		pfkey_sockaddr_fill(&x->sel.saddr, x->sel.sport,
  				    (struct sockaddr *) (addr + 1),
  				    x->props.family);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
894
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
895
896
897
  
  	/* auth key */
  	if (add_keys && auth_key_size) {
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
898
  		key = (struct sadb_key *) skb_put(skb,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
899
900
901
902
903
904
905
906
907
908
  						  sizeof(struct sadb_key)+auth_key_size);
  		key->sadb_key_len = (sizeof(struct sadb_key) + auth_key_size) /
  			sizeof(uint64_t);
  		key->sadb_key_exttype = SADB_EXT_KEY_AUTH;
  		key->sadb_key_bits = x->aalg->alg_key_len;
  		key->sadb_key_reserved = 0;
  		memcpy(key + 1, x->aalg->alg_key, (x->aalg->alg_key_len+7)/8);
  	}
  	/* encrypt key */
  	if (add_keys && encrypt_key_size) {
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
909
  		key = (struct sadb_key *) skb_put(skb,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
910
  						  sizeof(struct sadb_key)+encrypt_key_size);
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
911
  		key->sadb_key_len = (sizeof(struct sadb_key) +
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
912
913
914
915
  				     encrypt_key_size) / sizeof(uint64_t);
  		key->sadb_key_exttype = SADB_EXT_KEY_ENCRYPT;
  		key->sadb_key_bits = x->ealg->alg_key_len;
  		key->sadb_key_reserved = 0;
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
916
  		memcpy(key + 1, x->ealg->alg_key,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
917
918
919
920
921
922
923
  		       (x->ealg->alg_key_len+7)/8);
  	}
  
  	/* sa */
  	sa2 = (struct sadb_x_sa2 *)  skb_put(skb, sizeof(struct sadb_x_sa2));
  	sa2->sadb_x_sa2_len = sizeof(struct sadb_x_sa2)/sizeof(uint64_t);
  	sa2->sadb_x_sa2_exttype = SADB_X_EXT_SA2;
55569ce25   Kazunori MIYAZAWA   [KEY]: Fix conver...
924
925
926
927
928
  	if ((mode = pfkey_mode_from_xfrm(x->props.mode)) < 0) {
  		kfree_skb(skb);
  		return ERR_PTR(-EINVAL);
  	}
  	sa2->sadb_x_sa2_mode = mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
  	sa2->sadb_x_sa2_reserved1 = 0;
  	sa2->sadb_x_sa2_reserved2 = 0;
  	sa2->sadb_x_sa2_sequence = 0;
  	sa2->sadb_x_sa2_reqid = x->props.reqid;
  
  	if (natt && natt->encap_type) {
  		struct sadb_x_nat_t_type *n_type;
  		struct sadb_x_nat_t_port *n_port;
  
  		/* type */
  		n_type = (struct sadb_x_nat_t_type*) skb_put(skb, sizeof(*n_type));
  		n_type->sadb_x_nat_t_type_len = sizeof(*n_type)/sizeof(uint64_t);
  		n_type->sadb_x_nat_t_type_exttype = SADB_X_EXT_NAT_T_TYPE;
  		n_type->sadb_x_nat_t_type_type = natt->encap_type;
  		n_type->sadb_x_nat_t_type_reserved[0] = 0;
  		n_type->sadb_x_nat_t_type_reserved[1] = 0;
  		n_type->sadb_x_nat_t_type_reserved[2] = 0;
  
  		/* source port */
  		n_port = (struct sadb_x_nat_t_port*) skb_put(skb, sizeof (*n_port));
  		n_port->sadb_x_nat_t_port_len = sizeof(*n_port)/sizeof(uint64_t);
  		n_port->sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_SPORT;
  		n_port->sadb_x_nat_t_port_port = natt->encap_sport;
  		n_port->sadb_x_nat_t_port_reserved = 0;
  
  		/* dest port */
  		n_port = (struct sadb_x_nat_t_port*) skb_put(skb, sizeof (*n_port));
  		n_port->sadb_x_nat_t_port_len = sizeof(*n_port)/sizeof(uint64_t);
  		n_port->sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_DPORT;
  		n_port->sadb_x_nat_t_port_port = natt->encap_dport;
  		n_port->sadb_x_nat_t_port_reserved = 0;
  	}
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
961
962
963
964
965
966
967
968
969
970
971
972
973
  	/* security context */
  	if (xfrm_ctx) {
  		sec_ctx = (struct sadb_x_sec_ctx *) skb_put(skb,
  				sizeof(struct sadb_x_sec_ctx) + ctx_size);
  		sec_ctx->sadb_x_sec_len =
  		  (sizeof(struct sadb_x_sec_ctx) + ctx_size) / sizeof(uint64_t);
  		sec_ctx->sadb_x_sec_exttype = SADB_X_EXT_SEC_CTX;
  		sec_ctx->sadb_x_ctx_doi = xfrm_ctx->ctx_doi;
  		sec_ctx->sadb_x_ctx_alg = xfrm_ctx->ctx_alg;
  		sec_ctx->sadb_x_ctx_len = xfrm_ctx->ctx_len;
  		memcpy(sec_ctx + 1, xfrm_ctx->ctx_str,
  		       xfrm_ctx->ctx_len);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
974
975
  	return skb;
  }
050f009e1   Herbert Xu   [IPSEC]: Lock sta...
976

4c93fbb06   David S. Miller   pfkey: Use const ...
977
  static inline struct sk_buff *pfkey_xfrm_state2msg(const struct xfrm_state *x)
050f009e1   Herbert Xu   [IPSEC]: Lock sta...
978
979
  {
  	struct sk_buff *skb;
050f009e1   Herbert Xu   [IPSEC]: Lock sta...
980
  	skb = __pfkey_xfrm_state2msg(x, 1, 3);
050f009e1   Herbert Xu   [IPSEC]: Lock sta...
981
982
983
  
  	return skb;
  }
4c93fbb06   David S. Miller   pfkey: Use const ...
984
  static inline struct sk_buff *pfkey_xfrm_state2msg_expire(const struct xfrm_state *x,
050f009e1   Herbert Xu   [IPSEC]: Lock sta...
985
986
987
988
  							  int hsc)
  {
  	return __pfkey_xfrm_state2msg(x, 0, hsc);
  }
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
989
  static struct xfrm_state * pfkey_msg2xfrm_state(struct net *net,
4c93fbb06   David S. Miller   pfkey: Use const ...
990
991
  						const struct sadb_msg *hdr,
  						void * const *ext_hdrs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
992
  {
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
993
  	struct xfrm_state *x;
4c93fbb06   David S. Miller   pfkey: Use const ...
994
995
996
997
  	const struct sadb_lifetime *lifetime;
  	const struct sadb_sa *sa;
  	const struct sadb_key *key;
  	const struct sadb_x_sec_ctx *sec_ctx;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
998
999
  	uint16_t proto;
  	int err;
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
1000

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1001

ea1107338   Joe Perches   net: Remove casts...
1002
  	sa = ext_hdrs[SADB_EXT_SA - 1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
  	if (!sa ||
  	    !present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1],
  				     ext_hdrs[SADB_EXT_ADDRESS_DST-1]))
  		return ERR_PTR(-EINVAL);
  	if (hdr->sadb_msg_satype == SADB_SATYPE_ESP &&
  	    !ext_hdrs[SADB_EXT_KEY_ENCRYPT-1])
  		return ERR_PTR(-EINVAL);
  	if (hdr->sadb_msg_satype == SADB_SATYPE_AH &&
  	    !ext_hdrs[SADB_EXT_KEY_AUTH-1])
  		return ERR_PTR(-EINVAL);
  	if (!!ext_hdrs[SADB_EXT_LIFETIME_HARD-1] !=
  	    !!ext_hdrs[SADB_EXT_LIFETIME_SOFT-1])
  		return ERR_PTR(-EINVAL);
  
  	proto = pfkey_satype2proto(hdr->sadb_msg_satype);
  	if (proto == 0)
  		return ERR_PTR(-EINVAL);
  
  	/* default error is no buffer space */
  	err = -ENOBUFS;
  
  	/* RFC2367:
  
     Only SADB_SASTATE_MATURE SAs may be submitted in an SADB_ADD message.
     SADB_SASTATE_LARVAL SAs are created by SADB_GETSPI and it is not
     sensible to add a new SA in the DYING or SADB_SASTATE_DEAD state.
     Therefore, the sadb_sa_state field of all submitted SAs MUST be
     SADB_SASTATE_MATURE and the kernel MUST return an error if this is
     not true.
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
1032
  	   However, KAME setkey always uses SADB_SASTATE_LARVAL.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1033
1034
1035
1036
1037
1038
1039
  	   Hence, we have to _ignore_ sadb_sa_state, which is also reasonable.
  	 */
  	if (sa->sadb_sa_auth > SADB_AALG_MAX ||
  	    (hdr->sadb_msg_satype == SADB_X_SATYPE_IPCOMP &&
  	     sa->sadb_sa_encrypt > SADB_X_CALG_MAX) ||
  	    sa->sadb_sa_encrypt > SADB_EALG_MAX)
  		return ERR_PTR(-EINVAL);
ea1107338   Joe Perches   net: Remove casts...
1040
  	key = ext_hdrs[SADB_EXT_KEY_AUTH - 1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
  	if (key != NULL &&
  	    sa->sadb_sa_auth != SADB_X_AALG_NULL &&
  	    ((key->sadb_key_bits+7) / 8 == 0 ||
  	     (key->sadb_key_bits+7) / 8 > key->sadb_key_len * sizeof(uint64_t)))
  		return ERR_PTR(-EINVAL);
  	key = ext_hdrs[SADB_EXT_KEY_ENCRYPT-1];
  	if (key != NULL &&
  	    sa->sadb_sa_encrypt != SADB_EALG_NULL &&
  	    ((key->sadb_key_bits+7) / 8 == 0 ||
  	     (key->sadb_key_bits+7) / 8 > key->sadb_key_len * sizeof(uint64_t)))
  		return ERR_PTR(-EINVAL);
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
1052
  	x = xfrm_state_alloc(net);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
  	if (x == NULL)
  		return ERR_PTR(-ENOBUFS);
  
  	x->id.proto = proto;
  	x->id.spi = sa->sadb_sa_spi;
  	x->props.replay_window = sa->sadb_sa_replay;
  	if (sa->sadb_sa_flags & SADB_SAFLAGS_NOECN)
  		x->props.flags |= XFRM_STATE_NOECN;
  	if (sa->sadb_sa_flags & SADB_SAFLAGS_DECAP_DSCP)
  		x->props.flags |= XFRM_STATE_DECAP_DSCP;
dd87147ee   Herbert Xu   [IPSEC]: Add XFRM...
1063
1064
  	if (sa->sadb_sa_flags & SADB_SAFLAGS_NOPMTUDISC)
  		x->props.flags |= XFRM_STATE_NOPMTUDISC;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1065

ea1107338   Joe Perches   net: Remove casts...
1066
  	lifetime = ext_hdrs[SADB_EXT_LIFETIME_HARD - 1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1067
1068
1069
1070
1071
1072
  	if (lifetime != NULL) {
  		x->lft.hard_packet_limit = _KEY2X(lifetime->sadb_lifetime_allocations);
  		x->lft.hard_byte_limit = _KEY2X(lifetime->sadb_lifetime_bytes);
  		x->lft.hard_add_expires_seconds = lifetime->sadb_lifetime_addtime;
  		x->lft.hard_use_expires_seconds = lifetime->sadb_lifetime_usetime;
  	}
ea1107338   Joe Perches   net: Remove casts...
1073
  	lifetime = ext_hdrs[SADB_EXT_LIFETIME_SOFT - 1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1074
1075
1076
1077
1078
1079
  	if (lifetime != NULL) {
  		x->lft.soft_packet_limit = _KEY2X(lifetime->sadb_lifetime_allocations);
  		x->lft.soft_byte_limit = _KEY2X(lifetime->sadb_lifetime_bytes);
  		x->lft.soft_add_expires_seconds = lifetime->sadb_lifetime_addtime;
  		x->lft.soft_use_expires_seconds = lifetime->sadb_lifetime_usetime;
  	}
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
1080

ea1107338   Joe Perches   net: Remove casts...
1081
  	sec_ctx = ext_hdrs[SADB_X_EXT_SEC_CTX - 1];
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
  	if (sec_ctx != NULL) {
  		struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx);
  
  		if (!uctx)
  			goto out;
  
  		err = security_xfrm_state_alloc(x, uctx);
  		kfree(uctx);
  
  		if (err)
  			goto out;
  	}
ea1107338   Joe Perches   net: Remove casts...
1094
  	key = ext_hdrs[SADB_EXT_KEY_AUTH - 1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
  	if (sa->sadb_sa_auth) {
  		int keysize = 0;
  		struct xfrm_algo_desc *a = xfrm_aalg_get_byid(sa->sadb_sa_auth);
  		if (!a) {
  			err = -ENOSYS;
  			goto out;
  		}
  		if (key)
  			keysize = (key->sadb_key_bits + 7) / 8;
  		x->aalg = kmalloc(sizeof(*x->aalg) + keysize, GFP_KERNEL);
  		if (!x->aalg)
  			goto out;
  		strcpy(x->aalg->alg_name, a->name);
  		x->aalg->alg_key_len = 0;
  		if (key) {
  			x->aalg->alg_key_len = key->sadb_key_bits;
  			memcpy(x->aalg->alg_key, key+1, keysize);
  		}
c20a66f47   Martin Willi   xfrm: Fix truncat...
1113
  		x->aalg->alg_trunc_len = a->uinfo.auth.icv_truncbits;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
  		x->props.aalgo = sa->sadb_sa_auth;
  		/* x->algo.flags = sa->sadb_sa_flags; */
  	}
  	if (sa->sadb_sa_encrypt) {
  		if (hdr->sadb_msg_satype == SADB_X_SATYPE_IPCOMP) {
  			struct xfrm_algo_desc *a = xfrm_calg_get_byid(sa->sadb_sa_encrypt);
  			if (!a) {
  				err = -ENOSYS;
  				goto out;
  			}
  			x->calg = kmalloc(sizeof(*x->calg), GFP_KERNEL);
  			if (!x->calg)
  				goto out;
  			strcpy(x->calg->alg_name, a->name);
  			x->props.calgo = sa->sadb_sa_encrypt;
  		} else {
  			int keysize = 0;
  			struct xfrm_algo_desc *a = xfrm_ealg_get_byid(sa->sadb_sa_encrypt);
  			if (!a) {
  				err = -ENOSYS;
  				goto out;
  			}
  			key = (struct sadb_key*) ext_hdrs[SADB_EXT_KEY_ENCRYPT-1];
  			if (key)
  				keysize = (key->sadb_key_bits + 7) / 8;
  			x->ealg = kmalloc(sizeof(*x->ealg) + keysize, GFP_KERNEL);
  			if (!x->ealg)
  				goto out;
  			strcpy(x->ealg->alg_name, a->name);
  			x->ealg->alg_key_len = 0;
  			if (key) {
  				x->ealg->alg_key_len = key->sadb_key_bits;
  				memcpy(x->ealg->alg_key, key+1, keysize);
  			}
  			x->props.ealgo = sa->sadb_sa_encrypt;
  		}
  	}
  	/* x->algo.flags = sa->sadb_sa_flags; */
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
1152
  	x->props.family = pfkey_sadb_addr2xfrm_addr((struct sadb_address *) ext_hdrs[SADB_EXT_ADDRESS_SRC-1],
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1153
1154
1155
1156
1157
  						    &x->props.saddr);
  	if (!x->props.family) {
  		err = -EAFNOSUPPORT;
  		goto out;
  	}
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
1158
  	pfkey_sadb_addr2xfrm_addr((struct sadb_address *) ext_hdrs[SADB_EXT_ADDRESS_DST-1],
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1159
1160
1161
  				  &x->id.daddr);
  
  	if (ext_hdrs[SADB_X_EXT_SA2-1]) {
4c93fbb06   David S. Miller   pfkey: Use const ...
1162
  		const struct sadb_x_sa2 *sa2 = ext_hdrs[SADB_X_EXT_SA2-1];
55569ce25   Kazunori MIYAZAWA   [KEY]: Fix conver...
1163
1164
1165
1166
1167
1168
  		int mode = pfkey_mode_to_xfrm(sa2->sadb_x_sa2_mode);
  		if (mode < 0) {
  			err = -EINVAL;
  			goto out;
  		}
  		x->props.mode = mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1169
1170
1171
1172
  		x->props.reqid = sa2->sadb_x_sa2_reqid;
  	}
  
  	if (ext_hdrs[SADB_EXT_ADDRESS_PROXY-1]) {
4c93fbb06   David S. Miller   pfkey: Use const ...
1173
  		const struct sadb_address *addr = ext_hdrs[SADB_EXT_ADDRESS_PROXY-1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1174
1175
1176
1177
1178
  
  		/* Nobody uses this, but we try. */
  		x->sel.family = pfkey_sadb_addr2xfrm_addr(addr, &x->sel.saddr);
  		x->sel.prefixlen_s = addr->sadb_address_prefixlen;
  	}
4da510568   Kazunori MIYAZAWA   af_key: Fix selec...
1179
  	if (!x->sel.family)
4a4b6271a   Joy Latten   [PF_KEY]: Fix ips...
1180
  		x->sel.family = x->props.family;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1181
  	if (ext_hdrs[SADB_X_EXT_NAT_T_TYPE-1]) {
4c93fbb06   David S. Miller   pfkey: Use const ...
1182
  		const struct sadb_x_nat_t_type* n_type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
  		struct xfrm_encap_tmpl *natt;
  
  		x->encap = kmalloc(sizeof(*x->encap), GFP_KERNEL);
  		if (!x->encap)
  			goto out;
  
  		natt = x->encap;
  		n_type = ext_hdrs[SADB_X_EXT_NAT_T_TYPE-1];
  		natt->encap_type = n_type->sadb_x_nat_t_type_type;
  
  		if (ext_hdrs[SADB_X_EXT_NAT_T_SPORT-1]) {
4c93fbb06   David S. Miller   pfkey: Use const ...
1194
  			const struct sadb_x_nat_t_port *n_port =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1195
1196
1197
1198
  				ext_hdrs[SADB_X_EXT_NAT_T_SPORT-1];
  			natt->encap_sport = n_port->sadb_x_nat_t_port_port;
  		}
  		if (ext_hdrs[SADB_X_EXT_NAT_T_DPORT-1]) {
4c93fbb06   David S. Miller   pfkey: Use const ...
1199
  			const struct sadb_x_nat_t_port *n_port =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1200
1201
1202
  				ext_hdrs[SADB_X_EXT_NAT_T_DPORT-1];
  			natt->encap_dport = n_port->sadb_x_nat_t_port_port;
  		}
a8d694c65   Timo Teras   af_key: initializ...
1203
  		memset(&natt->encap_oa, 0, sizeof(natt->encap_oa));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1204
  	}
72cb6962a   Herbert Xu   [IPSEC]: Add xfrm...
1205
1206
  	err = xfrm_init_state(x);
  	if (err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1207
  		goto out;
72cb6962a   Herbert Xu   [IPSEC]: Add xfrm...
1208

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1209
  	x->km.seq = hdr->sadb_msg_seq;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1210
1211
1212
1213
1214
1215
1216
  	return x;
  
  out:
  	x->km.state = XFRM_STATE_DEAD;
  	xfrm_state_put(x);
  	return ERR_PTR(err);
  }
4c93fbb06   David S. Miller   pfkey: Use const ...
1217
  static int pfkey_reserved(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1218
1219
1220
  {
  	return -EOPNOTSUPP;
  }
4c93fbb06   David S. Miller   pfkey: Use const ...
1221
  static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1222
  {
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
1223
  	struct net *net = sock_net(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1224
1225
1226
1227
  	struct sk_buff *resp_skb;
  	struct sadb_x_sa2 *sa2;
  	struct sadb_address *saddr, *daddr;
  	struct sadb_msg *out_hdr;
658b219e9   Herbert Xu   [IPSEC]: Move com...
1228
  	struct sadb_spirange *range;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1229
  	struct xfrm_state *x = NULL;
55569ce25   Kazunori MIYAZAWA   [KEY]: Fix conver...
1230
  	int mode;
658b219e9   Herbert Xu   [IPSEC]: Move com...
1231
1232
  	int err;
  	u32 min_spi, max_spi;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
  	u32 reqid;
  	u8 proto;
  	unsigned short family;
  	xfrm_address_t *xsaddr = NULL, *xdaddr = NULL;
  
  	if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1],
  				     ext_hdrs[SADB_EXT_ADDRESS_DST-1]))
  		return -EINVAL;
  
  	proto = pfkey_satype2proto(hdr->sadb_msg_satype);
  	if (proto == 0)
  		return -EINVAL;
  
  	if ((sa2 = ext_hdrs[SADB_X_EXT_SA2-1]) != NULL) {
55569ce25   Kazunori MIYAZAWA   [KEY]: Fix conver...
1247
1248
1249
  		mode = pfkey_mode_to_xfrm(sa2->sadb_x_sa2_mode);
  		if (mode < 0)
  			return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
  		reqid = sa2->sadb_x_sa2_reqid;
  	} else {
  		mode = 0;
  		reqid = 0;
  	}
  
  	saddr = ext_hdrs[SADB_EXT_ADDRESS_SRC-1];
  	daddr = ext_hdrs[SADB_EXT_ADDRESS_DST-1];
  
  	family = ((struct sockaddr *)(saddr + 1))->sa_family;
  	switch (family) {
  	case AF_INET:
  		xdaddr = (xfrm_address_t *)&((struct sockaddr_in *)(daddr + 1))->sin_addr.s_addr;
  		xsaddr = (xfrm_address_t *)&((struct sockaddr_in *)(saddr + 1))->sin_addr.s_addr;
  		break;
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
1265
  #if IS_ENABLED(CONFIG_IPV6)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1266
1267
1268
1269
1270
1271
1272
1273
  	case AF_INET6:
  		xdaddr = (xfrm_address_t *)&((struct sockaddr_in6 *)(daddr + 1))->sin6_addr;
  		xsaddr = (xfrm_address_t *)&((struct sockaddr_in6 *)(saddr + 1))->sin6_addr;
  		break;
  #endif
  	}
  
  	if (hdr->sadb_msg_seq) {
bd55775c8   Jamal Hadi Salim   xfrm: SA lookups ...
1274
  		x = xfrm_find_acq_byseq(net, DUMMY_MARK, hdr->sadb_msg_seq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1275
1276
1277
1278
1279
1280
1281
  		if (x && xfrm_addr_cmp(&x->id.daddr, xdaddr, family)) {
  			xfrm_state_put(x);
  			x = NULL;
  		}
  	}
  
  	if (!x)
bd55775c8   Jamal Hadi Salim   xfrm: SA lookups ...
1282
  		x = xfrm_find_acq(net, &dummy_mark, mode, reqid, proto, xdaddr, xsaddr, 1, family);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1283
1284
1285
  
  	if (x == NULL)
  		return -ENOENT;
658b219e9   Herbert Xu   [IPSEC]: Move com...
1286
1287
  	min_spi = 0x100;
  	max_spi = 0x0fffffff;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1288

658b219e9   Herbert Xu   [IPSEC]: Move com...
1289
1290
1291
1292
  	range = ext_hdrs[SADB_EXT_SPIRANGE-1];
  	if (range) {
  		min_spi = range->sadb_spirange_min;
  		max_spi = range->sadb_spirange_max;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1293
  	}
658b219e9   Herbert Xu   [IPSEC]: Move com...
1294
1295
  
  	err = xfrm_alloc_spi(x, min_spi, max_spi);
050f009e1   Herbert Xu   [IPSEC]: Lock sta...
1296
  	resp_skb = err ? ERR_PTR(err) : pfkey_xfrm_state2msg(x);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
  
  	if (IS_ERR(resp_skb)) {
  		xfrm_state_put(x);
  		return  PTR_ERR(resp_skb);
  	}
  
  	out_hdr = (struct sadb_msg *) resp_skb->data;
  	out_hdr->sadb_msg_version = hdr->sadb_msg_version;
  	out_hdr->sadb_msg_type = SADB_GETSPI;
  	out_hdr->sadb_msg_satype = pfkey_proto2satype(proto);
  	out_hdr->sadb_msg_errno = 0;
  	out_hdr->sadb_msg_reserved = 0;
  	out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
  	out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
  
  	xfrm_state_put(x);
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
1313
  	pfkey_broadcast(resp_skb, GFP_KERNEL, BROADCAST_ONE, sk, net);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1314
1315
1316
  
  	return 0;
  }
4c93fbb06   David S. Miller   pfkey: Use const ...
1317
  static int pfkey_acquire(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1318
  {
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
1319
  	struct net *net = sock_net(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1320
1321
1322
1323
1324
1325
1326
  	struct xfrm_state *x;
  
  	if (hdr->sadb_msg_len != sizeof(struct sadb_msg)/8)
  		return -EOPNOTSUPP;
  
  	if (hdr->sadb_msg_seq == 0 || hdr->sadb_msg_errno == 0)
  		return 0;
bd55775c8   Jamal Hadi Salim   xfrm: SA lookups ...
1327
  	x = xfrm_find_acq_byseq(net, DUMMY_MARK, hdr->sadb_msg_seq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1328
1329
1330
1331
1332
1333
  	if (x == NULL)
  		return 0;
  
  	spin_lock_bh(&x->lock);
  	if (x->km.state == XFRM_STATE_ACQ) {
  		x->km.state = XFRM_STATE_ERROR;
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
1334
  		wake_up(&net->xfrm.km_waitq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1335
1336
1337
1338
1339
  	}
  	spin_unlock_bh(&x->lock);
  	xfrm_state_put(x);
  	return 0;
  }
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1340
1341
1342
  static inline int event2poltype(int event)
  {
  	switch (event) {
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
1343
  	case XFRM_MSG_DELPOLICY:
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1344
  		return SADB_X_SPDDELETE;
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
1345
  	case XFRM_MSG_NEWPOLICY:
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1346
  		return SADB_X_SPDADD;
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
1347
  	case XFRM_MSG_UPDPOLICY:
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1348
  		return SADB_X_SPDUPDATE;
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
1349
  	case XFRM_MSG_POLEXPIRE:
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1350
1351
  	//	return SADB_X_SPDEXPIRE;
  	default:
207024b94   stephen hemminger   pfkey: add severi...
1352
1353
  		pr_err("pfkey: Unknown policy event %d
  ", event);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1354
1355
1356
1357
1358
1359
1360
1361
1362
  		break;
  	}
  
  	return 0;
  }
  
  static inline int event2keytype(int event)
  {
  	switch (event) {
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
1363
  	case XFRM_MSG_DELSA:
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1364
  		return SADB_DELETE;
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
1365
  	case XFRM_MSG_NEWSA:
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1366
  		return SADB_ADD;
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
1367
  	case XFRM_MSG_UPDSA:
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1368
  		return SADB_UPDATE;
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
1369
  	case XFRM_MSG_EXPIRE:
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1370
1371
  		return SADB_EXPIRE;
  	default:
207024b94   stephen hemminger   pfkey: add severi...
1372
1373
  		pr_err("pfkey: Unknown SA event %d
  ", event);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1374
1375
1376
1377
1378
1379
1380
  		break;
  	}
  
  	return 0;
  }
  
  /* ADD/UPD/DEL */
214e005bc   David S. Miller   xfrm: Pass km_eve...
1381
  static int key_notify_sa(struct xfrm_state *x, const struct km_event *c)
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1382
1383
1384
  {
  	struct sk_buff *skb;
  	struct sadb_msg *hdr;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1385

050f009e1   Herbert Xu   [IPSEC]: Lock sta...
1386
  	skb = pfkey_xfrm_state2msg(x);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
  
  	if (IS_ERR(skb))
  		return PTR_ERR(skb);
  
  	hdr = (struct sadb_msg *) skb->data;
  	hdr->sadb_msg_version = PF_KEY_V2;
  	hdr->sadb_msg_type = event2keytype(c->event);
  	hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto);
  	hdr->sadb_msg_errno = 0;
  	hdr->sadb_msg_reserved = 0;
  	hdr->sadb_msg_seq = c->seq;
  	hdr->sadb_msg_pid = c->pid;
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
1399
  	pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL, xs_net(x));
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1400
1401
1402
  
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1403

4c93fbb06   David S. Miller   pfkey: Use const ...
1404
  static int pfkey_add(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1405
  {
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
1406
  	struct net *net = sock_net(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1407
1408
  	struct xfrm_state *x;
  	int err;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1409
  	struct km_event c;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1410

07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
1411
  	x = pfkey_msg2xfrm_state(net, hdr, ext_hdrs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1412
1413
  	if (IS_ERR(x))
  		return PTR_ERR(x);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1414
  	xfrm_state_hold(x);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1415
1416
1417
1418
  	if (hdr->sadb_msg_type == SADB_ADD)
  		err = xfrm_state_add(x);
  	else
  		err = xfrm_state_update(x);
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
1419
  	xfrm_audit_state_add(x, err ? 0 : 1,
2532386f4   Eric Paris   Audit: collect se...
1420
1421
  			     audit_get_loginuid(current),
  			     audit_get_sessionid(current), 0);
161a09e73   Joy Latten   audit: Add auditi...
1422

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1423
1424
  	if (err < 0) {
  		x->km.state = XFRM_STATE_DEAD;
21380b81e   Herbert Xu   [XFRM]: Eliminate...
1425
  		__xfrm_state_put(x);
7d6dfe1f5   Patrick McHardy   [IPSEC] Fix xfrm_...
1426
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1427
  	}
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1428
  	if (hdr->sadb_msg_type == SADB_ADD)
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
1429
  		c.event = XFRM_MSG_NEWSA;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1430
  	else
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
1431
  		c.event = XFRM_MSG_UPDSA;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1432
1433
1434
  	c.seq = hdr->sadb_msg_seq;
  	c.pid = hdr->sadb_msg_pid;
  	km_state_notify(x, &c);
7d6dfe1f5   Patrick McHardy   [IPSEC] Fix xfrm_...
1435
  out:
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1436
  	xfrm_state_put(x);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1437
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1438
  }
4c93fbb06   David S. Miller   pfkey: Use const ...
1439
  static int pfkey_delete(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1440
  {
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
1441
  	struct net *net = sock_net(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1442
  	struct xfrm_state *x;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1443
1444
  	struct km_event c;
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1445
1446
1447
1448
1449
  
  	if (!ext_hdrs[SADB_EXT_SA-1] ||
  	    !present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1],
  				     ext_hdrs[SADB_EXT_ADDRESS_DST-1]))
  		return -EINVAL;
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
1450
  	x = pfkey_xfrm_state_lookup(net, hdr, ext_hdrs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1451
1452
  	if (x == NULL)
  		return -ESRCH;
c8c05a8ee   Catherine Zhang   [LSM-IPsec]: SELi...
1453
1454
  	if ((err = security_xfrm_state_delete(x)))
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1455
  	if (xfrm_state_kern(x)) {
c8c05a8ee   Catherine Zhang   [LSM-IPsec]: SELi...
1456
1457
  		err = -EPERM;
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1458
  	}
161a09e73   Joy Latten   audit: Add auditi...
1459

26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1460
  	err = xfrm_state_delete(x);
161a09e73   Joy Latten   audit: Add auditi...
1461

c8c05a8ee   Catherine Zhang   [LSM-IPsec]: SELi...
1462
1463
  	if (err < 0)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1464

26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1465
1466
  	c.seq = hdr->sadb_msg_seq;
  	c.pid = hdr->sadb_msg_pid;
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
1467
  	c.event = XFRM_MSG_DELSA;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1468
  	km_state_notify(x, &c);
c8c05a8ee   Catherine Zhang   [LSM-IPsec]: SELi...
1469
  out:
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
1470
  	xfrm_audit_state_delete(x, err ? 0 : 1,
2532386f4   Eric Paris   Audit: collect se...
1471
1472
  				audit_get_loginuid(current),
  				audit_get_sessionid(current), 0);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1473
  	xfrm_state_put(x);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1474

26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1475
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1476
  }
4c93fbb06   David S. Miller   pfkey: Use const ...
1477
  static int pfkey_get(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1478
  {
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
1479
  	struct net *net = sock_net(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1480
1481
1482
1483
1484
1485
1486
1487
1488
  	__u8 proto;
  	struct sk_buff *out_skb;
  	struct sadb_msg *out_hdr;
  	struct xfrm_state *x;
  
  	if (!ext_hdrs[SADB_EXT_SA-1] ||
  	    !present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1],
  				     ext_hdrs[SADB_EXT_ADDRESS_DST-1]))
  		return -EINVAL;
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
1489
  	x = pfkey_xfrm_state_lookup(net, hdr, ext_hdrs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1490
1491
  	if (x == NULL)
  		return -ESRCH;
050f009e1   Herbert Xu   [IPSEC]: Lock sta...
1492
  	out_skb = pfkey_xfrm_state2msg(x);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1493
1494
1495
1496
1497
1498
1499
  	proto = x->id.proto;
  	xfrm_state_put(x);
  	if (IS_ERR(out_skb))
  		return  PTR_ERR(out_skb);
  
  	out_hdr = (struct sadb_msg *) out_skb->data;
  	out_hdr->sadb_msg_version = hdr->sadb_msg_version;
435000beb   Charles Hardin   [PFKEY]: Sending ...
1500
  	out_hdr->sadb_msg_type = SADB_GET;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1501
1502
1503
1504
1505
  	out_hdr->sadb_msg_satype = pfkey_proto2satype(proto);
  	out_hdr->sadb_msg_errno = 0;
  	out_hdr->sadb_msg_reserved = 0;
  	out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
  	out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
1506
  	pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, sk, sock_net(sk));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1507
1508
1509
  
  	return 0;
  }
4c93fbb06   David S. Miller   pfkey: Use const ...
1510
  static struct sk_buff *compose_sadb_supported(const struct sadb_msg *orig,
dd0fc66fb   Al Viro   [PATCH] gfp flags...
1511
  					      gfp_t allocation)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
  {
  	struct sk_buff *skb;
  	struct sadb_msg *hdr;
  	int len, auth_len, enc_len, i;
  
  	auth_len = xfrm_count_auth_supported();
  	if (auth_len) {
  		auth_len *= sizeof(struct sadb_alg);
  		auth_len += sizeof(struct sadb_supported);
  	}
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
1522

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1523
1524
1525
1526
1527
  	enc_len = xfrm_count_enc_supported();
  	if (enc_len) {
  		enc_len *= sizeof(struct sadb_alg);
  		enc_len += sizeof(struct sadb_supported);
  	}
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
1528

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
  	len = enc_len + auth_len + sizeof(struct sadb_msg);
  
  	skb = alloc_skb(len + 16, allocation);
  	if (!skb)
  		goto out_put_algs;
  
  	hdr = (struct sadb_msg *) skb_put(skb, sizeof(*hdr));
  	pfkey_hdr_dup(hdr, orig);
  	hdr->sadb_msg_errno = 0;
  	hdr->sadb_msg_len = len / sizeof(uint64_t);
  
  	if (auth_len) {
  		struct sadb_supported *sp;
  		struct sadb_alg *ap;
  
  		sp = (struct sadb_supported *) skb_put(skb, auth_len);
  		ap = (struct sadb_alg *) (sp + 1);
  
  		sp->sadb_supported_len = auth_len / sizeof(uint64_t);
  		sp->sadb_supported_exttype = SADB_EXT_SUPPORTED_AUTH;
  
  		for (i = 0; ; i++) {
  			struct xfrm_algo_desc *aalg = xfrm_aalg_get_byidx(i);
  			if (!aalg)
  				break;
  			if (aalg->available)
  				*ap++ = aalg->desc;
  		}
  	}
  
  	if (enc_len) {
  		struct sadb_supported *sp;
  		struct sadb_alg *ap;
  
  		sp = (struct sadb_supported *) skb_put(skb, enc_len);
  		ap = (struct sadb_alg *) (sp + 1);
  
  		sp->sadb_supported_len = enc_len / sizeof(uint64_t);
  		sp->sadb_supported_exttype = SADB_EXT_SUPPORTED_ENCRYPT;
  
  		for (i = 0; ; i++) {
  			struct xfrm_algo_desc *ealg = xfrm_ealg_get_byidx(i);
  			if (!ealg)
  				break;
  			if (ealg->available)
  				*ap++ = ealg->desc;
  		}
  	}
  
  out_put_algs:
  	return skb;
  }
4c93fbb06   David S. Miller   pfkey: Use const ...
1581
  static int pfkey_register(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
  {
  	struct pfkey_sock *pfk = pfkey_sk(sk);
  	struct sk_buff *supp_skb;
  
  	if (hdr->sadb_msg_satype > SADB_SATYPE_MAX)
  		return -EINVAL;
  
  	if (hdr->sadb_msg_satype != SADB_SATYPE_UNSPEC) {
  		if (pfk->registered&(1<<hdr->sadb_msg_satype))
  			return -EEXIST;
  		pfk->registered |= (1<<hdr->sadb_msg_satype);
  	}
  
  	xfrm_probe_algs();
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
1596

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1597
1598
1599
1600
1601
1602
1603
  	supp_skb = compose_sadb_supported(hdr, GFP_KERNEL);
  	if (!supp_skb) {
  		if (hdr->sadb_msg_satype != SADB_SATYPE_UNSPEC)
  			pfk->registered &= ~(1<<hdr->sadb_msg_satype);
  
  		return -ENOBUFS;
  	}
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
1604
  	pfkey_broadcast(supp_skb, GFP_KERNEL, BROADCAST_REGISTERED, sk, sock_net(sk));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1605
1606
1607
  
  	return 0;
  }
4c93fbb06   David S. Miller   pfkey: Use const ...
1608
  static int unicast_flush_resp(struct sock *sk, const struct sadb_msg *ihdr)
8be987d73   Jamal Hadi Salim   pfkey: fix SA and...
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
  {
  	struct sk_buff *skb;
  	struct sadb_msg *hdr;
  
  	skb = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_ATOMIC);
  	if (!skb)
  		return -ENOBUFS;
  
  	hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg));
  	memcpy(hdr, ihdr, sizeof(struct sadb_msg));
  	hdr->sadb_msg_errno = (uint8_t) 0;
  	hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
  
  	return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ONE, sk, sock_net(sk));
  }
214e005bc   David S. Miller   xfrm: Pass km_eve...
1624
  static int key_notify_sa_flush(const struct km_event *c)
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1625
1626
1627
1628
1629
1630
1631
1632
  {
  	struct sk_buff *skb;
  	struct sadb_msg *hdr;
  
  	skb = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_ATOMIC);
  	if (!skb)
  		return -ENOBUFS;
  	hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg));
bf08867f9   Herbert Xu   [IPSEC] Turn km_e...
1633
  	hdr->sadb_msg_satype = pfkey_proto2satype(c->data.proto);
151bb0ffe   Jerome Borsboom   [AF_KEY]: no mess...
1634
  	hdr->sadb_msg_type = SADB_FLUSH;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1635
1636
1637
1638
1639
  	hdr->sadb_msg_seq = c->seq;
  	hdr->sadb_msg_pid = c->pid;
  	hdr->sadb_msg_version = PF_KEY_V2;
  	hdr->sadb_msg_errno = (uint8_t) 0;
  	hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
1640
  	pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL, c->net);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1641
1642
1643
  
  	return 0;
  }
4c93fbb06   David S. Miller   pfkey: Use const ...
1644
  static int pfkey_flush(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1645
  {
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
1646
  	struct net *net = sock_net(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1647
  	unsigned proto;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1648
  	struct km_event c;
161a09e73   Joy Latten   audit: Add auditi...
1649
  	struct xfrm_audit audit_info;
8be987d73   Jamal Hadi Salim   pfkey: fix SA and...
1650
  	int err, err2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1651
1652
1653
1654
  
  	proto = pfkey_satype2proto(hdr->sadb_msg_satype);
  	if (proto == 0)
  		return -EINVAL;
0c11b9428   Al Viro   [PATCH] switch au...
1655
  	audit_info.loginuid = audit_get_loginuid(current);
2532386f4   Eric Paris   Audit: collect se...
1656
  	audit_info.sessionid = audit_get_sessionid(current);
161a09e73   Joy Latten   audit: Add auditi...
1657
  	audit_info.secid = 0;
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
1658
  	err = xfrm_state_flush(net, proto, &audit_info);
8be987d73   Jamal Hadi Salim   pfkey: fix SA and...
1659
  	err2 = unicast_flush_resp(sk, hdr);
9e64cc957   Jamal Hadi Salim   xfrm: Flushing em...
1660
1661
1662
  	if (err || err2) {
  		if (err == -ESRCH) /* empty table - go quietly */
  			err = 0;
8be987d73   Jamal Hadi Salim   pfkey: fix SA and...
1663
  		return err ? err : err2;
9e64cc957   Jamal Hadi Salim   xfrm: Flushing em...
1664
  	}
8be987d73   Jamal Hadi Salim   pfkey: fix SA and...
1665

bf08867f9   Herbert Xu   [IPSEC] Turn km_e...
1666
  	c.data.proto = proto;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1667
1668
  	c.seq = hdr->sadb_msg_seq;
  	c.pid = hdr->sadb_msg_pid;
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
1669
  	c.event = XFRM_MSG_FLUSHSA;
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
1670
  	c.net = net;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1671
  	km_state_notify(NULL, &c);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1672
1673
1674
  
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1675
1676
  static int dump_sa(struct xfrm_state *x, int count, void *ptr)
  {
83321d6b9   Timo Teras   [AF_KEY]: Dump SA...
1677
  	struct pfkey_sock *pfk = ptr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1678
1679
  	struct sk_buff *out_skb;
  	struct sadb_msg *out_hdr;
83321d6b9   Timo Teras   [AF_KEY]: Dump SA...
1680
1681
  	if (!pfkey_can_dump(&pfk->sk))
  		return -ENOBUFS;
050f009e1   Herbert Xu   [IPSEC]: Lock sta...
1682
  	out_skb = pfkey_xfrm_state2msg(x);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1683
1684
1685
1686
  	if (IS_ERR(out_skb))
  		return PTR_ERR(out_skb);
  
  	out_hdr = (struct sadb_msg *) out_skb->data;
83321d6b9   Timo Teras   [AF_KEY]: Dump SA...
1687
  	out_hdr->sadb_msg_version = pfk->dump.msg_version;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1688
1689
1690
1691
  	out_hdr->sadb_msg_type = SADB_DUMP;
  	out_hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto);
  	out_hdr->sadb_msg_errno = 0;
  	out_hdr->sadb_msg_reserved = 0;
12a169e7d   Herbert Xu   ipsec: Put dumper...
1692
  	out_hdr->sadb_msg_seq = count + 1;
83321d6b9   Timo Teras   [AF_KEY]: Dump SA...
1693
  	out_hdr->sadb_msg_pid = pfk->dump.msg_pid;
12a169e7d   Herbert Xu   ipsec: Put dumper...
1694
1695
1696
  
  	if (pfk->dump.skb)
  		pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE,
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
1697
  				&pfk->sk, sock_net(&pfk->sk));
12a169e7d   Herbert Xu   ipsec: Put dumper...
1698
  	pfk->dump.skb = out_skb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1699
1700
  	return 0;
  }
83321d6b9   Timo Teras   [AF_KEY]: Dump SA...
1701
1702
  static int pfkey_dump_sa(struct pfkey_sock *pfk)
  {
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
1703
1704
  	struct net *net = sock_net(&pfk->sk);
  	return xfrm_state_walk(net, &pfk->dump.u.state, dump_sa, (void *) pfk);
83321d6b9   Timo Teras   [AF_KEY]: Dump SA...
1705
1706
1707
1708
1709
1710
  }
  
  static void pfkey_dump_sa_done(struct pfkey_sock *pfk)
  {
  	xfrm_state_walk_done(&pfk->dump.u.state);
  }
4c93fbb06   David S. Miller   pfkey: Use const ...
1711
  static int pfkey_dump(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1712
1713
  {
  	u8 proto;
83321d6b9   Timo Teras   [AF_KEY]: Dump SA...
1714
1715
1716
1717
  	struct pfkey_sock *pfk = pfkey_sk(sk);
  
  	if (pfk->dump.dump != NULL)
  		return -EBUSY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1718
1719
1720
1721
  
  	proto = pfkey_satype2proto(hdr->sadb_msg_satype);
  	if (proto == 0)
  		return -EINVAL;
83321d6b9   Timo Teras   [AF_KEY]: Dump SA...
1722
1723
1724
1725
1726
  	pfk->dump.msg_version = hdr->sadb_msg_version;
  	pfk->dump.msg_pid = hdr->sadb_msg_pid;
  	pfk->dump.dump = pfkey_dump_sa;
  	pfk->dump.done = pfkey_dump_sa_done;
  	xfrm_state_walk_init(&pfk->dump.u.state, proto);
4c563f766   Timo Teras   [XFRM]: Speed up ...
1727

83321d6b9   Timo Teras   [AF_KEY]: Dump SA...
1728
  	return pfkey_do_dump(pfk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1729
  }
4c93fbb06   David S. Miller   pfkey: Use const ...
1730
  static int pfkey_promisc(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1731
1732
1733
  {
  	struct pfkey_sock *pfk = pfkey_sk(sk);
  	int satype = hdr->sadb_msg_satype;
4c93fbb06   David S. Miller   pfkey: Use const ...
1734
  	bool reset_errno = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1735
1736
  
  	if (hdr->sadb_msg_len == (sizeof(*hdr) / sizeof(uint64_t))) {
4c93fbb06   David S. Miller   pfkey: Use const ...
1737
  		reset_errno = true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1738
1739
1740
1741
  		if (satype != 0 && satype != 1)
  			return -EINVAL;
  		pfk->promisc = satype;
  	}
4c93fbb06   David S. Miller   pfkey: Use const ...
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
  	if (reset_errno && skb_cloned(skb))
  		skb = skb_copy(skb, GFP_KERNEL);
  	else
  		skb = skb_clone(skb, GFP_KERNEL);
  
  	if (reset_errno && skb) {
  		struct sadb_msg *new_hdr = (struct sadb_msg *) skb->data;
  		new_hdr->sadb_msg_errno = 0;
  	}
  
  	pfkey_broadcast(skb, GFP_KERNEL, BROADCAST_ALL, NULL, sock_net(sk));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
  	return 0;
  }
  
  static int check_reqid(struct xfrm_policy *xp, int dir, int count, void *ptr)
  {
  	int i;
  	u32 reqid = *(u32*)ptr;
  
  	for (i=0; i<xp->xfrm_nr; i++) {
  		if (xp->xfrm_vec[i].reqid == reqid)
  			return -EEXIST;
  	}
  	return 0;
  }
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
1767
  static u32 gen_reqid(struct net *net)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1768
  {
4c563f766   Timo Teras   [XFRM]: Speed up ...
1769
  	struct xfrm_policy_walk walk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1770
  	u32 start;
4c563f766   Timo Teras   [XFRM]: Speed up ...
1771
  	int rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1772
1773
1774
1775
1776
1777
1778
  	static u32 reqid = IPSEC_MANUAL_REQID_MAX;
  
  	start = reqid;
  	do {
  		++reqid;
  		if (reqid == 0)
  			reqid = IPSEC_MANUAL_REQID_MAX+1;
4c563f766   Timo Teras   [XFRM]: Speed up ...
1779
  		xfrm_policy_walk_init(&walk, XFRM_POLICY_TYPE_MAIN);
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
1780
  		rc = xfrm_policy_walk(net, &walk, check_reqid, (void*)&reqid);
4c563f766   Timo Teras   [XFRM]: Speed up ...
1781
1782
  		xfrm_policy_walk_done(&walk);
  		if (rc != -EEXIST)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1783
1784
1785
1786
1787
1788
1789
1790
  			return reqid;
  	} while (reqid != start);
  	return 0;
  }
  
  static int
  parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq)
  {
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
1791
  	struct net *net = xp_net(xp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1792
  	struct xfrm_tmpl *t = xp->xfrm_vec + xp->xfrm_nr;
55569ce25   Kazunori MIYAZAWA   [KEY]: Fix conver...
1793
  	int mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1794
1795
1796
1797
1798
1799
1800
1801
  
  	if (xp->xfrm_nr >= XFRM_MAX_DEPTH)
  		return -ELOOP;
  
  	if (rq->sadb_x_ipsecrequest_mode == 0)
  		return -EINVAL;
  
  	t->id.proto = rq->sadb_x_ipsecrequest_proto; /* XXX check proto */
55569ce25   Kazunori MIYAZAWA   [KEY]: Fix conver...
1802
1803
1804
  	if ((mode = pfkey_mode_to_xfrm(rq->sadb_x_ipsecrequest_mode)) < 0)
  		return -EINVAL;
  	t->mode = mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1805
1806
1807
1808
1809
1810
  	if (rq->sadb_x_ipsecrequest_level == IPSEC_LEVEL_USE)
  		t->optional = 1;
  	else if (rq->sadb_x_ipsecrequest_level == IPSEC_LEVEL_UNIQUE) {
  		t->reqid = rq->sadb_x_ipsecrequest_reqid;
  		if (t->reqid > IPSEC_MANUAL_REQID_MAX)
  			t->reqid = 0;
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
1811
  		if (!t->reqid && !(t->reqid = gen_reqid(net)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1812
1813
1814
1815
  			return -ENOBUFS;
  	}
  
  	/* addresses present only in tunnel mode */
7e49e6de3   Masahide NAKAMURA   [XFRM]: Add XFRM_...
1816
  	if (t->mode == XFRM_MODE_TUNNEL) {
5f95ac911   YOSHIFUJI Hideaki   key: Share common...
1817
1818
1819
1820
1821
1822
  		u8 *sa = (u8 *) (rq + 1);
  		int family, socklen;
  
  		family = pfkey_sockaddr_extract((struct sockaddr *)sa,
  						&t->saddr);
  		if (!family)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1823
  			return -EINVAL;
5f95ac911   YOSHIFUJI Hideaki   key: Share common...
1824
1825
1826
1827
1828
1829
  
  		socklen = pfkey_sockaddr_len(family);
  		if (pfkey_sockaddr_extract((struct sockaddr *)(sa + socklen),
  					   &t->id.daddr) != family)
  			return -EINVAL;
  		t->encap_family = family;
2718aa7c5   Miika Komu   [IPSEC]: Add AF_K...
1830
1831
  	} else
  		t->encap_family = xp->family;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1832
  	/* No way to set this via kame pfkey */
c5d18e984   Herbert Xu   [IPSEC]: Fix catc...
1833
  	t->allalgs = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
  	xp->xfrm_nr++;
  	return 0;
  }
  
  static int
  parse_ipsecrequests(struct xfrm_policy *xp, struct sadb_x_policy *pol)
  {
  	int err;
  	int len = pol->sadb_x_policy_len*8 - sizeof(struct sadb_x_policy);
  	struct sadb_x_ipsecrequest *rq = (void*)(pol+1);
  
  	while (len >= sizeof(struct sadb_x_ipsecrequest)) {
  		if ((err = parse_ipsecrequest(xp, rq)) < 0)
  			return err;
  		len -= rq->sadb_x_ipsecrequest_len;
  		rq = (void*)((u8*)rq + rq->sadb_x_ipsecrequest_len);
  	}
  	return 0;
  }
4c93fbb06   David S. Miller   pfkey: Use const ...
1853
  static inline int pfkey_xfrm_policy2sec_ctx_size(const struct xfrm_policy *xp)
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
  {
    struct xfrm_sec_ctx *xfrm_ctx = xp->security;
  
  	if (xfrm_ctx) {
  		int len = sizeof(struct sadb_x_sec_ctx);
  		len += xfrm_ctx->ctx_len;
  		return PFKEY_ALIGN8(len);
  	}
  	return 0;
  }
4c93fbb06   David S. Miller   pfkey: Use const ...
1864
  static int pfkey_xfrm_policy2msg_size(const struct xfrm_policy *xp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1865
  {
4c93fbb06   David S. Miller   pfkey: Use const ...
1866
  	const struct xfrm_tmpl *t;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1867
  	int sockaddr_size = pfkey_sockaddr_size(xp->family);
2718aa7c5   Miika Komu   [IPSEC]: Add AF_K...
1868
1869
1870
1871
1872
  	int socklen = 0;
  	int i;
  
  	for (i=0; i<xp->xfrm_nr; i++) {
  		t = xp->xfrm_vec + i;
9e8b4ed8b   YOSHIFUJI Hideaki   key: Introduce pf...
1873
  		socklen += pfkey_sockaddr_len(t->encap_family);
2718aa7c5   Miika Komu   [IPSEC]: Add AF_K...
1874
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1875
1876
1877
  
  	return sizeof(struct sadb_msg) +
  		(sizeof(struct sadb_lifetime) * 3) +
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
1878
  		(sizeof(struct sadb_address) * 2) +
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1879
1880
  		(sockaddr_size * 2) +
  		sizeof(struct sadb_x_policy) +
2718aa7c5   Miika Komu   [IPSEC]: Add AF_K...
1881
1882
  		(xp->xfrm_nr * sizeof(struct sadb_x_ipsecrequest)) +
  		(socklen * 2) +
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
1883
  		pfkey_xfrm_policy2sec_ctx_size(xp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1884
  }
4c93fbb06   David S. Miller   pfkey: Use const ...
1885
  static struct sk_buff * pfkey_xfrm_policy2msg_prep(const struct xfrm_policy *xp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
  {
  	struct sk_buff *skb;
  	int size;
  
  	size = pfkey_xfrm_policy2msg_size(xp);
  
  	skb =  alloc_skb(size + 16, GFP_ATOMIC);
  	if (skb == NULL)
  		return ERR_PTR(-ENOBUFS);
  
  	return skb;
  }
4c93fbb06   David S. Miller   pfkey: Use const ...
1898
  static int pfkey_xfrm_policy2msg(struct sk_buff *skb, const struct xfrm_policy *xp, int dir)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1899
1900
1901
1902
1903
  {
  	struct sadb_msg *hdr;
  	struct sadb_address *addr;
  	struct sadb_lifetime *lifetime;
  	struct sadb_x_policy *pol;
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
1904
1905
  	struct sadb_x_sec_ctx *sec_ctx;
  	struct xfrm_sec_ctx *xfrm_ctx;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1906
1907
1908
  	int i;
  	int size;
  	int sockaddr_size = pfkey_sockaddr_size(xp->family);
9e8b4ed8b   YOSHIFUJI Hideaki   key: Introduce pf...
1909
  	int socklen = pfkey_sockaddr_len(xp->family);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1910
1911
1912
1913
1914
1915
1916
1917
  
  	size = pfkey_xfrm_policy2msg_size(xp);
  
  	/* call should fill header later */
  	hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg));
  	memset(hdr, 0, size);	/* XXX do we need this ? */
  
  	/* src address */
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
1918
  	addr = (struct sadb_address*) skb_put(skb,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1919
  					      sizeof(struct sadb_address)+sockaddr_size);
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
1920
  	addr->sadb_address_len =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1921
1922
1923
1924
1925
1926
  		(sizeof(struct sadb_address)+sockaddr_size)/
  			sizeof(uint64_t);
  	addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
  	addr->sadb_address_proto = pfkey_proto_from_xfrm(xp->selector.proto);
  	addr->sadb_address_prefixlen = xp->selector.prefixlen_s;
  	addr->sadb_address_reserved = 0;
e5b56652c   YOSHIFUJI Hideaki   key: Share common...
1927
1928
1929
1930
  	if (!pfkey_sockaddr_fill(&xp->selector.saddr,
  				 xp->selector.sport,
  				 (struct sockaddr *) (addr + 1),
  				 xp->family))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1931
1932
1933
  		BUG();
  
  	/* dst address */
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
1934
  	addr = (struct sadb_address*) skb_put(skb,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1935
1936
1937
1938
1939
1940
  					      sizeof(struct sadb_address)+sockaddr_size);
  	addr->sadb_address_len =
  		(sizeof(struct sadb_address)+sockaddr_size)/
  			sizeof(uint64_t);
  	addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
  	addr->sadb_address_proto = pfkey_proto_from_xfrm(xp->selector.proto);
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
1941
  	addr->sadb_address_prefixlen = xp->selector.prefixlen_d;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1942
  	addr->sadb_address_reserved = 0;
e5b56652c   YOSHIFUJI Hideaki   key: Share common...
1943
1944
1945
1946
  
  	pfkey_sockaddr_fill(&xp->selector.daddr, xp->selector.dport,
  			    (struct sockaddr *) (addr + 1),
  			    xp->family);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1947
1948
  
  	/* hard time */
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
1949
  	lifetime = (struct sadb_lifetime *)  skb_put(skb,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1950
1951
1952
1953
1954
1955
1956
1957
1958
  						     sizeof(struct sadb_lifetime));
  	lifetime->sadb_lifetime_len =
  		sizeof(struct sadb_lifetime)/sizeof(uint64_t);
  	lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD;
  	lifetime->sadb_lifetime_allocations =  _X2KEY(xp->lft.hard_packet_limit);
  	lifetime->sadb_lifetime_bytes = _X2KEY(xp->lft.hard_byte_limit);
  	lifetime->sadb_lifetime_addtime = xp->lft.hard_add_expires_seconds;
  	lifetime->sadb_lifetime_usetime = xp->lft.hard_use_expires_seconds;
  	/* soft time */
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
1959
  	lifetime = (struct sadb_lifetime *)  skb_put(skb,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1960
1961
1962
1963
1964
1965
1966
1967
1968
  						     sizeof(struct sadb_lifetime));
  	lifetime->sadb_lifetime_len =
  		sizeof(struct sadb_lifetime)/sizeof(uint64_t);
  	lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT;
  	lifetime->sadb_lifetime_allocations =  _X2KEY(xp->lft.soft_packet_limit);
  	lifetime->sadb_lifetime_bytes = _X2KEY(xp->lft.soft_byte_limit);
  	lifetime->sadb_lifetime_addtime = xp->lft.soft_add_expires_seconds;
  	lifetime->sadb_lifetime_usetime = xp->lft.soft_use_expires_seconds;
  	/* current time */
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
1969
  	lifetime = (struct sadb_lifetime *)  skb_put(skb,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
  						     sizeof(struct sadb_lifetime));
  	lifetime->sadb_lifetime_len =
  		sizeof(struct sadb_lifetime)/sizeof(uint64_t);
  	lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT;
  	lifetime->sadb_lifetime_allocations = xp->curlft.packets;
  	lifetime->sadb_lifetime_bytes = xp->curlft.bytes;
  	lifetime->sadb_lifetime_addtime = xp->curlft.add_time;
  	lifetime->sadb_lifetime_usetime = xp->curlft.use_time;
  
  	pol = (struct sadb_x_policy *)  skb_put(skb, sizeof(struct sadb_x_policy));
  	pol->sadb_x_policy_len = sizeof(struct sadb_x_policy)/sizeof(uint64_t);
  	pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
  	pol->sadb_x_policy_type = IPSEC_POLICY_DISCARD;
  	if (xp->action == XFRM_POLICY_ALLOW) {
  		if (xp->xfrm_nr)
  			pol->sadb_x_policy_type = IPSEC_POLICY_IPSEC;
  		else
  			pol->sadb_x_policy_type = IPSEC_POLICY_NONE;
  	}
  	pol->sadb_x_policy_dir = dir+1;
  	pol->sadb_x_policy_id = xp->index;
  	pol->sadb_x_policy_priority = xp->priority;
  
  	for (i=0; i<xp->xfrm_nr; i++) {
4c93fbb06   David S. Miller   pfkey: Use const ...
1994
  		const struct xfrm_tmpl *t = xp->xfrm_vec + i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1995
  		struct sadb_x_ipsecrequest *rq;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1996
  		int req_size;
55569ce25   Kazunori MIYAZAWA   [KEY]: Fix conver...
1997
  		int mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1998
1999
  
  		req_size = sizeof(struct sadb_x_ipsecrequest);
e5b56652c   YOSHIFUJI Hideaki   key: Share common...
2000
2001
2002
2003
  		if (t->mode == XFRM_MODE_TUNNEL) {
  			socklen = pfkey_sockaddr_len(t->encap_family);
  			req_size += socklen * 2;
  		} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2004
  			size -= 2*socklen;
e5b56652c   YOSHIFUJI Hideaki   key: Share common...
2005
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2006
2007
2008
2009
2010
  		rq = (void*)skb_put(skb, req_size);
  		pol->sadb_x_policy_len += req_size/8;
  		memset(rq, 0, sizeof(*rq));
  		rq->sadb_x_ipsecrequest_len = req_size;
  		rq->sadb_x_ipsecrequest_proto = t->id.proto;
55569ce25   Kazunori MIYAZAWA   [KEY]: Fix conver...
2011
2012
  		if ((mode = pfkey_mode_from_xfrm(t->mode)) < 0)
  			return -EINVAL;
fefaa75e0   David S. Miller   [IPSEC] af_key: F...
2013
  		rq->sadb_x_ipsecrequest_mode = mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2014
2015
2016
2017
2018
2019
  		rq->sadb_x_ipsecrequest_level = IPSEC_LEVEL_REQUIRE;
  		if (t->reqid)
  			rq->sadb_x_ipsecrequest_level = IPSEC_LEVEL_UNIQUE;
  		if (t->optional)
  			rq->sadb_x_ipsecrequest_level = IPSEC_LEVEL_USE;
  		rq->sadb_x_ipsecrequest_reqid = t->reqid;
e5b56652c   YOSHIFUJI Hideaki   key: Share common...
2020

7e49e6de3   Masahide NAKAMURA   [XFRM]: Add XFRM_...
2021
  		if (t->mode == XFRM_MODE_TUNNEL) {
e5b56652c   YOSHIFUJI Hideaki   key: Share common...
2022
2023
2024
2025
2026
2027
2028
  			u8 *sa = (void *)(rq + 1);
  			pfkey_sockaddr_fill(&t->saddr, 0,
  					    (struct sockaddr *)sa,
  					    t->encap_family);
  			pfkey_sockaddr_fill(&t->id.daddr, 0,
  					    (struct sockaddr *) (sa + socklen),
  					    t->encap_family);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2029
2030
  		}
  	}
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
  
  	/* security context */
  	if ((xfrm_ctx = xp->security)) {
  		int ctx_size = pfkey_xfrm_policy2sec_ctx_size(xp);
  
  		sec_ctx = (struct sadb_x_sec_ctx *) skb_put(skb, ctx_size);
  		sec_ctx->sadb_x_sec_len = ctx_size / sizeof(uint64_t);
  		sec_ctx->sadb_x_sec_exttype = SADB_X_EXT_SEC_CTX;
  		sec_ctx->sadb_x_ctx_doi = xfrm_ctx->ctx_doi;
  		sec_ctx->sadb_x_ctx_alg = xfrm_ctx->ctx_alg;
  		sec_ctx->sadb_x_ctx_len = xfrm_ctx->ctx_len;
  		memcpy(sec_ctx + 1, xfrm_ctx->ctx_str,
  		       xfrm_ctx->ctx_len);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2045
2046
  	hdr->sadb_msg_len = size / sizeof(uint64_t);
  	hdr->sadb_msg_reserved = atomic_read(&xp->refcnt);
55569ce25   Kazunori MIYAZAWA   [KEY]: Fix conver...
2047
2048
  
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2049
  }
214e005bc   David S. Miller   xfrm: Pass km_eve...
2050
  static int key_notify_policy(struct xfrm_policy *xp, int dir, const struct km_event *c)
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2051
2052
2053
2054
2055
2056
  {
  	struct sk_buff *out_skb;
  	struct sadb_msg *out_hdr;
  	int err;
  
  	out_skb = pfkey_xfrm_policy2msg_prep(xp);
9a127aad4   Dan Carpenter   af_key: return er...
2057
2058
  	if (IS_ERR(out_skb))
  		return PTR_ERR(out_skb);
55569ce25   Kazunori MIYAZAWA   [KEY]: Fix conver...
2059
2060
2061
  	err = pfkey_xfrm_policy2msg(out_skb, xp, dir);
  	if (err < 0)
  		return err;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2062
2063
2064
  
  	out_hdr = (struct sadb_msg *) out_skb->data;
  	out_hdr->sadb_msg_version = PF_KEY_V2;
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
2065
  	if (c->data.byid && c->event == XFRM_MSG_DELPOLICY)
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2066
2067
2068
2069
2070
2071
  		out_hdr->sadb_msg_type = SADB_X_SPDDELETE2;
  	else
  		out_hdr->sadb_msg_type = event2poltype(c->event);
  	out_hdr->sadb_msg_errno = 0;
  	out_hdr->sadb_msg_seq = c->seq;
  	out_hdr->sadb_msg_pid = c->pid;
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
2072
  	pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, NULL, xp_net(xp));
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2073
2074
2075
  	return 0;
  
  }
4c93fbb06   David S. Miller   pfkey: Use const ...
2076
  static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2077
  {
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
2078
  	struct net *net = sock_net(sk);
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
2079
  	int err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2080
2081
2082
2083
  	struct sadb_lifetime *lifetime;
  	struct sadb_address *sa;
  	struct sadb_x_policy *pol;
  	struct xfrm_policy *xp;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2084
  	struct km_event c;
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
2085
  	struct sadb_x_sec_ctx *sec_ctx;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
  
  	if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1],
  				     ext_hdrs[SADB_EXT_ADDRESS_DST-1]) ||
  	    !ext_hdrs[SADB_X_EXT_POLICY-1])
  		return -EINVAL;
  
  	pol = ext_hdrs[SADB_X_EXT_POLICY-1];
  	if (pol->sadb_x_policy_type > IPSEC_POLICY_IPSEC)
  		return -EINVAL;
  	if (!pol->sadb_x_policy_dir || pol->sadb_x_policy_dir >= IPSEC_DIR_MAX)
  		return -EINVAL;
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
2097
  	xp = xfrm_policy_alloc(net, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2098
2099
2100
2101
2102
2103
  	if (xp == NULL)
  		return -ENOBUFS;
  
  	xp->action = (pol->sadb_x_policy_type == IPSEC_POLICY_DISCARD ?
  		      XFRM_POLICY_BLOCK : XFRM_POLICY_ALLOW);
  	xp->priority = pol->sadb_x_policy_priority;
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
2104
  	sa = ext_hdrs[SADB_EXT_ADDRESS_SRC-1],
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
  	xp->family = pfkey_sadb_addr2xfrm_addr(sa, &xp->selector.saddr);
  	if (!xp->family) {
  		err = -EINVAL;
  		goto out;
  	}
  	xp->selector.family = xp->family;
  	xp->selector.prefixlen_s = sa->sadb_address_prefixlen;
  	xp->selector.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto);
  	xp->selector.sport = ((struct sockaddr_in *)(sa+1))->sin_port;
  	if (xp->selector.sport)
8f83f23e6   Al Viro   [XFRM]: ports in ...
2115
  		xp->selector.sport_mask = htons(0xffff);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2116

8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
2117
  	sa = ext_hdrs[SADB_EXT_ADDRESS_DST-1],
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
  	pfkey_sadb_addr2xfrm_addr(sa, &xp->selector.daddr);
  	xp->selector.prefixlen_d = sa->sadb_address_prefixlen;
  
  	/* Amusing, we set this twice.  KAME apps appear to set same value
  	 * in both addresses.
  	 */
  	xp->selector.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto);
  
  	xp->selector.dport = ((struct sockaddr_in *)(sa+1))->sin_port;
  	if (xp->selector.dport)
8f83f23e6   Al Viro   [XFRM]: ports in ...
2128
  		xp->selector.dport_mask = htons(0xffff);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2129

ea1107338   Joe Perches   net: Remove casts...
2130
  	sec_ctx = ext_hdrs[SADB_X_EXT_SEC_CTX - 1];
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
2131
2132
2133
2134
2135
2136
2137
  	if (sec_ctx != NULL) {
  		struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx);
  
  		if (!uctx) {
  			err = -ENOBUFS;
  			goto out;
  		}
03e1ad7b5   Paul Moore   LSM: Make the Lab...
2138
  		err = security_xfrm_policy_alloc(&xp->security, uctx);
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
2139
2140
2141
2142
2143
  		kfree(uctx);
  
  		if (err)
  			goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
  	xp->lft.soft_byte_limit = XFRM_INF;
  	xp->lft.hard_byte_limit = XFRM_INF;
  	xp->lft.soft_packet_limit = XFRM_INF;
  	xp->lft.hard_packet_limit = XFRM_INF;
  	if ((lifetime = ext_hdrs[SADB_EXT_LIFETIME_HARD-1]) != NULL) {
  		xp->lft.hard_packet_limit = _KEY2X(lifetime->sadb_lifetime_allocations);
  		xp->lft.hard_byte_limit = _KEY2X(lifetime->sadb_lifetime_bytes);
  		xp->lft.hard_add_expires_seconds = lifetime->sadb_lifetime_addtime;
  		xp->lft.hard_use_expires_seconds = lifetime->sadb_lifetime_usetime;
  	}
  	if ((lifetime = ext_hdrs[SADB_EXT_LIFETIME_SOFT-1]) != NULL) {
  		xp->lft.soft_packet_limit = _KEY2X(lifetime->sadb_lifetime_allocations);
  		xp->lft.soft_byte_limit = _KEY2X(lifetime->sadb_lifetime_bytes);
  		xp->lft.soft_add_expires_seconds = lifetime->sadb_lifetime_addtime;
  		xp->lft.soft_use_expires_seconds = lifetime->sadb_lifetime_usetime;
  	}
  	xp->xfrm_nr = 0;
  	if (pol->sadb_x_policy_type == IPSEC_POLICY_IPSEC &&
  	    (err = parse_ipsecrequests(xp, pol)) < 0)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2164
2165
  	err = xfrm_policy_insert(pol->sadb_x_policy_dir-1, xp,
  				 hdr->sadb_msg_type != SADB_X_SPDUPDATE);
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
2166

ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2167
  	xfrm_audit_policy_add(xp, err ? 0 : 1,
2532386f4   Eric Paris   Audit: collect se...
2168
2169
  			      audit_get_loginuid(current),
  			      audit_get_sessionid(current), 0);
161a09e73   Joy Latten   audit: Add auditi...
2170

df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
2171
2172
  	if (err)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2173

26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2174
  	if (hdr->sadb_msg_type == SADB_X_SPDUPDATE)
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
2175
  		c.event = XFRM_MSG_UPDPOLICY;
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
2176
  	else
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
2177
  		c.event = XFRM_MSG_NEWPOLICY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2178

26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2179
2180
  	c.seq = hdr->sadb_msg_seq;
  	c.pid = hdr->sadb_msg_pid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2181

26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2182
2183
  	km_policy_notify(xp, pol->sadb_x_policy_dir-1, &c);
  	xfrm_pol_put(xp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2184
2185
2186
  	return 0;
  
  out:
12a169e7d   Herbert Xu   ipsec: Put dumper...
2187
  	xp->walk.dead = 1;
64c31b3f7   WANG Cong   [XFRM] xfrm_polic...
2188
  	xfrm_policy_destroy(xp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2189
2190
  	return err;
  }
4c93fbb06   David S. Miller   pfkey: Use const ...
2191
  static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2192
  {
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
2193
  	struct net *net = sock_net(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2194
2195
2196
  	int err;
  	struct sadb_address *sa;
  	struct sadb_x_policy *pol;
03e1ad7b5   Paul Moore   LSM: Make the Lab...
2197
  	struct xfrm_policy *xp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2198
  	struct xfrm_selector sel;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2199
  	struct km_event c;
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
2200
  	struct sadb_x_sec_ctx *sec_ctx;
2db3e47e7   Brian Haley   af_key: Fix af_ke...
2201
  	struct xfrm_sec_ctx *pol_ctx = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
  
  	if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1],
  				     ext_hdrs[SADB_EXT_ADDRESS_DST-1]) ||
  	    !ext_hdrs[SADB_X_EXT_POLICY-1])
  		return -EINVAL;
  
  	pol = ext_hdrs[SADB_X_EXT_POLICY-1];
  	if (!pol->sadb_x_policy_dir || pol->sadb_x_policy_dir >= IPSEC_DIR_MAX)
  		return -EINVAL;
  
  	memset(&sel, 0, sizeof(sel));
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
2213
  	sa = ext_hdrs[SADB_EXT_ADDRESS_SRC-1],
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2214
2215
2216
2217
2218
  	sel.family = pfkey_sadb_addr2xfrm_addr(sa, &sel.saddr);
  	sel.prefixlen_s = sa->sadb_address_prefixlen;
  	sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto);
  	sel.sport = ((struct sockaddr_in *)(sa+1))->sin_port;
  	if (sel.sport)
8f83f23e6   Al Viro   [XFRM]: ports in ...
2219
  		sel.sport_mask = htons(0xffff);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2220

8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
2221
  	sa = ext_hdrs[SADB_EXT_ADDRESS_DST-1],
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2222
2223
2224
2225
2226
  	pfkey_sadb_addr2xfrm_addr(sa, &sel.daddr);
  	sel.prefixlen_d = sa->sadb_address_prefixlen;
  	sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto);
  	sel.dport = ((struct sockaddr_in *)(sa+1))->sin_port;
  	if (sel.dport)
8f83f23e6   Al Viro   [XFRM]: ports in ...
2227
  		sel.dport_mask = htons(0xffff);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2228

ea1107338   Joe Perches   net: Remove casts...
2229
  	sec_ctx = ext_hdrs[SADB_X_EXT_SEC_CTX - 1];
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
2230
2231
2232
2233
2234
  	if (sec_ctx != NULL) {
  		struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx);
  
  		if (!uctx)
  			return -ENOMEM;
03e1ad7b5   Paul Moore   LSM: Make the Lab...
2235
  		err = security_xfrm_policy_alloc(&pol_ctx, uctx);
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
2236
  		kfree(uctx);
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
2237
2238
  		if (err)
  			return err;
2db3e47e7   Brian Haley   af_key: Fix af_ke...
2239
  	}
161a09e73   Joy Latten   audit: Add auditi...
2240

8ca2e93b5   Jamal Hadi Salim   xfrm: SP lookups ...
2241
  	xp = xfrm_policy_bysel_ctx(net, DUMMY_MARK, XFRM_POLICY_TYPE_MAIN,
03e1ad7b5   Paul Moore   LSM: Make the Lab...
2242
2243
2244
  				   pol->sadb_x_policy_dir - 1, &sel, pol_ctx,
  				   1, &err);
  	security_xfrm_policy_free(pol_ctx);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2245
2246
  	if (xp == NULL)
  		return -ENOENT;
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2247
  	xfrm_audit_policy_delete(xp, err ? 0 : 1,
2532386f4   Eric Paris   Audit: collect se...
2248
2249
  				 audit_get_loginuid(current),
  				 audit_get_sessionid(current), 0);
13fcfbb06   David S. Miller   [XFRM]: Fix OOPSe...
2250
2251
  
  	if (err)
c8c05a8ee   Catherine Zhang   [LSM-IPsec]: SELi...
2252
  		goto out;
13fcfbb06   David S. Miller   [XFRM]: Fix OOPSe...
2253

26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2254
2255
  	c.seq = hdr->sadb_msg_seq;
  	c.pid = hdr->sadb_msg_pid;
1839faab9   Tobias Brunner   af_key: fix SADB_...
2256
  	c.data.byid = 0;
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
2257
  	c.event = XFRM_MSG_DELPOLICY;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2258
  	km_policy_notify(xp, pol->sadb_x_policy_dir-1, &c);
c8c05a8ee   Catherine Zhang   [LSM-IPsec]: SELi...
2259
  out:
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2260
2261
2262
  	xfrm_pol_put(xp);
  	return err;
  }
4c93fbb06   David S. Miller   pfkey: Use const ...
2263
  static int key_pol_get_resp(struct sock *sk, struct xfrm_policy *xp, const struct sadb_msg *hdr, int dir)
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2264
2265
2266
2267
2268
  {
  	int err;
  	struct sk_buff *out_skb;
  	struct sadb_msg *out_hdr;
  	err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2269
2270
2271
2272
2273
  	out_skb = pfkey_xfrm_policy2msg_prep(xp);
  	if (IS_ERR(out_skb)) {
  		err =  PTR_ERR(out_skb);
  		goto out;
  	}
55569ce25   Kazunori MIYAZAWA   [KEY]: Fix conver...
2274
2275
2276
  	err = pfkey_xfrm_policy2msg(out_skb, xp, dir);
  	if (err < 0)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2277
2278
2279
  
  	out_hdr = (struct sadb_msg *) out_skb->data;
  	out_hdr->sadb_msg_version = hdr->sadb_msg_version;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2280
  	out_hdr->sadb_msg_type = hdr->sadb_msg_type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2281
2282
2283
2284
  	out_hdr->sadb_msg_satype = 0;
  	out_hdr->sadb_msg_errno = 0;
  	out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
  	out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
2285
  	pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, sk, xp_net(xp));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2286
2287
2288
  	err = 0;
  
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2289
2290
  	return err;
  }
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
2291
2292
2293
  #ifdef CONFIG_NET_KEY_MIGRATE
  static int pfkey_sockaddr_pair_size(sa_family_t family)
  {
9e8b4ed8b   YOSHIFUJI Hideaki   key: Introduce pf...
2294
  	return PFKEY_ALIGN8(pfkey_sockaddr_len(family) * 2);
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
2295
  }
13c1d1893   Arnaud Ebalard   xfrm: MIGRATE enh...
2296
  static int parse_sockaddr_pair(struct sockaddr *sa, int ext_len,
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
2297
2298
2299
  			       xfrm_address_t *saddr, xfrm_address_t *daddr,
  			       u16 *family)
  {
5f95ac911   YOSHIFUJI Hideaki   key: Share common...
2300
  	int af, socklen;
13c1d1893   Arnaud Ebalard   xfrm: MIGRATE enh...
2301
  	if (ext_len < pfkey_sockaddr_pair_size(sa->sa_family))
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
2302
  		return -EINVAL;
13c1d1893   Arnaud Ebalard   xfrm: MIGRATE enh...
2303
  	af = pfkey_sockaddr_extract(sa, saddr);
5f95ac911   YOSHIFUJI Hideaki   key: Share common...
2304
2305
2306
2307
  	if (!af)
  		return -EINVAL;
  
  	socklen = pfkey_sockaddr_len(af);
13c1d1893   Arnaud Ebalard   xfrm: MIGRATE enh...
2308
  	if (pfkey_sockaddr_extract((struct sockaddr *) (((u8 *)sa) + socklen),
5f95ac911   YOSHIFUJI Hideaki   key: Share common...
2309
  				   daddr) != af)
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
2310
  		return -EINVAL;
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
2311

5f95ac911   YOSHIFUJI Hideaki   key: Share common...
2312
  	*family = af;
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
2313
2314
2315
2316
2317
2318
2319
2320
  	return 0;
  }
  
  static int ipsecrequests_to_migrate(struct sadb_x_ipsecrequest *rq1, int len,
  				    struct xfrm_migrate *m)
  {
  	int err;
  	struct sadb_x_ipsecrequest *rq2;
55569ce25   Kazunori MIYAZAWA   [KEY]: Fix conver...
2321
  	int mode;
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
2322
2323
2324
2325
2326
2327
  
  	if (len <= sizeof(struct sadb_x_ipsecrequest) ||
  	    len < rq1->sadb_x_ipsecrequest_len)
  		return -EINVAL;
  
  	/* old endoints */
13c1d1893   Arnaud Ebalard   xfrm: MIGRATE enh...
2328
2329
2330
  	err = parse_sockaddr_pair((struct sockaddr *)(rq1 + 1),
  				  rq1->sadb_x_ipsecrequest_len,
  				  &m->old_saddr, &m->old_daddr,
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
  				  &m->old_family);
  	if (err)
  		return err;
  
  	rq2 = (struct sadb_x_ipsecrequest *)((u8 *)rq1 + rq1->sadb_x_ipsecrequest_len);
  	len -= rq1->sadb_x_ipsecrequest_len;
  
  	if (len <= sizeof(struct sadb_x_ipsecrequest) ||
  	    len < rq2->sadb_x_ipsecrequest_len)
  		return -EINVAL;
  
  	/* new endpoints */
13c1d1893   Arnaud Ebalard   xfrm: MIGRATE enh...
2343
2344
2345
  	err = parse_sockaddr_pair((struct sockaddr *)(rq2 + 1),
  				  rq2->sadb_x_ipsecrequest_len,
  				  &m->new_saddr, &m->new_daddr,
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
  				  &m->new_family);
  	if (err)
  		return err;
  
  	if (rq1->sadb_x_ipsecrequest_proto != rq2->sadb_x_ipsecrequest_proto ||
  	    rq1->sadb_x_ipsecrequest_mode != rq2->sadb_x_ipsecrequest_mode ||
  	    rq1->sadb_x_ipsecrequest_reqid != rq2->sadb_x_ipsecrequest_reqid)
  		return -EINVAL;
  
  	m->proto = rq1->sadb_x_ipsecrequest_proto;
55569ce25   Kazunori MIYAZAWA   [KEY]: Fix conver...
2356
2357
2358
  	if ((mode = pfkey_mode_to_xfrm(rq1->sadb_x_ipsecrequest_mode)) < 0)
  		return -EINVAL;
  	m->mode = mode;
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
2359
2360
2361
2362
2363
2364
2365
  	m->reqid = rq1->sadb_x_ipsecrequest_reqid;
  
  	return ((int)(rq1->sadb_x_ipsecrequest_len +
  		      rq2->sadb_x_ipsecrequest_len));
  }
  
  static int pfkey_migrate(struct sock *sk, struct sk_buff *skb,
4c93fbb06   David S. Miller   pfkey: Use const ...
2366
  			 const struct sadb_msg *hdr, void * const *ext_hdrs)
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
2367
2368
2369
2370
  {
  	int i, len, ret, err = -EINVAL;
  	u8 dir;
  	struct sadb_address *sa;
13c1d1893   Arnaud Ebalard   xfrm: MIGRATE enh...
2371
  	struct sadb_x_kmaddress *kma;
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
2372
2373
2374
2375
  	struct sadb_x_policy *pol;
  	struct sadb_x_ipsecrequest *rq;
  	struct xfrm_selector sel;
  	struct xfrm_migrate m[XFRM_MAX_DEPTH];
13c1d1893   Arnaud Ebalard   xfrm: MIGRATE enh...
2376
  	struct xfrm_kmaddress k;
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
2377
2378
  
  	if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC - 1],
13c1d1893   Arnaud Ebalard   xfrm: MIGRATE enh...
2379
  				     ext_hdrs[SADB_EXT_ADDRESS_DST - 1]) ||
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
2380
2381
2382
2383
  	    !ext_hdrs[SADB_X_EXT_POLICY - 1]) {
  		err = -EINVAL;
  		goto out;
  	}
13c1d1893   Arnaud Ebalard   xfrm: MIGRATE enh...
2384
  	kma = ext_hdrs[SADB_X_EXT_KMADDRESS - 1];
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
2385
  	pol = ext_hdrs[SADB_X_EXT_POLICY - 1];
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
2386
2387
2388
2389
2390
  
  	if (pol->sadb_x_policy_dir >= IPSEC_DIR_MAX) {
  		err = -EINVAL;
  		goto out;
  	}
13c1d1893   Arnaud Ebalard   xfrm: MIGRATE enh...
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
  	if (kma) {
  		/* convert sadb_x_kmaddress to xfrm_kmaddress */
  		k.reserved = kma->sadb_x_kmaddress_reserved;
  		ret = parse_sockaddr_pair((struct sockaddr *)(kma + 1),
  					  8*(kma->sadb_x_kmaddress_len) - sizeof(*kma),
  					  &k.local, &k.remote, &k.family);
  		if (ret < 0) {
  			err = ret;
  			goto out;
  		}
  	}
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
  	dir = pol->sadb_x_policy_dir - 1;
  	memset(&sel, 0, sizeof(sel));
  
  	/* set source address info of selector */
  	sa = ext_hdrs[SADB_EXT_ADDRESS_SRC - 1];
  	sel.family = pfkey_sadb_addr2xfrm_addr(sa, &sel.saddr);
  	sel.prefixlen_s = sa->sadb_address_prefixlen;
  	sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto);
  	sel.sport = ((struct sockaddr_in *)(sa + 1))->sin_port;
  	if (sel.sport)
582ee43da   Al Viro   net/* misc endian...
2412
  		sel.sport_mask = htons(0xffff);
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
2413
2414
2415
2416
2417
2418
2419
2420
  
  	/* set destination address info of selector */
  	sa = ext_hdrs[SADB_EXT_ADDRESS_DST - 1],
  	pfkey_sadb_addr2xfrm_addr(sa, &sel.daddr);
  	sel.prefixlen_d = sa->sadb_address_prefixlen;
  	sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto);
  	sel.dport = ((struct sockaddr_in *)(sa + 1))->sin_port;
  	if (sel.dport)
582ee43da   Al Viro   net/* misc endian...
2421
  		sel.dport_mask = htons(0xffff);
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
  
  	rq = (struct sadb_x_ipsecrequest *)(pol + 1);
  
  	/* extract ipsecrequests */
  	i = 0;
  	len = pol->sadb_x_policy_len * 8 - sizeof(struct sadb_x_policy);
  
  	while (len > 0 && i < XFRM_MAX_DEPTH) {
  		ret = ipsecrequests_to_migrate(rq, len, &m[i]);
  		if (ret < 0) {
  			err = ret;
  			goto out;
  		} else {
  			rq = (struct sadb_x_ipsecrequest *)((u8 *)rq + ret);
  			len -= ret;
  			i++;
  		}
  	}
  
  	if (!i || len > 0) {
  		err = -EINVAL;
  		goto out;
  	}
13c1d1893   Arnaud Ebalard   xfrm: MIGRATE enh...
2445
2446
  	return xfrm_migrate(&sel, dir, XFRM_POLICY_TYPE_MAIN, m, i,
  			    kma ? &k : NULL);
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
2447
2448
2449
2450
2451
2452
  
   out:
  	return err;
  }
  #else
  static int pfkey_migrate(struct sock *sk, struct sk_buff *skb,
7f6daa635   Stephen Hemminger   pfkey: fix warning
2453
  			 const struct sadb_msg *hdr, void * const *ext_hdrs)
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
2454
2455
2456
2457
  {
  	return -ENOPROTOOPT;
  }
  #endif
4c93fbb06   David S. Miller   pfkey: Use const ...
2458
  static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2459
  {
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
2460
  	struct net *net = sock_net(sk);
77d8d7a68   Herbert Xu   [IPSEC]: Document...
2461
  	unsigned int dir;
215a2dd3b   Eric Paris   [IPSEC]: Add xfrm...
2462
  	int err = 0, delete;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2463
2464
  	struct sadb_x_policy *pol;
  	struct xfrm_policy *xp;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2465
  	struct km_event c;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2466
2467
2468
  
  	if ((pol = ext_hdrs[SADB_X_EXT_POLICY-1]) == NULL)
  		return -EINVAL;
77d8d7a68   Herbert Xu   [IPSEC]: Document...
2469
2470
2471
  	dir = xfrm_policy_id2dir(pol->sadb_x_policy_id);
  	if (dir >= XFRM_POLICY_MAX)
  		return -EINVAL;
215a2dd3b   Eric Paris   [IPSEC]: Add xfrm...
2472
  	delete = (hdr->sadb_msg_type == SADB_X_SPDDELETE2);
8ca2e93b5   Jamal Hadi Salim   xfrm: SP lookups ...
2473
  	xp = xfrm_policy_byid(net, DUMMY_MARK, XFRM_POLICY_TYPE_MAIN,
bd55775c8   Jamal Hadi Salim   xfrm: SA lookups ...
2474
  			      dir, pol->sadb_x_policy_id, delete, &err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2475
2476
  	if (xp == NULL)
  		return -ENOENT;
215a2dd3b   Eric Paris   [IPSEC]: Add xfrm...
2477
  	if (delete) {
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2478
  		xfrm_audit_policy_delete(xp, err ? 0 : 1,
2532386f4   Eric Paris   Audit: collect se...
2479
2480
  				audit_get_loginuid(current),
  				audit_get_sessionid(current), 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2481

215a2dd3b   Eric Paris   [IPSEC]: Add xfrm...
2482
2483
2484
2485
  		if (err)
  			goto out;
  		c.seq = hdr->sadb_msg_seq;
  		c.pid = hdr->sadb_msg_pid;
bf08867f9   Herbert Xu   [IPSEC] Turn km_e...
2486
  		c.data.byid = 1;
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
2487
  		c.event = XFRM_MSG_DELPOLICY;
77d8d7a68   Herbert Xu   [IPSEC]: Document...
2488
  		km_policy_notify(xp, dir, &c);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2489
  	} else {
77d8d7a68   Herbert Xu   [IPSEC]: Document...
2490
  		err = key_pol_get_resp(sk, xp, hdr, dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2491
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2492

215a2dd3b   Eric Paris   [IPSEC]: Add xfrm...
2493
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2494
2495
2496
2497
2498
2499
  	xfrm_pol_put(xp);
  	return err;
  }
  
  static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr)
  {
83321d6b9   Timo Teras   [AF_KEY]: Dump SA...
2500
  	struct pfkey_sock *pfk = ptr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2501
2502
  	struct sk_buff *out_skb;
  	struct sadb_msg *out_hdr;
55569ce25   Kazunori MIYAZAWA   [KEY]: Fix conver...
2503
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2504

83321d6b9   Timo Teras   [AF_KEY]: Dump SA...
2505
2506
  	if (!pfkey_can_dump(&pfk->sk))
  		return -ENOBUFS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2507
2508
2509
  	out_skb = pfkey_xfrm_policy2msg_prep(xp);
  	if (IS_ERR(out_skb))
  		return PTR_ERR(out_skb);
55569ce25   Kazunori MIYAZAWA   [KEY]: Fix conver...
2510
2511
2512
  	err = pfkey_xfrm_policy2msg(out_skb, xp, dir);
  	if (err < 0)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2513
2514
  
  	out_hdr = (struct sadb_msg *) out_skb->data;
83321d6b9   Timo Teras   [AF_KEY]: Dump SA...
2515
  	out_hdr->sadb_msg_version = pfk->dump.msg_version;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2516
2517
2518
  	out_hdr->sadb_msg_type = SADB_X_SPDDUMP;
  	out_hdr->sadb_msg_satype = SADB_SATYPE_UNSPEC;
  	out_hdr->sadb_msg_errno = 0;
12a169e7d   Herbert Xu   ipsec: Put dumper...
2519
  	out_hdr->sadb_msg_seq = count + 1;
83321d6b9   Timo Teras   [AF_KEY]: Dump SA...
2520
  	out_hdr->sadb_msg_pid = pfk->dump.msg_pid;
12a169e7d   Herbert Xu   ipsec: Put dumper...
2521
2522
2523
  
  	if (pfk->dump.skb)
  		pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE,
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
2524
  				&pfk->sk, sock_net(&pfk->sk));
12a169e7d   Herbert Xu   ipsec: Put dumper...
2525
  	pfk->dump.skb = out_skb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2526
2527
  	return 0;
  }
83321d6b9   Timo Teras   [AF_KEY]: Dump SA...
2528
2529
  static int pfkey_dump_sp(struct pfkey_sock *pfk)
  {
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
2530
2531
  	struct net *net = sock_net(&pfk->sk);
  	return xfrm_policy_walk(net, &pfk->dump.u.policy, dump_sp, (void *) pfk);
83321d6b9   Timo Teras   [AF_KEY]: Dump SA...
2532
2533
2534
2535
2536
2537
  }
  
  static void pfkey_dump_sp_done(struct pfkey_sock *pfk)
  {
  	xfrm_policy_walk_done(&pfk->dump.u.policy);
  }
4c93fbb06   David S. Miller   pfkey: Use const ...
2538
  static int pfkey_spddump(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2539
  {
83321d6b9   Timo Teras   [AF_KEY]: Dump SA...
2540
  	struct pfkey_sock *pfk = pfkey_sk(sk);
4c563f766   Timo Teras   [XFRM]: Speed up ...
2541

83321d6b9   Timo Teras   [AF_KEY]: Dump SA...
2542
2543
  	if (pfk->dump.dump != NULL)
  		return -EBUSY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2544

83321d6b9   Timo Teras   [AF_KEY]: Dump SA...
2545
2546
2547
2548
2549
2550
2551
  	pfk->dump.msg_version = hdr->sadb_msg_version;
  	pfk->dump.msg_pid = hdr->sadb_msg_pid;
  	pfk->dump.dump = pfkey_dump_sp;
  	pfk->dump.done = pfkey_dump_sp_done;
  	xfrm_policy_walk_init(&pfk->dump.u.policy, XFRM_POLICY_TYPE_MAIN);
  
  	return pfkey_do_dump(pfk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2552
  }
214e005bc   David S. Miller   xfrm: Pass km_eve...
2553
  static int key_notify_policy_flush(const struct km_event *c)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2554
2555
  {
  	struct sk_buff *skb_out;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2556
  	struct sadb_msg *hdr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2557

26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2558
  	skb_out = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2559
2560
  	if (!skb_out)
  		return -ENOBUFS;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2561
  	hdr = (struct sadb_msg *) skb_put(skb_out, sizeof(struct sadb_msg));
151bb0ffe   Jerome Borsboom   [AF_KEY]: no mess...
2562
  	hdr->sadb_msg_type = SADB_X_SPDFLUSH;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2563
2564
2565
2566
2567
  	hdr->sadb_msg_seq = c->seq;
  	hdr->sadb_msg_pid = c->pid;
  	hdr->sadb_msg_version = PF_KEY_V2;
  	hdr->sadb_msg_errno = (uint8_t) 0;
  	hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
2568
  	pfkey_broadcast(skb_out, GFP_ATOMIC, BROADCAST_ALL, NULL, c->net);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2569
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2570

26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2571
  }
4c93fbb06   David S. Miller   pfkey: Use const ...
2572
  static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs)
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2573
  {
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
2574
  	struct net *net = sock_net(sk);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2575
  	struct km_event c;
161a09e73   Joy Latten   audit: Add auditi...
2576
  	struct xfrm_audit audit_info;
8be987d73   Jamal Hadi Salim   pfkey: fix SA and...
2577
  	int err, err2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2578

0c11b9428   Al Viro   [PATCH] switch au...
2579
  	audit_info.loginuid = audit_get_loginuid(current);
2532386f4   Eric Paris   Audit: collect se...
2580
  	audit_info.sessionid = audit_get_sessionid(current);
161a09e73   Joy Latten   audit: Add auditi...
2581
  	audit_info.secid = 0;
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
2582
  	err = xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, &audit_info);
8be987d73   Jamal Hadi Salim   pfkey: fix SA and...
2583
  	err2 = unicast_flush_resp(sk, hdr);
2f1eb65f3   Jamal Hadi Salim   xfrm: Flushing em...
2584
2585
2586
2587
2588
  	if (err || err2) {
  		if (err == -ESRCH) /* empty table - old silent behavior */
  			return 0;
  		return err;
  	}
8be987d73   Jamal Hadi Salim   pfkey: fix SA and...
2589

f7b6983f0   Masahide NAKAMURA   [XFRM] POLICY: Su...
2590
  	c.data.type = XFRM_POLICY_TYPE_MAIN;
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
2591
  	c.event = XFRM_MSG_FLUSHPOLICY;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2592
2593
  	c.pid = hdr->sadb_msg_pid;
  	c.seq = hdr->sadb_msg_seq;
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
2594
  	c.net = net;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2595
  	km_policy_notify(NULL, 0, &c);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2596
2597
2598
2599
2600
  
  	return 0;
  }
  
  typedef int (*pfkey_handler)(struct sock *sk, struct sk_buff *skb,
4c93fbb06   David S. Miller   pfkey: Use const ...
2601
  			     const struct sadb_msg *hdr, void * const *ext_hdrs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
  static pfkey_handler pfkey_funcs[SADB_MAX + 1] = {
  	[SADB_RESERVED]		= pfkey_reserved,
  	[SADB_GETSPI]		= pfkey_getspi,
  	[SADB_UPDATE]		= pfkey_add,
  	[SADB_ADD]		= pfkey_add,
  	[SADB_DELETE]		= pfkey_delete,
  	[SADB_GET]		= pfkey_get,
  	[SADB_ACQUIRE]		= pfkey_acquire,
  	[SADB_REGISTER]		= pfkey_register,
  	[SADB_EXPIRE]		= NULL,
  	[SADB_FLUSH]		= pfkey_flush,
  	[SADB_DUMP]		= pfkey_dump,
  	[SADB_X_PROMISC]	= pfkey_promisc,
  	[SADB_X_PCHANGE]	= NULL,
  	[SADB_X_SPDUPDATE]	= pfkey_spdadd,
  	[SADB_X_SPDADD]		= pfkey_spdadd,
  	[SADB_X_SPDDELETE]	= pfkey_spddelete,
  	[SADB_X_SPDGET]		= pfkey_spdget,
  	[SADB_X_SPDACQUIRE]	= NULL,
  	[SADB_X_SPDDUMP]	= pfkey_spddump,
  	[SADB_X_SPDFLUSH]	= pfkey_spdflush,
  	[SADB_X_SPDSETIDX]	= pfkey_spdadd,
  	[SADB_X_SPDDELETE2]	= pfkey_spdget,
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
2625
  	[SADB_X_MIGRATE]	= pfkey_migrate,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2626
  };
4c93fbb06   David S. Miller   pfkey: Use const ...
2627
  static int pfkey_process(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2628
2629
2630
2631
2632
  {
  	void *ext_hdrs[SADB_EXT_MAX];
  	int err;
  
  	pfkey_broadcast(skb_clone(skb, GFP_KERNEL), GFP_KERNEL,
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
2633
  			BROADCAST_PROMISC_ONLY, NULL, sock_net(sk));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
  
  	memset(ext_hdrs, 0, sizeof(ext_hdrs));
  	err = parse_exthdrs(skb, hdr, ext_hdrs);
  	if (!err) {
  		err = -EOPNOTSUPP;
  		if (pfkey_funcs[hdr->sadb_msg_type])
  			err = pfkey_funcs[hdr->sadb_msg_type](sk, skb, hdr, ext_hdrs);
  	}
  	return err;
  }
  
  static struct sadb_msg *pfkey_get_base_msg(struct sk_buff *skb, int *errp)
  {
  	struct sadb_msg *hdr = NULL;
  
  	if (skb->len < sizeof(*hdr)) {
  		*errp = -EMSGSIZE;
  	} else {
  		hdr = (struct sadb_msg *) skb->data;
  		if (hdr->sadb_msg_version != PF_KEY_V2 ||
  		    hdr->sadb_msg_reserved != 0 ||
  		    (hdr->sadb_msg_type <= SADB_RESERVED ||
  		     hdr->sadb_msg_type > SADB_MAX)) {
  			hdr = NULL;
  			*errp = -EINVAL;
  		} else if (hdr->sadb_msg_len != (skb->len /
  						 sizeof(uint64_t)) ||
  			   hdr->sadb_msg_len < (sizeof(struct sadb_msg) /
  						sizeof(uint64_t))) {
  			hdr = NULL;
  			*errp = -EMSGSIZE;
  		} else {
  			*errp = 0;
  		}
  	}
  	return hdr;
  }
4c93fbb06   David S. Miller   pfkey: Use const ...
2671
2672
  static inline int aalg_tmpl_set(const struct xfrm_tmpl *t,
  				const struct xfrm_algo_desc *d)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2673
  {
f398035f2   Herbert Xu   [IPSEC]: Avoid un...
2674
2675
2676
2677
2678
2679
  	unsigned int id = d->desc.sadb_alg_id;
  
  	if (id >= sizeof(t->aalgos) * 8)
  		return 0;
  
  	return (t->aalgos >> id) & 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2680
  }
4c93fbb06   David S. Miller   pfkey: Use const ...
2681
2682
  static inline int ealg_tmpl_set(const struct xfrm_tmpl *t,
  				const struct xfrm_algo_desc *d)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2683
  {
f398035f2   Herbert Xu   [IPSEC]: Avoid un...
2684
2685
2686
2687
2688
2689
  	unsigned int id = d->desc.sadb_alg_id;
  
  	if (id >= sizeof(t->ealgos) * 8)
  		return 0;
  
  	return (t->ealgos >> id) & 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2690
  }
4c93fbb06   David S. Miller   pfkey: Use const ...
2691
  static int count_ah_combs(const struct xfrm_tmpl *t)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2692
2693
2694
2695
  {
  	int i, sz = 0;
  
  	for (i = 0; ; i++) {
4c93fbb06   David S. Miller   pfkey: Use const ...
2696
  		const struct xfrm_algo_desc *aalg = xfrm_aalg_get_byidx(i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2697
2698
2699
2700
2701
2702
2703
  		if (!aalg)
  			break;
  		if (aalg_tmpl_set(t, aalg) && aalg->available)
  			sz += sizeof(struct sadb_comb);
  	}
  	return sz + sizeof(struct sadb_prop);
  }
4c93fbb06   David S. Miller   pfkey: Use const ...
2704
  static int count_esp_combs(const struct xfrm_tmpl *t)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2705
2706
2707
2708
  {
  	int i, k, sz = 0;
  
  	for (i = 0; ; i++) {
4c93fbb06   David S. Miller   pfkey: Use const ...
2709
  		const struct xfrm_algo_desc *ealg = xfrm_ealg_get_byidx(i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2710
2711
  		if (!ealg)
  			break;
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
2712

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2713
2714
  		if (!(ealg_tmpl_set(t, ealg) && ealg->available))
  			continue;
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
2715

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2716
  		for (k = 1; ; k++) {
4c93fbb06   David S. Miller   pfkey: Use const ...
2717
  			const struct xfrm_algo_desc *aalg = xfrm_aalg_get_byidx(k);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2718
2719
  			if (!aalg)
  				break;
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
2720

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2721
2722
2723
2724
2725
2726
  			if (aalg_tmpl_set(t, aalg) && aalg->available)
  				sz += sizeof(struct sadb_comb);
  		}
  	}
  	return sz + sizeof(struct sadb_prop);
  }
4c93fbb06   David S. Miller   pfkey: Use const ...
2727
  static void dump_ah_combs(struct sk_buff *skb, const struct xfrm_tmpl *t)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
  {
  	struct sadb_prop *p;
  	int i;
  
  	p = (struct sadb_prop*)skb_put(skb, sizeof(struct sadb_prop));
  	p->sadb_prop_len = sizeof(struct sadb_prop)/8;
  	p->sadb_prop_exttype = SADB_EXT_PROPOSAL;
  	p->sadb_prop_replay = 32;
  	memset(p->sadb_prop_reserved, 0, sizeof(p->sadb_prop_reserved));
  
  	for (i = 0; ; i++) {
4c93fbb06   David S. Miller   pfkey: Use const ...
2739
  		const struct xfrm_algo_desc *aalg = xfrm_aalg_get_byidx(i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
  		if (!aalg)
  			break;
  
  		if (aalg_tmpl_set(t, aalg) && aalg->available) {
  			struct sadb_comb *c;
  			c = (struct sadb_comb*)skb_put(skb, sizeof(struct sadb_comb));
  			memset(c, 0, sizeof(*c));
  			p->sadb_prop_len += sizeof(struct sadb_comb)/8;
  			c->sadb_comb_auth = aalg->desc.sadb_alg_id;
  			c->sadb_comb_auth_minbits = aalg->desc.sadb_alg_minbits;
  			c->sadb_comb_auth_maxbits = aalg->desc.sadb_alg_maxbits;
  			c->sadb_comb_hard_addtime = 24*60*60;
  			c->sadb_comb_soft_addtime = 20*60*60;
  			c->sadb_comb_hard_usetime = 8*60*60;
  			c->sadb_comb_soft_usetime = 7*60*60;
  		}
  	}
  }
4c93fbb06   David S. Miller   pfkey: Use const ...
2758
  static void dump_esp_combs(struct sk_buff *skb, const struct xfrm_tmpl *t)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
  {
  	struct sadb_prop *p;
  	int i, k;
  
  	p = (struct sadb_prop*)skb_put(skb, sizeof(struct sadb_prop));
  	p->sadb_prop_len = sizeof(struct sadb_prop)/8;
  	p->sadb_prop_exttype = SADB_EXT_PROPOSAL;
  	p->sadb_prop_replay = 32;
  	memset(p->sadb_prop_reserved, 0, sizeof(p->sadb_prop_reserved));
  
  	for (i=0; ; i++) {
4c93fbb06   David S. Miller   pfkey: Use const ...
2770
  		const struct xfrm_algo_desc *ealg = xfrm_ealg_get_byidx(i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2771
2772
  		if (!ealg)
  			break;
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
2773

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2774
2775
  		if (!(ealg_tmpl_set(t, ealg) && ealg->available))
  			continue;
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
2776

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2777
2778
  		for (k = 1; ; k++) {
  			struct sadb_comb *c;
4c93fbb06   David S. Miller   pfkey: Use const ...
2779
  			const struct xfrm_algo_desc *aalg = xfrm_aalg_get_byidx(k);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
  			if (!aalg)
  				break;
  			if (!(aalg_tmpl_set(t, aalg) && aalg->available))
  				continue;
  			c = (struct sadb_comb*)skb_put(skb, sizeof(struct sadb_comb));
  			memset(c, 0, sizeof(*c));
  			p->sadb_prop_len += sizeof(struct sadb_comb)/8;
  			c->sadb_comb_auth = aalg->desc.sadb_alg_id;
  			c->sadb_comb_auth_minbits = aalg->desc.sadb_alg_minbits;
  			c->sadb_comb_auth_maxbits = aalg->desc.sadb_alg_maxbits;
  			c->sadb_comb_encrypt = ealg->desc.sadb_alg_id;
  			c->sadb_comb_encrypt_minbits = ealg->desc.sadb_alg_minbits;
  			c->sadb_comb_encrypt_maxbits = ealg->desc.sadb_alg_maxbits;
  			c->sadb_comb_hard_addtime = 24*60*60;
  			c->sadb_comb_soft_addtime = 20*60*60;
  			c->sadb_comb_hard_usetime = 8*60*60;
  			c->sadb_comb_soft_usetime = 7*60*60;
  		}
  	}
  }
214e005bc   David S. Miller   xfrm: Pass km_eve...
2800
  static int key_notify_policy_expire(struct xfrm_policy *xp, const struct km_event *c)
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2801
2802
2803
  {
  	return 0;
  }
214e005bc   David S. Miller   xfrm: Pass km_eve...
2804
  static int key_notify_sa_expire(struct xfrm_state *x, const struct km_event *c)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2805
2806
2807
  {
  	struct sk_buff *out_skb;
  	struct sadb_msg *out_hdr;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2808
2809
  	int hard;
  	int hsc;
bf08867f9   Herbert Xu   [IPSEC] Turn km_e...
2810
  	hard = c->data.hard;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2811
2812
2813
2814
  	if (hard)
  		hsc = 2;
  	else
  		hsc = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2815

050f009e1   Herbert Xu   [IPSEC]: Lock sta...
2816
  	out_skb = pfkey_xfrm_state2msg_expire(x, hsc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
  	if (IS_ERR(out_skb))
  		return PTR_ERR(out_skb);
  
  	out_hdr = (struct sadb_msg *) out_skb->data;
  	out_hdr->sadb_msg_version = PF_KEY_V2;
  	out_hdr->sadb_msg_type = SADB_EXPIRE;
  	out_hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto);
  	out_hdr->sadb_msg_errno = 0;
  	out_hdr->sadb_msg_reserved = 0;
  	out_hdr->sadb_msg_seq = 0;
  	out_hdr->sadb_msg_pid = 0;
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
2828
  	pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL, xs_net(x));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2829
2830
  	return 0;
  }
214e005bc   David S. Miller   xfrm: Pass km_eve...
2831
  static int pfkey_send_notify(struct xfrm_state *x, const struct km_event *c)
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2832
  {
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
2833
  	struct net *net = x ? xs_net(x) : c->net;
3fa87a321   Alexey Dobriyan   netns PF_KEY: part 1
2834
2835
2836
  	struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
  
  	if (atomic_read(&net_pfkey->socks_nr) == 0)
99c6f60e7   Jamal Hadi Salim   ipsec: pfkey shou...
2837
  		return 0;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2838
  	switch (c->event) {
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
2839
  	case XFRM_MSG_EXPIRE:
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2840
  		return key_notify_sa_expire(x, c);
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
2841
2842
2843
  	case XFRM_MSG_DELSA:
  	case XFRM_MSG_NEWSA:
  	case XFRM_MSG_UPDSA:
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2844
  		return key_notify_sa(x, c);
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
2845
  	case XFRM_MSG_FLUSHSA:
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2846
  		return key_notify_sa_flush(c);
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
2847
2848
  	case XFRM_MSG_NEWAE: /* not yet supported */
  		break;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2849
  	default:
207024b94   stephen hemminger   pfkey: add severi...
2850
2851
  		pr_err("pfkey: Unknown SA event %d
  ", c->event);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2852
2853
2854
2855
2856
  		break;
  	}
  
  	return 0;
  }
214e005bc   David S. Miller   xfrm: Pass km_eve...
2857
  static int pfkey_send_policy_notify(struct xfrm_policy *xp, int dir, const struct km_event *c)
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2858
  {
f7b6983f0   Masahide NAKAMURA   [XFRM] POLICY: Su...
2859
2860
  	if (xp && xp->type != XFRM_POLICY_TYPE_MAIN)
  		return 0;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2861
  	switch (c->event) {
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
2862
  	case XFRM_MSG_POLEXPIRE:
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2863
  		return key_notify_policy_expire(xp, c);
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
2864
2865
2866
  	case XFRM_MSG_DELPOLICY:
  	case XFRM_MSG_NEWPOLICY:
  	case XFRM_MSG_UPDPOLICY:
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2867
  		return key_notify_policy(xp, dir, c);
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
2868
  	case XFRM_MSG_FLUSHPOLICY:
f7b6983f0   Masahide NAKAMURA   [XFRM] POLICY: Su...
2869
2870
  		if (c->data.type != XFRM_POLICY_TYPE_MAIN)
  			break;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2871
2872
  		return key_notify_policy_flush(c);
  	default:
207024b94   stephen hemminger   pfkey: add severi...
2873
2874
  		pr_err("pfkey: Unknown policy event %d
  ", c->event);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2875
2876
2877
2878
2879
  		break;
  	}
  
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2880
2881
2882
  static u32 get_acqseq(void)
  {
  	u32 res;
28aecb9d7   Eric Dumazet   xfrm: avoid spinl...
2883
  	static atomic_t acqseq;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2884

28aecb9d7   Eric Dumazet   xfrm: avoid spinl...
2885
2886
2887
  	do {
  		res = atomic_inc_return(&acqseq);
  	} while (!res);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2888
2889
2890
2891
2892
2893
2894
2895
2896
  	return res;
  }
  
  static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *xp, int dir)
  {
  	struct sk_buff *skb;
  	struct sadb_msg *hdr;
  	struct sadb_address *addr;
  	struct sadb_x_policy *pol;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2897
2898
  	int sockaddr_size;
  	int size;
4e2ba18ea   Venkat Yekkirala   [MLSXFRM]: Add se...
2899
2900
2901
  	struct sadb_x_sec_ctx *sec_ctx;
  	struct xfrm_sec_ctx *xfrm_ctx;
  	int ctx_size = 0;
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
2902

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2903
2904
2905
2906
2907
2908
2909
2910
  	sockaddr_size = pfkey_sockaddr_size(x->props.family);
  	if (!sockaddr_size)
  		return -EINVAL;
  
  	size = sizeof(struct sadb_msg) +
  		(sizeof(struct sadb_address) * 2) +
  		(sockaddr_size * 2) +
  		sizeof(struct sadb_x_policy);
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
2911

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2912
2913
2914
2915
  	if (x->id.proto == IPPROTO_AH)
  		size += count_ah_combs(t);
  	else if (x->id.proto == IPPROTO_ESP)
  		size += count_esp_combs(t);
4e2ba18ea   Venkat Yekkirala   [MLSXFRM]: Add se...
2916
2917
2918
2919
  	if ((xfrm_ctx = x->security)) {
  		ctx_size = PFKEY_ALIGN8(xfrm_ctx->ctx_len);
  		size +=  sizeof(struct sadb_x_sec_ctx) + ctx_size;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2920
2921
2922
  	skb =  alloc_skb(size + 16, GFP_ATOMIC);
  	if (skb == NULL)
  		return -ENOMEM;
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
2923

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
  	hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg));
  	hdr->sadb_msg_version = PF_KEY_V2;
  	hdr->sadb_msg_type = SADB_ACQUIRE;
  	hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto);
  	hdr->sadb_msg_len = size / sizeof(uint64_t);
  	hdr->sadb_msg_errno = 0;
  	hdr->sadb_msg_reserved = 0;
  	hdr->sadb_msg_seq = x->km.seq = get_acqseq();
  	hdr->sadb_msg_pid = 0;
  
  	/* src address */
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
2935
  	addr = (struct sadb_address*) skb_put(skb,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2936
  					      sizeof(struct sadb_address)+sockaddr_size);
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
2937
  	addr->sadb_address_len =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2938
2939
2940
2941
2942
  		(sizeof(struct sadb_address)+sockaddr_size)/
  			sizeof(uint64_t);
  	addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
  	addr->sadb_address_proto = 0;
  	addr->sadb_address_reserved = 0;
e5b56652c   YOSHIFUJI Hideaki   key: Share common...
2943
2944
2945
2946
2947
  	addr->sadb_address_prefixlen =
  		pfkey_sockaddr_fill(&x->props.saddr, 0,
  				    (struct sockaddr *) (addr + 1),
  				    x->props.family);
  	if (!addr->sadb_address_prefixlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2948
  		BUG();
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
2949

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2950
  	/* dst address */
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
2951
  	addr = (struct sadb_address*) skb_put(skb,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2952
2953
2954
2955
2956
2957
2958
  					      sizeof(struct sadb_address)+sockaddr_size);
  	addr->sadb_address_len =
  		(sizeof(struct sadb_address)+sockaddr_size)/
  			sizeof(uint64_t);
  	addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
  	addr->sadb_address_proto = 0;
  	addr->sadb_address_reserved = 0;
e5b56652c   YOSHIFUJI Hideaki   key: Share common...
2959
2960
2961
2962
2963
  	addr->sadb_address_prefixlen =
  		pfkey_sockaddr_fill(&x->id.daddr, 0,
  				    (struct sockaddr *) (addr + 1),
  				    x->props.family);
  	if (!addr->sadb_address_prefixlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
  		BUG();
  
  	pol = (struct sadb_x_policy *)  skb_put(skb, sizeof(struct sadb_x_policy));
  	pol->sadb_x_policy_len = sizeof(struct sadb_x_policy)/sizeof(uint64_t);
  	pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
  	pol->sadb_x_policy_type = IPSEC_POLICY_IPSEC;
  	pol->sadb_x_policy_dir = dir+1;
  	pol->sadb_x_policy_id = xp->index;
  
  	/* Set sadb_comb's. */
  	if (x->id.proto == IPPROTO_AH)
  		dump_ah_combs(skb, t);
  	else if (x->id.proto == IPPROTO_ESP)
  		dump_esp_combs(skb, t);
4e2ba18ea   Venkat Yekkirala   [MLSXFRM]: Add se...
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
  	/* security context */
  	if (xfrm_ctx) {
  		sec_ctx = (struct sadb_x_sec_ctx *) skb_put(skb,
  				sizeof(struct sadb_x_sec_ctx) + ctx_size);
  		sec_ctx->sadb_x_sec_len =
  		  (sizeof(struct sadb_x_sec_ctx) + ctx_size) / sizeof(uint64_t);
  		sec_ctx->sadb_x_sec_exttype = SADB_X_EXT_SEC_CTX;
  		sec_ctx->sadb_x_ctx_doi = xfrm_ctx->ctx_doi;
  		sec_ctx->sadb_x_ctx_alg = xfrm_ctx->ctx_alg;
  		sec_ctx->sadb_x_ctx_len = xfrm_ctx->ctx_len;
  		memcpy(sec_ctx + 1, xfrm_ctx->ctx_str,
  		       xfrm_ctx->ctx_len);
  	}
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
2991
  	return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL, xs_net(x));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2992
  }
cb969f072   Venkat Yekkirala   [MLSXFRM]: Defaul...
2993
  static struct xfrm_policy *pfkey_compile_policy(struct sock *sk, int opt,
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
2994
  						u8 *data, int len, int *dir)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2995
  {
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
2996
  	struct net *net = sock_net(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2997
2998
  	struct xfrm_policy *xp;
  	struct sadb_x_policy *pol = (struct sadb_x_policy*)data;
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
2999
  	struct sadb_x_sec_ctx *sec_ctx;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3000

cb969f072   Venkat Yekkirala   [MLSXFRM]: Defaul...
3001
  	switch (sk->sk_family) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3002
3003
3004
3005
3006
3007
  	case AF_INET:
  		if (opt != IP_IPSEC_POLICY) {
  			*dir = -EOPNOTSUPP;
  			return NULL;
  		}
  		break;
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
3008
  #if IS_ENABLED(CONFIG_IPV6)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
  	case AF_INET6:
  		if (opt != IPV6_IPSEC_POLICY) {
  			*dir = -EOPNOTSUPP;
  			return NULL;
  		}
  		break;
  #endif
  	default:
  		*dir = -EINVAL;
  		return NULL;
  	}
  
  	*dir = -EINVAL;
  
  	if (len < sizeof(struct sadb_x_policy) ||
  	    pol->sadb_x_policy_len*8 > len ||
  	    pol->sadb_x_policy_type > IPSEC_POLICY_BYPASS ||
  	    (!pol->sadb_x_policy_dir || pol->sadb_x_policy_dir > IPSEC_DIR_OUTBOUND))
  		return NULL;
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
3028
  	xp = xfrm_policy_alloc(net, GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
  	if (xp == NULL) {
  		*dir = -ENOBUFS;
  		return NULL;
  	}
  
  	xp->action = (pol->sadb_x_policy_type == IPSEC_POLICY_DISCARD ?
  		      XFRM_POLICY_BLOCK : XFRM_POLICY_ALLOW);
  
  	xp->lft.soft_byte_limit = XFRM_INF;
  	xp->lft.hard_byte_limit = XFRM_INF;
  	xp->lft.soft_packet_limit = XFRM_INF;
  	xp->lft.hard_packet_limit = XFRM_INF;
cb969f072   Venkat Yekkirala   [MLSXFRM]: Defaul...
3041
  	xp->family = sk->sk_family;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3042
3043
3044
3045
3046
  
  	xp->xfrm_nr = 0;
  	if (pol->sadb_x_policy_type == IPSEC_POLICY_IPSEC &&
  	    (*dir = parse_ipsecrequests(xp, pol)) < 0)
  		goto out;
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
3047
3048
3049
3050
3051
3052
3053
3054
3055
  	/* security context too */
  	if (len >= (pol->sadb_x_policy_len*8 +
  	    sizeof(struct sadb_x_sec_ctx))) {
  		char *p = (char *)pol;
  		struct xfrm_user_sec_ctx *uctx;
  
  		p += pol->sadb_x_policy_len*8;
  		sec_ctx = (struct sadb_x_sec_ctx *)p;
  		if (len < pol->sadb_x_policy_len*8 +
cb969f072   Venkat Yekkirala   [MLSXFRM]: Defaul...
3056
3057
  		    sec_ctx->sadb_x_sec_len) {
  			*dir = -EINVAL;
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
3058
  			goto out;
cb969f072   Venkat Yekkirala   [MLSXFRM]: Defaul...
3059
  		}
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
3060
3061
3062
  		if ((*dir = verify_sec_ctx_len(p)))
  			goto out;
  		uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx);
03e1ad7b5   Paul Moore   LSM: Make the Lab...
3063
  		*dir = security_xfrm_policy_alloc(&xp->security, uctx);
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
3064
3065
3066
3067
3068
  		kfree(uctx);
  
  		if (*dir)
  			goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3069
3070
3071
3072
  	*dir = pol->sadb_x_policy_dir-1;
  	return xp;
  
  out:
70e90679f   Alexey Dobriyan   af_key: mark poli...
3073
  	xp->walk.dead = 1;
64c31b3f7   WANG Cong   [XFRM] xfrm_polic...
3074
  	xfrm_policy_destroy(xp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3075
3076
  	return NULL;
  }
5d36b1803   Al Viro   [XFRM]: annotate ...
3077
  static int pfkey_send_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3078
3079
3080
3081
3082
3083
  {
  	struct sk_buff *skb;
  	struct sadb_msg *hdr;
  	struct sadb_sa *sa;
  	struct sadb_address *addr;
  	struct sadb_x_nat_t_port *n_port;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
  	int sockaddr_size;
  	int size;
  	__u8 satype = (x->id.proto == IPPROTO_ESP ? SADB_SATYPE_ESP : 0);
  	struct xfrm_encap_tmpl *natt = NULL;
  
  	sockaddr_size = pfkey_sockaddr_size(x->props.family);
  	if (!sockaddr_size)
  		return -EINVAL;
  
  	if (!satype)
  		return -EINVAL;
  
  	if (!x->encap)
  		return -EINVAL;
  
  	natt = x->encap;
  
  	/* Build an SADB_X_NAT_T_NEW_MAPPING message:
  	 *
  	 * HDR | SA | ADDRESS_SRC (old addr) | NAT_T_SPORT (old port) |
  	 * ADDRESS_DST (new addr) | NAT_T_DPORT (new port)
  	 */
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
3106

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3107
3108
3109
3110
3111
  	size = sizeof(struct sadb_msg) +
  		sizeof(struct sadb_sa) +
  		(sizeof(struct sadb_address) * 2) +
  		(sockaddr_size * 2) +
  		(sizeof(struct sadb_x_nat_t_port) * 2);
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
3112

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3113
3114
3115
  	skb =  alloc_skb(size + 16, GFP_ATOMIC);
  	if (skb == NULL)
  		return -ENOMEM;
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
3116

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
  	hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg));
  	hdr->sadb_msg_version = PF_KEY_V2;
  	hdr->sadb_msg_type = SADB_X_NAT_T_NEW_MAPPING;
  	hdr->sadb_msg_satype = satype;
  	hdr->sadb_msg_len = size / sizeof(uint64_t);
  	hdr->sadb_msg_errno = 0;
  	hdr->sadb_msg_reserved = 0;
  	hdr->sadb_msg_seq = x->km.seq = get_acqseq();
  	hdr->sadb_msg_pid = 0;
  
  	/* SA */
  	sa = (struct sadb_sa *) skb_put(skb, sizeof(struct sadb_sa));
  	sa->sadb_sa_len = sizeof(struct sadb_sa)/sizeof(uint64_t);
  	sa->sadb_sa_exttype = SADB_EXT_SA;
  	sa->sadb_sa_spi = x->id.spi;
  	sa->sadb_sa_replay = 0;
  	sa->sadb_sa_state = 0;
  	sa->sadb_sa_auth = 0;
  	sa->sadb_sa_encrypt = 0;
  	sa->sadb_sa_flags = 0;
  
  	/* ADDRESS_SRC (old addr) */
  	addr = (struct sadb_address*)
  		skb_put(skb, sizeof(struct sadb_address)+sockaddr_size);
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
3141
  	addr->sadb_address_len =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3142
3143
3144
3145
3146
  		(sizeof(struct sadb_address)+sockaddr_size)/
  			sizeof(uint64_t);
  	addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
  	addr->sadb_address_proto = 0;
  	addr->sadb_address_reserved = 0;
e5b56652c   YOSHIFUJI Hideaki   key: Share common...
3147
3148
3149
3150
3151
  	addr->sadb_address_prefixlen =
  		pfkey_sockaddr_fill(&x->props.saddr, 0,
  				    (struct sockaddr *) (addr + 1),
  				    x->props.family);
  	if (!addr->sadb_address_prefixlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
  		BUG();
  
  	/* NAT_T_SPORT (old port) */
  	n_port = (struct sadb_x_nat_t_port*) skb_put(skb, sizeof (*n_port));
  	n_port->sadb_x_nat_t_port_len = sizeof(*n_port)/sizeof(uint64_t);
  	n_port->sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_SPORT;
  	n_port->sadb_x_nat_t_port_port = natt->encap_sport;
  	n_port->sadb_x_nat_t_port_reserved = 0;
  
  	/* ADDRESS_DST (new addr) */
  	addr = (struct sadb_address*)
  		skb_put(skb, sizeof(struct sadb_address)+sockaddr_size);
8ff24541d   YOSHIFUJI Hideaki   [NET] KEY: Fix wh...
3164
  	addr->sadb_address_len =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3165
3166
3167
3168
3169
  		(sizeof(struct sadb_address)+sockaddr_size)/
  			sizeof(uint64_t);
  	addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
  	addr->sadb_address_proto = 0;
  	addr->sadb_address_reserved = 0;
e5b56652c   YOSHIFUJI Hideaki   key: Share common...
3170
3171
3172
3173
3174
  	addr->sadb_address_prefixlen =
  		pfkey_sockaddr_fill(ipaddr, 0,
  				    (struct sockaddr *) (addr + 1),
  				    x->props.family);
  	if (!addr->sadb_address_prefixlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3175
3176
3177
3178
3179
3180
3181
3182
  		BUG();
  
  	/* NAT_T_DPORT (new port) */
  	n_port = (struct sadb_x_nat_t_port*) skb_put(skb, sizeof (*n_port));
  	n_port->sadb_x_nat_t_port_len = sizeof(*n_port)/sizeof(uint64_t);
  	n_port->sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_DPORT;
  	n_port->sadb_x_nat_t_port_port = sport;
  	n_port->sadb_x_nat_t_port_reserved = 0;
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
3183
  	return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL, xs_net(x));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3184
  }
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
3185
3186
  #ifdef CONFIG_NET_KEY_MIGRATE
  static int set_sadb_address(struct sk_buff *skb, int sasize, int type,
183cad127   David S. Miller   xfrm: Const'ify p...
3187
  			    const struct xfrm_selector *sel)
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
3188
3189
  {
  	struct sadb_address *addr;
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
3190
3191
3192
3193
3194
3195
3196
3197
  	addr = (struct sadb_address *)skb_put(skb, sizeof(struct sadb_address) + sasize);
  	addr->sadb_address_len = (sizeof(struct sadb_address) + sasize)/8;
  	addr->sadb_address_exttype = type;
  	addr->sadb_address_proto = sel->proto;
  	addr->sadb_address_reserved = 0;
  
  	switch (type) {
  	case SADB_EXT_ADDRESS_SRC:
e5b56652c   YOSHIFUJI Hideaki   key: Share common...
3198
3199
3200
3201
  		addr->sadb_address_prefixlen = sel->prefixlen_s;
  		pfkey_sockaddr_fill(&sel->saddr, 0,
  				    (struct sockaddr *)(addr + 1),
  				    sel->family);
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
3202
3203
  		break;
  	case SADB_EXT_ADDRESS_DST:
e5b56652c   YOSHIFUJI Hideaki   key: Share common...
3204
3205
3206
3207
  		addr->sadb_address_prefixlen = sel->prefixlen_d;
  		pfkey_sockaddr_fill(&sel->daddr, 0,
  				    (struct sockaddr *)(addr + 1),
  				    sel->family);
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
3208
3209
3210
3211
3212
3213
3214
  		break;
  	default:
  		return -EINVAL;
  	}
  
  	return 0;
  }
13c1d1893   Arnaud Ebalard   xfrm: MIGRATE enh...
3215

183cad127   David S. Miller   xfrm: Const'ify p...
3216
  static int set_sadb_kmaddress(struct sk_buff *skb, const struct xfrm_kmaddress *k)
13c1d1893   Arnaud Ebalard   xfrm: MIGRATE enh...
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
  {
  	struct sadb_x_kmaddress *kma;
  	u8 *sa;
  	int family = k->family;
  	int socklen = pfkey_sockaddr_len(family);
  	int size_req;
  
  	size_req = (sizeof(struct sadb_x_kmaddress) +
  		    pfkey_sockaddr_pair_size(family));
  
  	kma = (struct sadb_x_kmaddress *)skb_put(skb, size_req);
  	memset(kma, 0, size_req);
  	kma->sadb_x_kmaddress_len = size_req / 8;
  	kma->sadb_x_kmaddress_exttype = SADB_X_EXT_KMADDRESS;
  	kma->sadb_x_kmaddress_reserved = k->reserved;
  
  	sa = (u8 *)(kma + 1);
  	if (!pfkey_sockaddr_fill(&k->local, 0, (struct sockaddr *)sa, family) ||
  	    !pfkey_sockaddr_fill(&k->remote, 0, (struct sockaddr *)(sa+socklen), family))
  		return -EINVAL;
  
  	return 0;
  }
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
3240
3241
3242
  static int set_ipsecrequest(struct sk_buff *skb,
  			    uint8_t proto, uint8_t mode, int level,
  			    uint32_t reqid, uint8_t family,
183cad127   David S. Miller   xfrm: Const'ify p...
3243
  			    const xfrm_address_t *src, const xfrm_address_t *dst)
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
3244
3245
  {
  	struct sadb_x_ipsecrequest *rq;
e5b56652c   YOSHIFUJI Hideaki   key: Share common...
3246
3247
  	u8 *sa;
  	int socklen = pfkey_sockaddr_len(family);
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
  	int size_req;
  
  	size_req = sizeof(struct sadb_x_ipsecrequest) +
  		   pfkey_sockaddr_pair_size(family);
  
  	rq = (struct sadb_x_ipsecrequest *)skb_put(skb, size_req);
  	memset(rq, 0, size_req);
  	rq->sadb_x_ipsecrequest_len = size_req;
  	rq->sadb_x_ipsecrequest_proto = proto;
  	rq->sadb_x_ipsecrequest_mode = mode;
  	rq->sadb_x_ipsecrequest_level = level;
  	rq->sadb_x_ipsecrequest_reqid = reqid;
e5b56652c   YOSHIFUJI Hideaki   key: Share common...
3260
3261
3262
  	sa = (u8 *) (rq + 1);
  	if (!pfkey_sockaddr_fill(src, 0, (struct sockaddr *)sa, family) ||
  	    !pfkey_sockaddr_fill(dst, 0, (struct sockaddr *)(sa + socklen), family))
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
3263
  		return -EINVAL;
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
3264
3265
3266
3267
3268
3269
  
  	return 0;
  }
  #endif
  
  #ifdef CONFIG_NET_KEY_MIGRATE
183cad127   David S. Miller   xfrm: Const'ify p...
3270
3271
3272
  static int pfkey_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
  			      const struct xfrm_migrate *m, int num_bundles,
  			      const struct xfrm_kmaddress *k)
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
3273
3274
3275
3276
3277
3278
3279
3280
  {
  	int i;
  	int sasize_sel;
  	int size = 0;
  	int size_pol = 0;
  	struct sk_buff *skb;
  	struct sadb_msg *hdr;
  	struct sadb_x_policy *pol;
183cad127   David S. Miller   xfrm: Const'ify p...
3281
  	const struct xfrm_migrate *mp;
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
3282
3283
3284
3285
3286
3287
  
  	if (type != XFRM_POLICY_TYPE_MAIN)
  		return 0;
  
  	if (num_bundles <= 0 || num_bundles > XFRM_MAX_DEPTH)
  		return -EINVAL;
13c1d1893   Arnaud Ebalard   xfrm: MIGRATE enh...
3288
3289
3290
3291
3292
  	if (k != NULL) {
  		/* addresses for KM */
  		size += PFKEY_ALIGN8(sizeof(struct sadb_x_kmaddress) +
  				     pfkey_sockaddr_pair_size(k->family));
  	}
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
  	/* selector */
  	sasize_sel = pfkey_sockaddr_size(sel->family);
  	if (!sasize_sel)
  		return -EINVAL;
  	size += (sizeof(struct sadb_address) + sasize_sel) * 2;
  
  	/* policy info */
  	size_pol += sizeof(struct sadb_x_policy);
  
  	/* ipsecrequests */
  	for (i = 0, mp = m; i < num_bundles; i++, mp++) {
  		/* old locator pair */
  		size_pol += sizeof(struct sadb_x_ipsecrequest) +
  			    pfkey_sockaddr_pair_size(mp->old_family);
  		/* new locator pair */
  		size_pol += sizeof(struct sadb_x_ipsecrequest) +
  			    pfkey_sockaddr_pair_size(mp->new_family);
  	}
  
  	size += sizeof(struct sadb_msg) + size_pol;
  
  	/* alloc buffer */
  	skb = alloc_skb(size, GFP_ATOMIC);
  	if (skb == NULL)
  		return -ENOMEM;
  
  	hdr = (struct sadb_msg *)skb_put(skb, sizeof(struct sadb_msg));
  	hdr->sadb_msg_version = PF_KEY_V2;
  	hdr->sadb_msg_type = SADB_X_MIGRATE;
  	hdr->sadb_msg_satype = pfkey_proto2satype(m->proto);
  	hdr->sadb_msg_len = size / 8;
  	hdr->sadb_msg_errno = 0;
  	hdr->sadb_msg_reserved = 0;
  	hdr->sadb_msg_seq = 0;
  	hdr->sadb_msg_pid = 0;
13c1d1893   Arnaud Ebalard   xfrm: MIGRATE enh...
3328
3329
3330
  	/* Addresses to be used by KM for negotiation, if ext is available */
  	if (k != NULL && (set_sadb_kmaddress(skb, k) < 0))
  		return -EINVAL;
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
  	/* selector src */
  	set_sadb_address(skb, sasize_sel, SADB_EXT_ADDRESS_SRC, sel);
  
  	/* selector dst */
  	set_sadb_address(skb, sasize_sel, SADB_EXT_ADDRESS_DST, sel);
  
  	/* policy information */
  	pol = (struct sadb_x_policy *)skb_put(skb, sizeof(struct sadb_x_policy));
  	pol->sadb_x_policy_len = size_pol / 8;
  	pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
  	pol->sadb_x_policy_type = IPSEC_POLICY_IPSEC;
  	pol->sadb_x_policy_dir = dir + 1;
  	pol->sadb_x_policy_id = 0;
  	pol->sadb_x_policy_priority = 0;
  
  	for (i = 0, mp = m; i < num_bundles; i++, mp++) {
  		/* old ipsecrequest */
55569ce25   Kazunori MIYAZAWA   [KEY]: Fix conver...
3348
3349
  		int mode = pfkey_mode_from_xfrm(mp->mode);
  		if (mode < 0)
d4782c323   Patrick McHardy   [AF_KEY]: Fix skb...
3350
  			goto err;
55569ce25   Kazunori MIYAZAWA   [KEY]: Fix conver...
3351
  		if (set_ipsecrequest(skb, mp->proto, mode,
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
3352
3353
  				     (mp->reqid ?  IPSEC_LEVEL_UNIQUE : IPSEC_LEVEL_REQUIRE),
  				     mp->reqid, mp->old_family,
d4782c323   Patrick McHardy   [AF_KEY]: Fix skb...
3354
3355
  				     &mp->old_saddr, &mp->old_daddr) < 0)
  			goto err;
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
3356
3357
  
  		/* new ipsecrequest */
55569ce25   Kazunori MIYAZAWA   [KEY]: Fix conver...
3358
  		if (set_ipsecrequest(skb, mp->proto, mode,
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
3359
3360
  				     (mp->reqid ? IPSEC_LEVEL_UNIQUE : IPSEC_LEVEL_REQUIRE),
  				     mp->reqid, mp->new_family,
d4782c323   Patrick McHardy   [AF_KEY]: Fix skb...
3361
3362
  				     &mp->new_saddr, &mp->new_daddr) < 0)
  			goto err;
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
3363
3364
3365
  	}
  
  	/* broadcast migrate message to sockets */
07fb0f179   Alexey Dobriyan   netns PF_KEY: part 2
3366
  	pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL, &init_net);
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
3367
3368
  
  	return 0;
d4782c323   Patrick McHardy   [AF_KEY]: Fix skb...
3369
3370
3371
3372
  
  err:
  	kfree_skb(skb);
  	return -EINVAL;
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
3373
3374
  }
  #else
183cad127   David S. Miller   xfrm: Const'ify p...
3375
3376
3377
  static int pfkey_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
  			      const struct xfrm_migrate *m, int num_bundles,
  			      const struct xfrm_kmaddress *k)
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
3378
3379
3380
3381
  {
  	return -ENOPROTOOPT;
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
  static int pfkey_sendmsg(struct kiocb *kiocb,
  			 struct socket *sock, struct msghdr *msg, size_t len)
  {
  	struct sock *sk = sock->sk;
  	struct sk_buff *skb = NULL;
  	struct sadb_msg *hdr = NULL;
  	int err;
  
  	err = -EOPNOTSUPP;
  	if (msg->msg_flags & MSG_OOB)
  		goto out;
  
  	err = -EMSGSIZE;
  	if ((unsigned)len > sk->sk_sndbuf - 32)
  		goto out;
  
  	err = -ENOBUFS;
  	skb = alloc_skb(len, GFP_KERNEL);
  	if (skb == NULL)
  		goto out;
  
  	err = -EFAULT;
  	if (memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len))
  		goto out;
  
  	hdr = pfkey_get_base_msg(skb, &err);
  	if (!hdr)
  		goto out;
4a3e2f711   Arjan van de Ven   [NET] sem2mutex: ...
3410
  	mutex_lock(&xfrm_cfg_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3411
  	err = pfkey_process(sk, skb, hdr);
4a3e2f711   Arjan van de Ven   [NET] sem2mutex: ...
3412
  	mutex_unlock(&xfrm_cfg_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3413
3414
3415
3416
  
  out:
  	if (err && hdr && pfkey_error(hdr, err, sk) == 0)
  		err = 0;
6f9610686   Wei Yongjun   af_key: remove so...
3417
  	kfree_skb(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3418
3419
3420
3421
3422
3423
3424
3425
3426
  
  	return err ? : len;
  }
  
  static int pfkey_recvmsg(struct kiocb *kiocb,
  			 struct socket *sock, struct msghdr *msg, size_t len,
  			 int flags)
  {
  	struct sock *sk = sock->sk;
83321d6b9   Timo Teras   [AF_KEY]: Dump SA...
3427
  	struct pfkey_sock *pfk = pfkey_sk(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
  	struct sk_buff *skb;
  	int copied, err;
  
  	err = -EINVAL;
  	if (flags & ~(MSG_PEEK|MSG_DONTWAIT|MSG_TRUNC|MSG_CMSG_COMPAT))
  		goto out;
  
  	msg->msg_namelen = 0;
  	skb = skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &err);
  	if (skb == NULL)
  		goto out;
  
  	copied = skb->len;
  	if (copied > len) {
  		msg->msg_flags |= MSG_TRUNC;
  		copied = len;
  	}
badff6d01   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
3445
  	skb_reset_transport_header(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3446
3447
3448
  	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
  	if (err)
  		goto out_free;
3b885787e   Neil Horman   net: Generalize s...
3449
  	sock_recv_ts_and_drops(msg, sk, skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3450
3451
  
  	err = (flags & MSG_TRUNC) ? skb->len : copied;
83321d6b9   Timo Teras   [AF_KEY]: Dump SA...
3452
3453
3454
  	if (pfk->dump.dump != NULL &&
  	    3 * atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf)
  		pfkey_do_dump(pfk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3455
3456
3457
3458
3459
  out_free:
  	skb_free_datagram(sk, skb);
  out:
  	return err;
  }
90ddc4f04   Eric Dumazet   [NET]: move struc...
3460
  static const struct proto_ops pfkey_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
  	.family		=	PF_KEY,
  	.owner		=	THIS_MODULE,
  	/* Operations that make no sense on pfkey sockets. */
  	.bind		=	sock_no_bind,
  	.connect	=	sock_no_connect,
  	.socketpair	=	sock_no_socketpair,
  	.accept		=	sock_no_accept,
  	.getname	=	sock_no_getname,
  	.ioctl		=	sock_no_ioctl,
  	.listen		=	sock_no_listen,
  	.shutdown	=	sock_no_shutdown,
  	.setsockopt	=	sock_no_setsockopt,
  	.getsockopt	=	sock_no_getsockopt,
  	.mmap		=	sock_no_mmap,
  	.sendpage	=	sock_no_sendpage,
  
  	/* Now the operations that really occur. */
  	.release	=	pfkey_release,
  	.poll		=	datagram_poll,
  	.sendmsg	=	pfkey_sendmsg,
  	.recvmsg	=	pfkey_recvmsg,
  };
ec1b4cf74   Stephen Hemminger   net: mark net_pro...
3483
  static const struct net_proto_family pfkey_family_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3484
3485
3486
3487
3488
3489
  	.family	=	PF_KEY,
  	.create	=	pfkey_create,
  	.owner	=	THIS_MODULE,
  };
  
  #ifdef CONFIG_PROC_FS
bd2f74765   Pavel Emelyanov   [KEY]: Convert ne...
3490
  static int pfkey_seq_show(struct seq_file *f, void *v)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3491
  {
27b5b8657   Li Zefan   net: af_key: use ...
3492
  	struct sock *s = sk_entry(v);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3493

bd2f74765   Pavel Emelyanov   [KEY]: Convert ne...
3494
3495
3496
3497
  	if (v == SEQ_START_TOKEN)
  		seq_printf(f ,"sk       RefCnt Rmem   Wmem   User   Inode
  ");
  	else
71338aa7d   Dan Rosenberg   net: convert %p u...
3498
3499
  		seq_printf(f, "%pK %-6d %-6u %-6u %-6u %-6lu
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3500
3501
  			       s,
  			       atomic_read(&s->sk_refcnt),
31e6d363a   Eric Dumazet   net: correct off-...
3502
3503
  			       sk_rmem_alloc_get(s),
  			       sk_wmem_alloc_get(s),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3504
3505
3506
  			       sock_i_uid(s),
  			       sock_i_ino(s)
  			       );
bd2f74765   Pavel Emelyanov   [KEY]: Convert ne...
3507
3508
3509
3510
  	return 0;
  }
  
  static void *pfkey_seq_start(struct seq_file *f, loff_t *ppos)
ada440e3b   stephen hemminger   afkey: add sparse...
3511
  	__acquires(rcu)
bd2f74765   Pavel Emelyanov   [KEY]: Convert ne...
3512
  {
7013ec30e   Alexey Dobriyan   netns PF_KEY: per...
3513
  	struct net *net = seq_file_net(f);
3fa87a321   Alexey Dobriyan   netns PF_KEY: part 1
3514
  	struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3515

7f6b9dbd5   stephen hemminger   af_key: locking c...
3516
3517
  	rcu_read_lock();
  	return seq_hlist_start_head_rcu(&net_pfkey->table, *ppos);
bd2f74765   Pavel Emelyanov   [KEY]: Convert ne...
3518
3519
3520
3521
  }
  
  static void *pfkey_seq_next(struct seq_file *f, void *v, loff_t *ppos)
  {
7013ec30e   Alexey Dobriyan   netns PF_KEY: per...
3522
  	struct net *net = seq_file_net(f);
3fa87a321   Alexey Dobriyan   netns PF_KEY: part 1
3523
  	struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
7f6b9dbd5   stephen hemminger   af_key: locking c...
3524
  	return seq_hlist_next_rcu(v, &net_pfkey->table, ppos);
bd2f74765   Pavel Emelyanov   [KEY]: Convert ne...
3525
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3526

bd2f74765   Pavel Emelyanov   [KEY]: Convert ne...
3527
  static void pfkey_seq_stop(struct seq_file *f, void *v)
ada440e3b   stephen hemminger   afkey: add sparse...
3528
  	__releases(rcu)
bd2f74765   Pavel Emelyanov   [KEY]: Convert ne...
3529
  {
7f6b9dbd5   stephen hemminger   af_key: locking c...
3530
  	rcu_read_unlock();
bd2f74765   Pavel Emelyanov   [KEY]: Convert ne...
3531
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3532

98147d527   Stephen Hemminger   net: seq_operatio...
3533
  static const struct seq_operations pfkey_seq_ops = {
bd2f74765   Pavel Emelyanov   [KEY]: Convert ne...
3534
3535
3536
3537
3538
  	.start	= pfkey_seq_start,
  	.next	= pfkey_seq_next,
  	.stop	= pfkey_seq_stop,
  	.show	= pfkey_seq_show,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3539

bd2f74765   Pavel Emelyanov   [KEY]: Convert ne...
3540
3541
  static int pfkey_seq_open(struct inode *inode, struct file *file)
  {
7013ec30e   Alexey Dobriyan   netns PF_KEY: per...
3542
3543
  	return seq_open_net(inode, file, &pfkey_seq_ops,
  			    sizeof(struct seq_net_private));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3544
  }
61145aa1a   Pavel Emelyanov   [KEY]: Clean up p...
3545

5ca1b998d   Stephen Hemminger   net: file_operati...
3546
  static const struct file_operations pfkey_proc_ops = {
bd2f74765   Pavel Emelyanov   [KEY]: Convert ne...
3547
3548
3549
  	.open	 = pfkey_seq_open,
  	.read	 = seq_read,
  	.llseek	 = seq_lseek,
7013ec30e   Alexey Dobriyan   netns PF_KEY: per...
3550
  	.release = seq_release_net,
bd2f74765   Pavel Emelyanov   [KEY]: Convert ne...
3551
  };
7013ec30e   Alexey Dobriyan   netns PF_KEY: per...
3552
  static int __net_init pfkey_init_proc(struct net *net)
61145aa1a   Pavel Emelyanov   [KEY]: Clean up p...
3553
  {
bd2f74765   Pavel Emelyanov   [KEY]: Convert ne...
3554
  	struct proc_dir_entry *e;
7013ec30e   Alexey Dobriyan   netns PF_KEY: per...
3555
  	e = proc_net_fops_create(net, "pfkey", 0, &pfkey_proc_ops);
bd2f74765   Pavel Emelyanov   [KEY]: Convert ne...
3556
  	if (e == NULL)
61145aa1a   Pavel Emelyanov   [KEY]: Clean up p...
3557
  		return -ENOMEM;
bd2f74765   Pavel Emelyanov   [KEY]: Convert ne...
3558

bd2f74765   Pavel Emelyanov   [KEY]: Convert ne...
3559
  	return 0;
61145aa1a   Pavel Emelyanov   [KEY]: Clean up p...
3560
  }
2c8c1e729   Alexey Dobriyan   net: spread __net...
3561
  static void __net_exit pfkey_exit_proc(struct net *net)
61145aa1a   Pavel Emelyanov   [KEY]: Clean up p...
3562
  {
7013ec30e   Alexey Dobriyan   netns PF_KEY: per...
3563
  	proc_net_remove(net, "pfkey");
61145aa1a   Pavel Emelyanov   [KEY]: Clean up p...
3564
3565
  }
  #else
2c8c1e729   Alexey Dobriyan   net: spread __net...
3566
  static inline int pfkey_init_proc(struct net *net)
61145aa1a   Pavel Emelyanov   [KEY]: Clean up p...
3567
3568
3569
  {
  	return 0;
  }
2c8c1e729   Alexey Dobriyan   net: spread __net...
3570
  static inline void pfkey_exit_proc(struct net *net)
61145aa1a   Pavel Emelyanov   [KEY]: Clean up p...
3571
3572
  {
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3573
3574
3575
3576
3577
3578
3579
3580
3581
  #endif
  
  static struct xfrm_mgr pfkeyv2_mgr =
  {
  	.id		= "pfkeyv2",
  	.notify		= pfkey_send_notify,
  	.acquire	= pfkey_send_acquire,
  	.compile_policy	= pfkey_compile_policy,
  	.new_mapping	= pfkey_send_new_mapping,
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
3582
  	.notify_policy	= pfkey_send_policy_notify,
08de61bea   Shinta Sugimoto   [PFKEYV2]: Extens...
3583
  	.migrate	= pfkey_send_migrate,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3584
  };
3fa87a321   Alexey Dobriyan   netns PF_KEY: part 1
3585
3586
  static int __net_init pfkey_net_init(struct net *net)
  {
23c049ca9   Eric W. Biederman   net: Simplify af_...
3587
  	struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
3fa87a321   Alexey Dobriyan   netns PF_KEY: part 1
3588
  	int rv;
3fa87a321   Alexey Dobriyan   netns PF_KEY: part 1
3589
3590
  	INIT_HLIST_HEAD(&net_pfkey->table);
  	atomic_set(&net_pfkey->socks_nr, 0);
23c049ca9   Eric W. Biederman   net: Simplify af_...
3591

7013ec30e   Alexey Dobriyan   netns PF_KEY: per...
3592
  	rv = pfkey_init_proc(net);
3fa87a321   Alexey Dobriyan   netns PF_KEY: part 1
3593

3fa87a321   Alexey Dobriyan   netns PF_KEY: part 1
3594
3595
3596
3597
3598
3599
  	return rv;
  }
  
  static void __net_exit pfkey_net_exit(struct net *net)
  {
  	struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
7013ec30e   Alexey Dobriyan   netns PF_KEY: per...
3600
  	pfkey_exit_proc(net);
3fa87a321   Alexey Dobriyan   netns PF_KEY: part 1
3601
  	BUG_ON(!hlist_empty(&net_pfkey->table));
3fa87a321   Alexey Dobriyan   netns PF_KEY: part 1
3602
3603
3604
3605
3606
  }
  
  static struct pernet_operations pfkey_net_ops = {
  	.init = pfkey_net_init,
  	.exit = pfkey_net_exit,
23c049ca9   Eric W. Biederman   net: Simplify af_...
3607
3608
  	.id   = &pfkey_net_id,
  	.size = sizeof(struct netns_pfkey),
3fa87a321   Alexey Dobriyan   netns PF_KEY: part 1
3609
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3610
3611
3612
  static void __exit ipsec_pfkey_exit(void)
  {
  	xfrm_unregister_km(&pfkeyv2_mgr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3613
  	sock_unregister(PF_KEY);
180211b84   Alexey Dobriyan   af_key: fix netns...
3614
  	unregister_pernet_subsys(&pfkey_net_ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3615
3616
3617
3618
3619
3620
3621
3622
3623
  	proto_unregister(&key_proto);
  }
  
  static int __init ipsec_pfkey_init(void)
  {
  	int err = proto_register(&key_proto, 0);
  
  	if (err != 0)
  		goto out;
180211b84   Alexey Dobriyan   af_key: fix netns...
3624
  	err = register_pernet_subsys(&pfkey_net_ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3625
3626
  	if (err != 0)
  		goto out_unregister_key_proto;
180211b84   Alexey Dobriyan   af_key: fix netns...
3627
3628
3629
  	err = sock_register(&pfkey_family_ops);
  	if (err != 0)
  		goto out_unregister_pernet;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3630
3631
  	err = xfrm_register_km(&pfkeyv2_mgr);
  	if (err != 0)
7013ec30e   Alexey Dobriyan   netns PF_KEY: per...
3632
  		goto out_sock_unregister;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3633
3634
  out:
  	return err;
180211b84   Alexey Dobriyan   af_key: fix netns...
3635

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3636
  out_sock_unregister:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3637
  	sock_unregister(PF_KEY);
180211b84   Alexey Dobriyan   af_key: fix netns...
3638
3639
  out_unregister_pernet:
  	unregister_pernet_subsys(&pfkey_net_ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3640
3641
3642
3643
3644
3645
3646
3647
3648
  out_unregister_key_proto:
  	proto_unregister(&key_proto);
  	goto out;
  }
  
  module_init(ipsec_pfkey_init);
  module_exit(ipsec_pfkey_exit);
  MODULE_LICENSE("GPL");
  MODULE_ALIAS_NETPROTO(PF_KEY);