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