xref: /openbmc/linux/net/xfrm/xfrm_algo.c (revision d2ba09c1)
1 /*
2  * xfrm algorithm interface
3  *
4  * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the Free
8  * Software Foundation; either version 2 of the License, or (at your option)
9  * any later version.
10  */
11 
12 #include <crypto/hash.h>
13 #include <crypto/skcipher.h>
14 #include <linux/module.h>
15 #include <linux/kernel.h>
16 #include <linux/pfkeyv2.h>
17 #include <linux/crypto.h>
18 #include <linux/scatterlist.h>
19 #include <net/xfrm.h>
20 #if IS_ENABLED(CONFIG_INET_ESP) || IS_ENABLED(CONFIG_INET6_ESP)
21 #include <net/esp.h>
22 #endif
23 
24 /*
25  * Algorithms supported by IPsec.  These entries contain properties which
26  * are used in key negotiation and xfrm processing, and are used to verify
27  * that instantiated crypto transforms have correct parameters for IPsec
28  * purposes.
29  */
30 static struct xfrm_algo_desc aead_list[] = {
31 {
32 	.name = "rfc4106(gcm(aes))",
33 
34 	.uinfo = {
35 		.aead = {
36 			.geniv = "seqiv",
37 			.icv_truncbits = 64,
38 		}
39 	},
40 
41 	.pfkey_supported = 1,
42 
43 	.desc = {
44 		.sadb_alg_id = SADB_X_EALG_AES_GCM_ICV8,
45 		.sadb_alg_ivlen = 8,
46 		.sadb_alg_minbits = 128,
47 		.sadb_alg_maxbits = 256
48 	}
49 },
50 {
51 	.name = "rfc4106(gcm(aes))",
52 
53 	.uinfo = {
54 		.aead = {
55 			.geniv = "seqiv",
56 			.icv_truncbits = 96,
57 		}
58 	},
59 
60 	.pfkey_supported = 1,
61 
62 	.desc = {
63 		.sadb_alg_id = SADB_X_EALG_AES_GCM_ICV12,
64 		.sadb_alg_ivlen = 8,
65 		.sadb_alg_minbits = 128,
66 		.sadb_alg_maxbits = 256
67 	}
68 },
69 {
70 	.name = "rfc4106(gcm(aes))",
71 
72 	.uinfo = {
73 		.aead = {
74 			.geniv = "seqiv",
75 			.icv_truncbits = 128,
76 		}
77 	},
78 
79 	.pfkey_supported = 1,
80 
81 	.desc = {
82 		.sadb_alg_id = SADB_X_EALG_AES_GCM_ICV16,
83 		.sadb_alg_ivlen = 8,
84 		.sadb_alg_minbits = 128,
85 		.sadb_alg_maxbits = 256
86 	}
87 },
88 {
89 	.name = "rfc4309(ccm(aes))",
90 
91 	.uinfo = {
92 		.aead = {
93 			.geniv = "seqiv",
94 			.icv_truncbits = 64,
95 		}
96 	},
97 
98 	.pfkey_supported = 1,
99 
100 	.desc = {
101 		.sadb_alg_id = SADB_X_EALG_AES_CCM_ICV8,
102 		.sadb_alg_ivlen = 8,
103 		.sadb_alg_minbits = 128,
104 		.sadb_alg_maxbits = 256
105 	}
106 },
107 {
108 	.name = "rfc4309(ccm(aes))",
109 
110 	.uinfo = {
111 		.aead = {
112 			.geniv = "seqiv",
113 			.icv_truncbits = 96,
114 		}
115 	},
116 
117 	.pfkey_supported = 1,
118 
119 	.desc = {
120 		.sadb_alg_id = SADB_X_EALG_AES_CCM_ICV12,
121 		.sadb_alg_ivlen = 8,
122 		.sadb_alg_minbits = 128,
123 		.sadb_alg_maxbits = 256
124 	}
125 },
126 {
127 	.name = "rfc4309(ccm(aes))",
128 
129 	.uinfo = {
130 		.aead = {
131 			.geniv = "seqiv",
132 			.icv_truncbits = 128,
133 		}
134 	},
135 
136 	.pfkey_supported = 1,
137 
138 	.desc = {
139 		.sadb_alg_id = SADB_X_EALG_AES_CCM_ICV16,
140 		.sadb_alg_ivlen = 8,
141 		.sadb_alg_minbits = 128,
142 		.sadb_alg_maxbits = 256
143 	}
144 },
145 {
146 	.name = "rfc4543(gcm(aes))",
147 
148 	.uinfo = {
149 		.aead = {
150 			.geniv = "seqiv",
151 			.icv_truncbits = 128,
152 		}
153 	},
154 
155 	.pfkey_supported = 1,
156 
157 	.desc = {
158 		.sadb_alg_id = SADB_X_EALG_NULL_AES_GMAC,
159 		.sadb_alg_ivlen = 8,
160 		.sadb_alg_minbits = 128,
161 		.sadb_alg_maxbits = 256
162 	}
163 },
164 {
165 	.name = "rfc7539esp(chacha20,poly1305)",
166 
167 	.uinfo = {
168 		.aead = {
169 			.geniv = "seqiv",
170 			.icv_truncbits = 128,
171 		}
172 	},
173 
174 	.pfkey_supported = 0,
175 },
176 };
177 
178 static struct xfrm_algo_desc aalg_list[] = {
179 {
180 	.name = "digest_null",
181 
182 	.uinfo = {
183 		.auth = {
184 			.icv_truncbits = 0,
185 			.icv_fullbits = 0,
186 		}
187 	},
188 
189 	.pfkey_supported = 1,
190 
191 	.desc = {
192 		.sadb_alg_id = SADB_X_AALG_NULL,
193 		.sadb_alg_ivlen = 0,
194 		.sadb_alg_minbits = 0,
195 		.sadb_alg_maxbits = 0
196 	}
197 },
198 {
199 	.name = "hmac(md5)",
200 	.compat = "md5",
201 
202 	.uinfo = {
203 		.auth = {
204 			.icv_truncbits = 96,
205 			.icv_fullbits = 128,
206 		}
207 	},
208 
209 	.pfkey_supported = 1,
210 
211 	.desc = {
212 		.sadb_alg_id = SADB_AALG_MD5HMAC,
213 		.sadb_alg_ivlen = 0,
214 		.sadb_alg_minbits = 128,
215 		.sadb_alg_maxbits = 128
216 	}
217 },
218 {
219 	.name = "hmac(sha1)",
220 	.compat = "sha1",
221 
222 	.uinfo = {
223 		.auth = {
224 			.icv_truncbits = 96,
225 			.icv_fullbits = 160,
226 		}
227 	},
228 
229 	.pfkey_supported = 1,
230 
231 	.desc = {
232 		.sadb_alg_id = SADB_AALG_SHA1HMAC,
233 		.sadb_alg_ivlen = 0,
234 		.sadb_alg_minbits = 160,
235 		.sadb_alg_maxbits = 160
236 	}
237 },
238 {
239 	.name = "hmac(sha256)",
240 	.compat = "sha256",
241 
242 	.uinfo = {
243 		.auth = {
244 			.icv_truncbits = 96,
245 			.icv_fullbits = 256,
246 		}
247 	},
248 
249 	.pfkey_supported = 1,
250 
251 	.desc = {
252 		.sadb_alg_id = SADB_X_AALG_SHA2_256HMAC,
253 		.sadb_alg_ivlen = 0,
254 		.sadb_alg_minbits = 256,
255 		.sadb_alg_maxbits = 256
256 	}
257 },
258 {
259 	.name = "hmac(sha384)",
260 
261 	.uinfo = {
262 		.auth = {
263 			.icv_truncbits = 192,
264 			.icv_fullbits = 384,
265 		}
266 	},
267 
268 	.pfkey_supported = 1,
269 
270 	.desc = {
271 		.sadb_alg_id = SADB_X_AALG_SHA2_384HMAC,
272 		.sadb_alg_ivlen = 0,
273 		.sadb_alg_minbits = 384,
274 		.sadb_alg_maxbits = 384
275 	}
276 },
277 {
278 	.name = "hmac(sha512)",
279 
280 	.uinfo = {
281 		.auth = {
282 			.icv_truncbits = 256,
283 			.icv_fullbits = 512,
284 		}
285 	},
286 
287 	.pfkey_supported = 1,
288 
289 	.desc = {
290 		.sadb_alg_id = SADB_X_AALG_SHA2_512HMAC,
291 		.sadb_alg_ivlen = 0,
292 		.sadb_alg_minbits = 512,
293 		.sadb_alg_maxbits = 512
294 	}
295 },
296 {
297 	.name = "hmac(rmd160)",
298 	.compat = "rmd160",
299 
300 	.uinfo = {
301 		.auth = {
302 			.icv_truncbits = 96,
303 			.icv_fullbits = 160,
304 		}
305 	},
306 
307 	.pfkey_supported = 1,
308 
309 	.desc = {
310 		.sadb_alg_id = SADB_X_AALG_RIPEMD160HMAC,
311 		.sadb_alg_ivlen = 0,
312 		.sadb_alg_minbits = 160,
313 		.sadb_alg_maxbits = 160
314 	}
315 },
316 {
317 	.name = "xcbc(aes)",
318 
319 	.uinfo = {
320 		.auth = {
321 			.icv_truncbits = 96,
322 			.icv_fullbits = 128,
323 		}
324 	},
325 
326 	.pfkey_supported = 1,
327 
328 	.desc = {
329 		.sadb_alg_id = SADB_X_AALG_AES_XCBC_MAC,
330 		.sadb_alg_ivlen = 0,
331 		.sadb_alg_minbits = 128,
332 		.sadb_alg_maxbits = 128
333 	}
334 },
335 {
336 	/* rfc4494 */
337 	.name = "cmac(aes)",
338 
339 	.uinfo = {
340 		.auth = {
341 			.icv_truncbits = 96,
342 			.icv_fullbits = 128,
343 		}
344 	},
345 
346 	.pfkey_supported = 0,
347 },
348 };
349 
350 static struct xfrm_algo_desc ealg_list[] = {
351 {
352 	.name = "ecb(cipher_null)",
353 	.compat = "cipher_null",
354 
355 	.uinfo = {
356 		.encr = {
357 			.blockbits = 8,
358 			.defkeybits = 0,
359 		}
360 	},
361 
362 	.pfkey_supported = 1,
363 
364 	.desc = {
365 		.sadb_alg_id =	SADB_EALG_NULL,
366 		.sadb_alg_ivlen = 0,
367 		.sadb_alg_minbits = 0,
368 		.sadb_alg_maxbits = 0
369 	}
370 },
371 {
372 	.name = "cbc(des)",
373 	.compat = "des",
374 
375 	.uinfo = {
376 		.encr = {
377 			.geniv = "echainiv",
378 			.blockbits = 64,
379 			.defkeybits = 64,
380 		}
381 	},
382 
383 	.pfkey_supported = 1,
384 
385 	.desc = {
386 		.sadb_alg_id = SADB_EALG_DESCBC,
387 		.sadb_alg_ivlen = 8,
388 		.sadb_alg_minbits = 64,
389 		.sadb_alg_maxbits = 64
390 	}
391 },
392 {
393 	.name = "cbc(des3_ede)",
394 	.compat = "des3_ede",
395 
396 	.uinfo = {
397 		.encr = {
398 			.geniv = "echainiv",
399 			.blockbits = 64,
400 			.defkeybits = 192,
401 		}
402 	},
403 
404 	.pfkey_supported = 1,
405 
406 	.desc = {
407 		.sadb_alg_id = SADB_EALG_3DESCBC,
408 		.sadb_alg_ivlen = 8,
409 		.sadb_alg_minbits = 192,
410 		.sadb_alg_maxbits = 192
411 	}
412 },
413 {
414 	.name = "cbc(cast5)",
415 	.compat = "cast5",
416 
417 	.uinfo = {
418 		.encr = {
419 			.geniv = "echainiv",
420 			.blockbits = 64,
421 			.defkeybits = 128,
422 		}
423 	},
424 
425 	.pfkey_supported = 1,
426 
427 	.desc = {
428 		.sadb_alg_id = SADB_X_EALG_CASTCBC,
429 		.sadb_alg_ivlen = 8,
430 		.sadb_alg_minbits = 40,
431 		.sadb_alg_maxbits = 128
432 	}
433 },
434 {
435 	.name = "cbc(blowfish)",
436 	.compat = "blowfish",
437 
438 	.uinfo = {
439 		.encr = {
440 			.geniv = "echainiv",
441 			.blockbits = 64,
442 			.defkeybits = 128,
443 		}
444 	},
445 
446 	.pfkey_supported = 1,
447 
448 	.desc = {
449 		.sadb_alg_id = SADB_X_EALG_BLOWFISHCBC,
450 		.sadb_alg_ivlen = 8,
451 		.sadb_alg_minbits = 40,
452 		.sadb_alg_maxbits = 448
453 	}
454 },
455 {
456 	.name = "cbc(aes)",
457 	.compat = "aes",
458 
459 	.uinfo = {
460 		.encr = {
461 			.geniv = "echainiv",
462 			.blockbits = 128,
463 			.defkeybits = 128,
464 		}
465 	},
466 
467 	.pfkey_supported = 1,
468 
469 	.desc = {
470 		.sadb_alg_id = SADB_X_EALG_AESCBC,
471 		.sadb_alg_ivlen = 8,
472 		.sadb_alg_minbits = 128,
473 		.sadb_alg_maxbits = 256
474 	}
475 },
476 {
477 	.name = "cbc(serpent)",
478 	.compat = "serpent",
479 
480 	.uinfo = {
481 		.encr = {
482 			.geniv = "echainiv",
483 			.blockbits = 128,
484 			.defkeybits = 128,
485 		}
486 	},
487 
488 	.pfkey_supported = 1,
489 
490 	.desc = {
491 		.sadb_alg_id = SADB_X_EALG_SERPENTCBC,
492 		.sadb_alg_ivlen = 8,
493 		.sadb_alg_minbits = 128,
494 		.sadb_alg_maxbits = 256,
495 	}
496 },
497 {
498 	.name = "cbc(camellia)",
499 	.compat = "camellia",
500 
501 	.uinfo = {
502 		.encr = {
503 			.geniv = "echainiv",
504 			.blockbits = 128,
505 			.defkeybits = 128,
506 		}
507 	},
508 
509 	.pfkey_supported = 1,
510 
511 	.desc = {
512 		.sadb_alg_id = SADB_X_EALG_CAMELLIACBC,
513 		.sadb_alg_ivlen = 8,
514 		.sadb_alg_minbits = 128,
515 		.sadb_alg_maxbits = 256
516 	}
517 },
518 {
519 	.name = "cbc(twofish)",
520 	.compat = "twofish",
521 
522 	.uinfo = {
523 		.encr = {
524 			.geniv = "echainiv",
525 			.blockbits = 128,
526 			.defkeybits = 128,
527 		}
528 	},
529 
530 	.pfkey_supported = 1,
531 
532 	.desc = {
533 		.sadb_alg_id = SADB_X_EALG_TWOFISHCBC,
534 		.sadb_alg_ivlen = 8,
535 		.sadb_alg_minbits = 128,
536 		.sadb_alg_maxbits = 256
537 	}
538 },
539 {
540 	.name = "rfc3686(ctr(aes))",
541 
542 	.uinfo = {
543 		.encr = {
544 			.geniv = "seqiv",
545 			.blockbits = 128,
546 			.defkeybits = 160, /* 128-bit key + 32-bit nonce */
547 		}
548 	},
549 
550 	.pfkey_supported = 1,
551 
552 	.desc = {
553 		.sadb_alg_id = SADB_X_EALG_AESCTR,
554 		.sadb_alg_ivlen	= 8,
555 		.sadb_alg_minbits = 160,
556 		.sadb_alg_maxbits = 288
557 	}
558 },
559 };
560 
561 static struct xfrm_algo_desc calg_list[] = {
562 {
563 	.name = "deflate",
564 	.uinfo = {
565 		.comp = {
566 			.threshold = 90,
567 		}
568 	},
569 	.pfkey_supported = 1,
570 	.desc = { .sadb_alg_id = SADB_X_CALG_DEFLATE }
571 },
572 {
573 	.name = "lzs",
574 	.uinfo = {
575 		.comp = {
576 			.threshold = 90,
577 		}
578 	},
579 	.pfkey_supported = 1,
580 	.desc = { .sadb_alg_id = SADB_X_CALG_LZS }
581 },
582 {
583 	.name = "lzjh",
584 	.uinfo = {
585 		.comp = {
586 			.threshold = 50,
587 		}
588 	},
589 	.pfkey_supported = 1,
590 	.desc = { .sadb_alg_id = SADB_X_CALG_LZJH }
591 },
592 };
593 
594 static inline int aalg_entries(void)
595 {
596 	return ARRAY_SIZE(aalg_list);
597 }
598 
599 static inline int ealg_entries(void)
600 {
601 	return ARRAY_SIZE(ealg_list);
602 }
603 
604 static inline int calg_entries(void)
605 {
606 	return ARRAY_SIZE(calg_list);
607 }
608 
609 struct xfrm_algo_list {
610 	struct xfrm_algo_desc *algs;
611 	int entries;
612 	u32 type;
613 	u32 mask;
614 };
615 
616 static const struct xfrm_algo_list xfrm_aead_list = {
617 	.algs = aead_list,
618 	.entries = ARRAY_SIZE(aead_list),
619 	.type = CRYPTO_ALG_TYPE_AEAD,
620 	.mask = CRYPTO_ALG_TYPE_MASK,
621 };
622 
623 static const struct xfrm_algo_list xfrm_aalg_list = {
624 	.algs = aalg_list,
625 	.entries = ARRAY_SIZE(aalg_list),
626 	.type = CRYPTO_ALG_TYPE_HASH,
627 	.mask = CRYPTO_ALG_TYPE_HASH_MASK,
628 };
629 
630 static const struct xfrm_algo_list xfrm_ealg_list = {
631 	.algs = ealg_list,
632 	.entries = ARRAY_SIZE(ealg_list),
633 	.type = CRYPTO_ALG_TYPE_BLKCIPHER,
634 	.mask = CRYPTO_ALG_TYPE_BLKCIPHER_MASK,
635 };
636 
637 static const struct xfrm_algo_list xfrm_calg_list = {
638 	.algs = calg_list,
639 	.entries = ARRAY_SIZE(calg_list),
640 	.type = CRYPTO_ALG_TYPE_COMPRESS,
641 	.mask = CRYPTO_ALG_TYPE_MASK,
642 };
643 
644 static struct xfrm_algo_desc *xfrm_find_algo(
645 	const struct xfrm_algo_list *algo_list,
646 	int match(const struct xfrm_algo_desc *entry, const void *data),
647 	const void *data, int probe)
648 {
649 	struct xfrm_algo_desc *list = algo_list->algs;
650 	int i, status;
651 
652 	for (i = 0; i < algo_list->entries; i++) {
653 		if (!match(list + i, data))
654 			continue;
655 
656 		if (list[i].available)
657 			return &list[i];
658 
659 		if (!probe)
660 			break;
661 
662 		status = crypto_has_alg(list[i].name, algo_list->type,
663 					algo_list->mask);
664 		if (!status)
665 			break;
666 
667 		list[i].available = status;
668 		return &list[i];
669 	}
670 	return NULL;
671 }
672 
673 static int xfrm_alg_id_match(const struct xfrm_algo_desc *entry,
674 			     const void *data)
675 {
676 	return entry->desc.sadb_alg_id == (unsigned long)data;
677 }
678 
679 struct xfrm_algo_desc *xfrm_aalg_get_byid(int alg_id)
680 {
681 	return xfrm_find_algo(&xfrm_aalg_list, xfrm_alg_id_match,
682 			      (void *)(unsigned long)alg_id, 1);
683 }
684 EXPORT_SYMBOL_GPL(xfrm_aalg_get_byid);
685 
686 struct xfrm_algo_desc *xfrm_ealg_get_byid(int alg_id)
687 {
688 	return xfrm_find_algo(&xfrm_ealg_list, xfrm_alg_id_match,
689 			      (void *)(unsigned long)alg_id, 1);
690 }
691 EXPORT_SYMBOL_GPL(xfrm_ealg_get_byid);
692 
693 struct xfrm_algo_desc *xfrm_calg_get_byid(int alg_id)
694 {
695 	return xfrm_find_algo(&xfrm_calg_list, xfrm_alg_id_match,
696 			      (void *)(unsigned long)alg_id, 1);
697 }
698 EXPORT_SYMBOL_GPL(xfrm_calg_get_byid);
699 
700 static int xfrm_alg_name_match(const struct xfrm_algo_desc *entry,
701 			       const void *data)
702 {
703 	const char *name = data;
704 
705 	return name && (!strcmp(name, entry->name) ||
706 			(entry->compat && !strcmp(name, entry->compat)));
707 }
708 
709 struct xfrm_algo_desc *xfrm_aalg_get_byname(const char *name, int probe)
710 {
711 	return xfrm_find_algo(&xfrm_aalg_list, xfrm_alg_name_match, name,
712 			      probe);
713 }
714 EXPORT_SYMBOL_GPL(xfrm_aalg_get_byname);
715 
716 struct xfrm_algo_desc *xfrm_ealg_get_byname(const char *name, int probe)
717 {
718 	return xfrm_find_algo(&xfrm_ealg_list, xfrm_alg_name_match, name,
719 			      probe);
720 }
721 EXPORT_SYMBOL_GPL(xfrm_ealg_get_byname);
722 
723 struct xfrm_algo_desc *xfrm_calg_get_byname(const char *name, int probe)
724 {
725 	return xfrm_find_algo(&xfrm_calg_list, xfrm_alg_name_match, name,
726 			      probe);
727 }
728 EXPORT_SYMBOL_GPL(xfrm_calg_get_byname);
729 
730 struct xfrm_aead_name {
731 	const char *name;
732 	int icvbits;
733 };
734 
735 static int xfrm_aead_name_match(const struct xfrm_algo_desc *entry,
736 				const void *data)
737 {
738 	const struct xfrm_aead_name *aead = data;
739 	const char *name = aead->name;
740 
741 	return aead->icvbits == entry->uinfo.aead.icv_truncbits && name &&
742 	       !strcmp(name, entry->name);
743 }
744 
745 struct xfrm_algo_desc *xfrm_aead_get_byname(const char *name, int icv_len, int probe)
746 {
747 	struct xfrm_aead_name data = {
748 		.name = name,
749 		.icvbits = icv_len,
750 	};
751 
752 	return xfrm_find_algo(&xfrm_aead_list, xfrm_aead_name_match, &data,
753 			      probe);
754 }
755 EXPORT_SYMBOL_GPL(xfrm_aead_get_byname);
756 
757 struct xfrm_algo_desc *xfrm_aalg_get_byidx(unsigned int idx)
758 {
759 	if (idx >= aalg_entries())
760 		return NULL;
761 
762 	return &aalg_list[idx];
763 }
764 EXPORT_SYMBOL_GPL(xfrm_aalg_get_byidx);
765 
766 struct xfrm_algo_desc *xfrm_ealg_get_byidx(unsigned int idx)
767 {
768 	if (idx >= ealg_entries())
769 		return NULL;
770 
771 	return &ealg_list[idx];
772 }
773 EXPORT_SYMBOL_GPL(xfrm_ealg_get_byidx);
774 
775 /*
776  * Probe for the availability of crypto algorithms, and set the available
777  * flag for any algorithms found on the system.  This is typically called by
778  * pfkey during userspace SA add, update or register.
779  */
780 void xfrm_probe_algs(void)
781 {
782 	int i, status;
783 
784 	BUG_ON(in_softirq());
785 
786 	for (i = 0; i < aalg_entries(); i++) {
787 		status = crypto_has_ahash(aalg_list[i].name, 0, 0);
788 		if (aalg_list[i].available != status)
789 			aalg_list[i].available = status;
790 	}
791 
792 	for (i = 0; i < ealg_entries(); i++) {
793 		status = crypto_has_skcipher(ealg_list[i].name, 0, 0);
794 		if (ealg_list[i].available != status)
795 			ealg_list[i].available = status;
796 	}
797 
798 	for (i = 0; i < calg_entries(); i++) {
799 		status = crypto_has_comp(calg_list[i].name, 0,
800 					 CRYPTO_ALG_ASYNC);
801 		if (calg_list[i].available != status)
802 			calg_list[i].available = status;
803 	}
804 }
805 EXPORT_SYMBOL_GPL(xfrm_probe_algs);
806 
807 int xfrm_count_pfkey_auth_supported(void)
808 {
809 	int i, n;
810 
811 	for (i = 0, n = 0; i < aalg_entries(); i++)
812 		if (aalg_list[i].available && aalg_list[i].pfkey_supported)
813 			n++;
814 	return n;
815 }
816 EXPORT_SYMBOL_GPL(xfrm_count_pfkey_auth_supported);
817 
818 int xfrm_count_pfkey_enc_supported(void)
819 {
820 	int i, n;
821 
822 	for (i = 0, n = 0; i < ealg_entries(); i++)
823 		if (ealg_list[i].available && ealg_list[i].pfkey_supported)
824 			n++;
825 	return n;
826 }
827 EXPORT_SYMBOL_GPL(xfrm_count_pfkey_enc_supported);
828 
829 MODULE_LICENSE("GPL");
830