Blame view

crypto/crypto_user.c 13.4 KB
a38f7907b   Steffen Klassert   crypto: Add users...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  /*
   * Crypto user configuration API.
   *
   * Copyright (C) 2011 secunet Security Networks AG
   * Copyright (C) 2011 Steffen Klassert <steffen.klassert@secunet.com>
   *
   * This program is free software; you can redistribute it and/or modify it
   * under the terms and conditions of the GNU General Public License,
   * version 2, as published by the Free Software Foundation.
   *
   * This program is distributed in the hope it will be useful, but WITHOUT
   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
   * more details.
   *
   * You should have received a copy of the GNU General Public License along with
   * this program; if not, write to the Free Software Foundation, Inc.,
   * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
   */
  
  #include <linux/module.h>
  #include <linux/crypto.h>
  #include <linux/cryptouser.h>
1e1229940   Steffen Klassert   crypto: user - Fi...
24
  #include <linux/sched.h>
a38f7907b   Steffen Klassert   crypto: Add users...
25
26
27
  #include <net/netlink.h>
  #include <linux/security.h>
  #include <net/net_namespace.h>
1e1229940   Steffen Klassert   crypto: user - Fi...
28
29
  #include <crypto/internal/aead.h>
  #include <crypto/internal/skcipher.h>
9aa867e46   Herbert Xu   crypto: user - Ad...
30
  #include <crypto/internal/rng.h>
3c339ab83   Tadeusz Struk   crypto: akcipher ...
31
  #include <crypto/akcipher.h>
1e1229940   Steffen Klassert   crypto: user - Fi...
32

a38f7907b   Steffen Klassert   crypto: Add users...
33
  #include "internal.h"
8fd61d342   Mathias Krause   crypto: user - en...
34
  #define null_terminated(x)	(strnlen(x, sizeof(x)) < sizeof(x))
66ce0b0f2   Jussi Kivilinna   crypto: crypto_us...
35
  static DEFINE_MUTEX(crypto_cfg_mutex);
a38f7907b   Steffen Klassert   crypto: Add users...
36
37
38
39
40
41
42
43
44
45
46
47
48
  
  /* The crypto netlink socket */
  static struct sock *crypto_nlsk;
  
  struct crypto_dump_info {
  	struct sk_buff *in_skb;
  	struct sk_buff *out_skb;
  	u32 nlmsg_seq;
  	u16 nlmsg_flags;
  };
  
  static struct crypto_alg *crypto_alg_match(struct crypto_user_alg *p, int exact)
  {
a38f7907b   Steffen Klassert   crypto: Add users...
49
50
51
  	struct crypto_alg *q, *alg = NULL;
  
  	down_read(&crypto_alg_sem);
a38f7907b   Steffen Klassert   crypto: Add users...
52
  	list_for_each_entry(q, &crypto_alg_list, cra_list) {
e6ea64ece   Herbert Xu   crypto: user - In...
53
  		int match = 0;
a38f7907b   Steffen Klassert   crypto: Add users...
54
55
56
57
58
59
60
61
62
  
  		if ((q->cra_flags ^ p->cru_type) & p->cru_mask)
  			continue;
  
  		if (strlen(p->cru_driver_name))
  			match = !strcmp(q->cra_driver_name,
  					p->cru_driver_name);
  		else if (!exact)
  			match = !strcmp(q->cra_name, p->cru_name);
016baaa11   Herbert Xu   crypto: user - Fi...
63
64
65
66
67
68
69
70
  		if (!match)
  			continue;
  
  		if (unlikely(!crypto_mod_get(q)))
  			continue;
  
  		alg = q;
  		break;
a38f7907b   Steffen Klassert   crypto: Add users...
71
72
73
74
75
76
  	}
  
  	up_read(&crypto_alg_sem);
  
  	return alg;
  }
07a5fa4ab   Steffen Klassert   crypto: Add users...
77
78
79
  static int crypto_report_cipher(struct sk_buff *skb, struct crypto_alg *alg)
  {
  	struct crypto_report_cipher rcipher;
9a5467bf7   Mathias Krause   crypto: user - fi...
80
  	strncpy(rcipher.type, "cipher", sizeof(rcipher.type));
07a5fa4ab   Steffen Klassert   crypto: Add users...
81
82
83
84
  
  	rcipher.blocksize = alg->cra_blocksize;
  	rcipher.min_keysize = alg->cra_cipher.cia_min_keysize;
  	rcipher.max_keysize = alg->cra_cipher.cia_max_keysize;
6662df33f   David S. Miller   crypto: Stop usin...
85
86
87
  	if (nla_put(skb, CRYPTOCFGA_REPORT_CIPHER,
  		    sizeof(struct crypto_report_cipher), &rcipher))
  		goto nla_put_failure;
07a5fa4ab   Steffen Klassert   crypto: Add users...
88
89
90
91
92
  	return 0;
  
  nla_put_failure:
  	return -EMSGSIZE;
  }
540b97c1d   Steffen Klassert   crypto: Add users...
93
94
95
  static int crypto_report_comp(struct sk_buff *skb, struct crypto_alg *alg)
  {
  	struct crypto_report_comp rcomp;
9a5467bf7   Mathias Krause   crypto: user - fi...
96
  	strncpy(rcomp.type, "compression", sizeof(rcomp.type));
6662df33f   David S. Miller   crypto: Stop usin...
97
98
99
  	if (nla_put(skb, CRYPTOCFGA_REPORT_COMPRESS,
  		    sizeof(struct crypto_report_comp), &rcomp))
  		goto nla_put_failure;
540b97c1d   Steffen Klassert   crypto: Add users...
100
101
102
103
104
  	return 0;
  
  nla_put_failure:
  	return -EMSGSIZE;
  }
3c339ab83   Tadeusz Struk   crypto: akcipher ...
105
106
107
108
109
110
111
112
113
114
115
116
117
118
  static int crypto_report_akcipher(struct sk_buff *skb, struct crypto_alg *alg)
  {
  	struct crypto_report_akcipher rakcipher;
  
  	strncpy(rakcipher.type, "akcipher", sizeof(rakcipher.type));
  
  	if (nla_put(skb, CRYPTOCFGA_REPORT_AKCIPHER,
  		    sizeof(struct crypto_report_akcipher), &rakcipher))
  		goto nla_put_failure;
  	return 0;
  
  nla_put_failure:
  	return -EMSGSIZE;
  }
a38f7907b   Steffen Klassert   crypto: Add users...
119
120
121
  static int crypto_report_one(struct crypto_alg *alg,
  			     struct crypto_user_alg *ualg, struct sk_buff *skb)
  {
9a5467bf7   Mathias Krause   crypto: user - fi...
122
123
124
125
126
127
128
129
  	strncpy(ualg->cru_name, alg->cra_name, sizeof(ualg->cru_name));
  	strncpy(ualg->cru_driver_name, alg->cra_driver_name,
  		sizeof(ualg->cru_driver_name));
  	strncpy(ualg->cru_module_name, module_name(alg->cra_module),
  		sizeof(ualg->cru_module_name));
  
  	ualg->cru_type = 0;
  	ualg->cru_mask = 0;
a38f7907b   Steffen Klassert   crypto: Add users...
130
131
  	ualg->cru_flags = alg->cra_flags;
  	ualg->cru_refcnt = atomic_read(&alg->cra_refcnt);
6662df33f   David S. Miller   crypto: Stop usin...
132
133
  	if (nla_put_u32(skb, CRYPTOCFGA_PRIORITY_VAL, alg->cra_priority))
  		goto nla_put_failure;
6c5a86f52   Steffen Klassert   crypto: Add users...
134
135
  	if (alg->cra_flags & CRYPTO_ALG_LARVAL) {
  		struct crypto_report_larval rl;
9a5467bf7   Mathias Krause   crypto: user - fi...
136
  		strncpy(rl.type, "larval", sizeof(rl.type));
6662df33f   David S. Miller   crypto: Stop usin...
137
138
139
  		if (nla_put(skb, CRYPTOCFGA_REPORT_LARVAL,
  			    sizeof(struct crypto_report_larval), &rl))
  			goto nla_put_failure;
6c5a86f52   Steffen Klassert   crypto: Add users...
140
141
  		goto out;
  	}
b6aa63c09   Steffen Klassert   crypto: Add a rep...
142
143
144
  	if (alg->cra_type && alg->cra_type->report) {
  		if (alg->cra_type->report(skb, alg))
  			goto nla_put_failure;
07a5fa4ab   Steffen Klassert   crypto: Add users...
145
146
147
148
149
150
151
152
153
154
  
  		goto out;
  	}
  
  	switch (alg->cra_flags & (CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_LARVAL)) {
  	case CRYPTO_ALG_TYPE_CIPHER:
  		if (crypto_report_cipher(skb, alg))
  			goto nla_put_failure;
  
  		break;
540b97c1d   Steffen Klassert   crypto: Add users...
155
156
157
158
159
  	case CRYPTO_ALG_TYPE_COMPRESS:
  		if (crypto_report_comp(skb, alg))
  			goto nla_put_failure;
  
  		break;
3c339ab83   Tadeusz Struk   crypto: akcipher ...
160
161
162
163
164
165
  
  	case CRYPTO_ALG_TYPE_AKCIPHER:
  		if (crypto_report_akcipher(skb, alg))
  			goto nla_put_failure;
  
  		break;
b6aa63c09   Steffen Klassert   crypto: Add a rep...
166
  	}
6c5a86f52   Steffen Klassert   crypto: Add users...
167
  out:
a38f7907b   Steffen Klassert   crypto: Add users...
168
169
170
171
172
173
174
175
176
177
178
179
180
181
  	return 0;
  
  nla_put_failure:
  	return -EMSGSIZE;
  }
  
  static int crypto_report_alg(struct crypto_alg *alg,
  			     struct crypto_dump_info *info)
  {
  	struct sk_buff *in_skb = info->in_skb;
  	struct sk_buff *skb = info->out_skb;
  	struct nlmsghdr *nlh;
  	struct crypto_user_alg *ualg;
  	int err = 0;
15e473046   Eric W. Biederman   netlink: Rename p...
182
  	nlh = nlmsg_put(skb, NETLINK_CB(in_skb).portid, info->nlmsg_seq,
a38f7907b   Steffen Klassert   crypto: Add users...
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
  			CRYPTO_MSG_GETALG, sizeof(*ualg), info->nlmsg_flags);
  	if (!nlh) {
  		err = -EMSGSIZE;
  		goto out;
  	}
  
  	ualg = nlmsg_data(nlh);
  
  	err = crypto_report_one(alg, ualg, skb);
  	if (err) {
  		nlmsg_cancel(skb, nlh);
  		goto out;
  	}
  
  	nlmsg_end(skb, nlh);
  
  out:
  	return err;
  }
  
  static int crypto_report(struct sk_buff *in_skb, struct nlmsghdr *in_nlh,
  			 struct nlattr **attrs)
  {
  	struct crypto_user_alg *p = nlmsg_data(in_nlh);
  	struct crypto_alg *alg;
  	struct sk_buff *skb;
  	struct crypto_dump_info info;
  	int err;
8fd61d342   Mathias Krause   crypto: user - en...
211
212
  	if (!null_terminated(p->cru_name) || !null_terminated(p->cru_driver_name))
  		return -EINVAL;
5d4a5e770   Herbert Xu   crypto: user - Al...
213
  	alg = crypto_alg_match(p, 0);
a38f7907b   Steffen Klassert   crypto: Add users...
214
215
  	if (!alg)
  		return -ENOENT;
016baaa11   Herbert Xu   crypto: user - Fi...
216
  	err = -ENOMEM;
a38f7907b   Steffen Klassert   crypto: Add users...
217
218
  	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
  	if (!skb)
016baaa11   Herbert Xu   crypto: user - Fi...
219
  		goto drop_alg;
a38f7907b   Steffen Klassert   crypto: Add users...
220
221
222
223
224
225
226
  
  	info.in_skb = in_skb;
  	info.out_skb = skb;
  	info.nlmsg_seq = in_nlh->nlmsg_seq;
  	info.nlmsg_flags = 0;
  
  	err = crypto_report_alg(alg, &info);
016baaa11   Herbert Xu   crypto: user - Fi...
227
228
229
  
  drop_alg:
  	crypto_mod_put(alg);
a38f7907b   Steffen Klassert   crypto: Add users...
230
231
  	if (err)
  		return err;
15e473046   Eric W. Biederman   netlink: Rename p...
232
  	return nlmsg_unicast(crypto_nlsk, skb, NETLINK_CB(in_skb).portid);
a38f7907b   Steffen Klassert   crypto: Add users...
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
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
  }
  
  static int crypto_dump_report(struct sk_buff *skb, struct netlink_callback *cb)
  {
  	struct crypto_alg *alg;
  	struct crypto_dump_info info;
  	int err;
  
  	if (cb->args[0])
  		goto out;
  
  	cb->args[0] = 1;
  
  	info.in_skb = cb->skb;
  	info.out_skb = skb;
  	info.nlmsg_seq = cb->nlh->nlmsg_seq;
  	info.nlmsg_flags = NLM_F_MULTI;
  
  	list_for_each_entry(alg, &crypto_alg_list, cra_list) {
  		err = crypto_report_alg(alg, &info);
  		if (err)
  			goto out_err;
  	}
  
  out:
  	return skb->len;
  out_err:
  	return err;
  }
  
  static int crypto_dump_report_done(struct netlink_callback *cb)
  {
  	return 0;
  }
  
  static int crypto_update_alg(struct sk_buff *skb, struct nlmsghdr *nlh,
  			     struct nlattr **attrs)
  {
  	struct crypto_alg *alg;
  	struct crypto_user_alg *p = nlmsg_data(nlh);
  	struct nlattr *priority = attrs[CRYPTOCFGA_PRIORITY_VAL];
  	LIST_HEAD(list);
639b4ac69   Linus Torvalds   Merge git://git.k...
275
  	if (!netlink_capable(skb, CAP_NET_ADMIN))
c568398aa   Matthias-Christian Ott   crypto: user - Al...
276
  		return -EPERM;
8fd61d342   Mathias Krause   crypto: user - en...
277
278
  	if (!null_terminated(p->cru_name) || !null_terminated(p->cru_driver_name))
  		return -EINVAL;
a38f7907b   Steffen Klassert   crypto: Add users...
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
  	if (priority && !strlen(p->cru_driver_name))
  		return -EINVAL;
  
  	alg = crypto_alg_match(p, 1);
  	if (!alg)
  		return -ENOENT;
  
  	down_write(&crypto_alg_sem);
  
  	crypto_remove_spawns(alg, &list, NULL);
  
  	if (priority)
  		alg->cra_priority = nla_get_u32(priority);
  
  	up_write(&crypto_alg_sem);
016baaa11   Herbert Xu   crypto: user - Fi...
294
  	crypto_mod_put(alg);
a38f7907b   Steffen Klassert   crypto: Add users...
295
296
297
298
299
300
301
302
303
304
  	crypto_remove_final(&list);
  
  	return 0;
  }
  
  static int crypto_del_alg(struct sk_buff *skb, struct nlmsghdr *nlh,
  			  struct nlattr **attrs)
  {
  	struct crypto_alg *alg;
  	struct crypto_user_alg *p = nlmsg_data(nlh);
016baaa11   Herbert Xu   crypto: user - Fi...
305
  	int err;
a38f7907b   Steffen Klassert   crypto: Add users...
306

639b4ac69   Linus Torvalds   Merge git://git.k...
307
  	if (!netlink_capable(skb, CAP_NET_ADMIN))
c568398aa   Matthias-Christian Ott   crypto: user - Al...
308
  		return -EPERM;
8fd61d342   Mathias Krause   crypto: user - en...
309
310
  	if (!null_terminated(p->cru_name) || !null_terminated(p->cru_driver_name))
  		return -EINVAL;
a38f7907b   Steffen Klassert   crypto: Add users...
311
312
313
314
315
316
317
318
319
  	alg = crypto_alg_match(p, 1);
  	if (!alg)
  		return -ENOENT;
  
  	/* We can not unregister core algorithms such as aes-generic.
  	 * We would loose the reference in the crypto_alg_list to this algorithm
  	 * if we try to unregister. Unregistering such an algorithm without
  	 * removing the module is not possible, so we restrict to crypto
  	 * instances that are build from templates. */
016baaa11   Herbert Xu   crypto: user - Fi...
320
  	err = -EINVAL;
a38f7907b   Steffen Klassert   crypto: Add users...
321
  	if (!(alg->cra_flags & CRYPTO_ALG_INSTANCE))
016baaa11   Herbert Xu   crypto: user - Fi...
322
  		goto drop_alg;
a38f7907b   Steffen Klassert   crypto: Add users...
323

016baaa11   Herbert Xu   crypto: user - Fi...
324
325
326
  	err = -EBUSY;
  	if (atomic_read(&alg->cra_refcnt) > 2)
  		goto drop_alg;
a38f7907b   Steffen Klassert   crypto: Add users...
327

016baaa11   Herbert Xu   crypto: user - Fi...
328
329
330
331
332
  	err = crypto_unregister_instance((struct crypto_instance *)alg);
  
  drop_alg:
  	crypto_mod_put(alg);
  	return err;
a38f7907b   Steffen Klassert   crypto: Add users...
333
  }
1e1229940   Steffen Klassert   crypto: user - Fi...
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
  static struct crypto_alg *crypto_user_skcipher_alg(const char *name, u32 type,
  						   u32 mask)
  {
  	int err;
  	struct crypto_alg *alg;
  
  	type = crypto_skcipher_type(type);
  	mask = crypto_skcipher_mask(mask);
  
  	for (;;) {
  		alg = crypto_lookup_skcipher(name,  type, mask);
  		if (!IS_ERR(alg))
  			return alg;
  
  		err = PTR_ERR(alg);
  		if (err != -EAGAIN)
  			break;
  		if (signal_pending(current)) {
  			err = -EINTR;
  			break;
  		}
  	}
  
  	return ERR_PTR(err);
  }
  
  static struct crypto_alg *crypto_user_aead_alg(const char *name, u32 type,
  					       u32 mask)
  {
  	int err;
  	struct crypto_alg *alg;
  
  	type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV);
  	type |= CRYPTO_ALG_TYPE_AEAD;
  	mask &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV);
  	mask |= CRYPTO_ALG_TYPE_MASK;
  
  	for (;;) {
  		alg = crypto_lookup_aead(name,  type, mask);
  		if (!IS_ERR(alg))
  			return alg;
  
  		err = PTR_ERR(alg);
  		if (err != -EAGAIN)
  			break;
  		if (signal_pending(current)) {
  			err = -EINTR;
  			break;
  		}
  	}
  
  	return ERR_PTR(err);
  }
a38f7907b   Steffen Klassert   crypto: Add users...
387
388
389
  static int crypto_add_alg(struct sk_buff *skb, struct nlmsghdr *nlh,
  			  struct nlattr **attrs)
  {
0cfdec7a6   Jesper Juhl   crypto: In crypto...
390
  	int exact = 0;
a38f7907b   Steffen Klassert   crypto: Add users...
391
392
393
394
  	const char *name;
  	struct crypto_alg *alg;
  	struct crypto_user_alg *p = nlmsg_data(nlh);
  	struct nlattr *priority = attrs[CRYPTOCFGA_PRIORITY_VAL];
639b4ac69   Linus Torvalds   Merge git://git.k...
395
  	if (!netlink_capable(skb, CAP_NET_ADMIN))
c568398aa   Matthias-Christian Ott   crypto: user - Al...
396
  		return -EPERM;
8fd61d342   Mathias Krause   crypto: user - en...
397
398
  	if (!null_terminated(p->cru_name) || !null_terminated(p->cru_driver_name))
  		return -EINVAL;
a38f7907b   Steffen Klassert   crypto: Add users...
399
400
401
402
403
404
405
  	if (strlen(p->cru_driver_name))
  		exact = 1;
  
  	if (priority && !exact)
  		return -EINVAL;
  
  	alg = crypto_alg_match(p, exact);
016baaa11   Herbert Xu   crypto: user - Fi...
406
407
  	if (alg) {
  		crypto_mod_put(alg);
a38f7907b   Steffen Klassert   crypto: Add users...
408
  		return -EEXIST;
016baaa11   Herbert Xu   crypto: user - Fi...
409
  	}
a38f7907b   Steffen Klassert   crypto: Add users...
410
411
412
413
414
  
  	if (strlen(p->cru_driver_name))
  		name = p->cru_driver_name;
  	else
  		name = p->cru_name;
1e1229940   Steffen Klassert   crypto: user - Fi...
415
416
417
418
419
420
421
422
423
424
425
426
  	switch (p->cru_type & p->cru_mask & CRYPTO_ALG_TYPE_MASK) {
  	case CRYPTO_ALG_TYPE_AEAD:
  		alg = crypto_user_aead_alg(name, p->cru_type, p->cru_mask);
  		break;
  	case CRYPTO_ALG_TYPE_GIVCIPHER:
  	case CRYPTO_ALG_TYPE_BLKCIPHER:
  	case CRYPTO_ALG_TYPE_ABLKCIPHER:
  		alg = crypto_user_skcipher_alg(name, p->cru_type, p->cru_mask);
  		break;
  	default:
  		alg = crypto_alg_mod_lookup(name, p->cru_type, p->cru_mask);
  	}
a38f7907b   Steffen Klassert   crypto: Add users...
427
428
429
430
431
432
433
434
435
436
437
438
439
440
  	if (IS_ERR(alg))
  		return PTR_ERR(alg);
  
  	down_write(&crypto_alg_sem);
  
  	if (priority)
  		alg->cra_priority = nla_get_u32(priority);
  
  	up_write(&crypto_alg_sem);
  
  	crypto_mod_put(alg);
  
  	return 0;
  }
9aa867e46   Herbert Xu   crypto: user - Ad...
441
442
443
444
445
446
447
  static int crypto_del_rng(struct sk_buff *skb, struct nlmsghdr *nlh,
  			  struct nlattr **attrs)
  {
  	if (!netlink_capable(skb, CAP_NET_ADMIN))
  		return -EPERM;
  	return crypto_del_default_rng();
  }
a38f7907b   Steffen Klassert   crypto: Add users...
448
449
450
451
452
453
  #define MSGSIZE(type) sizeof(struct type)
  
  static const int crypto_msg_min[CRYPTO_NR_MSGTYPES] = {
  	[CRYPTO_MSG_NEWALG	- CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg),
  	[CRYPTO_MSG_DELALG	- CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg),
  	[CRYPTO_MSG_UPDATEALG	- CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg),
9aa867e46   Herbert Xu   crypto: user - Ad...
454
  	[CRYPTO_MSG_DELRNG	- CRYPTO_MSG_BASE] = 0,
a38f7907b   Steffen Klassert   crypto: Add users...
455
456
457
458
459
460
461
  };
  
  static const struct nla_policy crypto_policy[CRYPTOCFGA_MAX+1] = {
  	[CRYPTOCFGA_PRIORITY_VAL]   = { .type = NLA_U32},
  };
  
  #undef MSGSIZE
a84fb791c   Mathias Krause   crypto: user - co...
462
  static const struct crypto_link {
a38f7907b   Steffen Klassert   crypto: Add users...
463
464
465
466
467
468
469
470
471
472
  	int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **);
  	int (*dump)(struct sk_buff *, struct netlink_callback *);
  	int (*done)(struct netlink_callback *);
  } crypto_dispatch[CRYPTO_NR_MSGTYPES] = {
  	[CRYPTO_MSG_NEWALG	- CRYPTO_MSG_BASE] = { .doit = crypto_add_alg},
  	[CRYPTO_MSG_DELALG	- CRYPTO_MSG_BASE] = { .doit = crypto_del_alg},
  	[CRYPTO_MSG_UPDATEALG	- CRYPTO_MSG_BASE] = { .doit = crypto_update_alg},
  	[CRYPTO_MSG_GETALG	- CRYPTO_MSG_BASE] = { .doit = crypto_report,
  						       .dump = crypto_dump_report,
  						       .done = crypto_dump_report_done},
9aa867e46   Herbert Xu   crypto: user - Ad...
473
  	[CRYPTO_MSG_DELRNG	- CRYPTO_MSG_BASE] = { .doit = crypto_del_rng },
a38f7907b   Steffen Klassert   crypto: Add users...
474
475
476
477
478
  };
  
  static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
  {
  	struct nlattr *attrs[CRYPTOCFGA_MAX+1];
a84fb791c   Mathias Krause   crypto: user - co...
479
  	const struct crypto_link *link;
a38f7907b   Steffen Klassert   crypto: Add users...
480
481
482
483
484
485
486
487
  	int type, err;
  
  	type = nlh->nlmsg_type;
  	if (type > CRYPTO_MSG_MAX)
  		return -EINVAL;
  
  	type -= CRYPTO_MSG_BASE;
  	link = &crypto_dispatch[type];
a38f7907b   Steffen Klassert   crypto: Add users...
488
489
  	if ((type == (CRYPTO_MSG_GETALG - CRYPTO_MSG_BASE) &&
  	    (nlh->nlmsg_flags & NLM_F_DUMP))) {
5219a5342   Steffen Klassert   crypto: user - Fi...
490
491
  		struct crypto_alg *alg;
  		u16 dump_alloc = 0;
a38f7907b   Steffen Klassert   crypto: Add users...
492
493
  		if (link->dump == NULL)
  			return -EINVAL;
5219a5342   Steffen Klassert   crypto: user - Fi...
494
495
496
  
  		list_for_each_entry(alg, &crypto_alg_list, cra_list)
  			dump_alloc += CRYPTO_REPORT_MAXSIZE;
80d326fab   Pablo Neira Ayuso   netlink: add netl...
497
498
499
500
  		{
  			struct netlink_dump_control c = {
  				.dump = link->dump,
  				.done = link->done,
5219a5342   Steffen Klassert   crypto: user - Fi...
501
  				.min_dump_alloc = dump_alloc,
80d326fab   Pablo Neira Ayuso   netlink: add netl...
502
503
504
  			};
  			return netlink_dump_start(crypto_nlsk, skb, nlh, &c);
  		}
a38f7907b   Steffen Klassert   crypto: Add users...
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
  	}
  
  	err = nlmsg_parse(nlh, crypto_msg_min[type], attrs, CRYPTOCFGA_MAX,
  			  crypto_policy);
  	if (err < 0)
  		return err;
  
  	if (link->doit == NULL)
  		return -EINVAL;
  
  	return link->doit(skb, nlh, attrs);
  }
  
  static void crypto_netlink_rcv(struct sk_buff *skb)
  {
  	mutex_lock(&crypto_cfg_mutex);
  	netlink_rcv_skb(skb, &crypto_user_rcv_msg);
  	mutex_unlock(&crypto_cfg_mutex);
  }
  
  static int __init crypto_user_init(void)
  {
a31f2d17b   Pablo Neira Ayuso   netlink: add netl...
527
528
529
  	struct netlink_kernel_cfg cfg = {
  		.input	= crypto_netlink_rcv,
  	};
9f00d9776   Pablo Neira Ayuso   netlink: hide str...
530
  	crypto_nlsk = netlink_kernel_create(&init_net, NETLINK_CRYPTO, &cfg);
a38f7907b   Steffen Klassert   crypto: Add users...
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
  	if (!crypto_nlsk)
  		return -ENOMEM;
  
  	return 0;
  }
  
  static void __exit crypto_user_exit(void)
  {
  	netlink_kernel_release(crypto_nlsk);
  }
  
  module_init(crypto_user_init);
  module_exit(crypto_user_exit);
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("Steffen Klassert <steffen.klassert@secunet.com>");
  MODULE_DESCRIPTION("Crypto userspace configuration API");
476c7fe20   Stephan Mueller   crypto: user - ad...
547
  MODULE_ALIAS("net-pf-16-proto-21");