diff options
| -rw-r--r-- | include/linux/pfkeyv2.h | 26 | ||||
| -rw-r--r-- | include/net/xfrm.h | 41 | ||||
| -rw-r--r-- | net/ipv4/Makefile | 2 | ||||
| -rw-r--r-- | net/ipv4/ah.c | 118 | ||||
| -rw-r--r-- | net/ipv4/xfrm_algo.c | 348 | ||||
| -rw-r--r-- | net/key/af_key.c | 274 | ||||
| -rw-r--r-- | net/netsyms.c | 9 |
7 files changed, 597 insertions, 221 deletions
diff --git a/include/linux/pfkeyv2.h b/include/linux/pfkeyv2.h index ff599ee1cf3d..c6e4e6e29f10 100644 --- a/include/linux/pfkeyv2.h +++ b/include/linux/pfkeyv2.h @@ -242,17 +242,25 @@ struct sadb_x_ipsecrequest { #define SADB_SATYPE_MAX 9 /* Authentication algorithms */ -#define SADB_AALG_NONE 0 -#define SADB_AALG_MD5HMAC 2 -#define SADB_AALG_SHA1HMAC 3 -#define SADB_AALG_MAX 3 +#define SADB_AALG_NONE 0 +#define SADB_AALG_MD5HMAC 2 +#define SADB_AALG_SHA1HMAC 3 +#define SADB_X_AALG_SHA2_256HMAC 5 +#define SADB_X_AALG_SHA2_384HMAC 6 +#define SADB_X_AALG_SHA2_512HMAC 7 +#define SADB_X_AALG_RIPEMD160HMAC 8 +#define SADB_X_AALG_NULL 251 /* kame */ +#define SADB_AALG_MAX 251 /* Encryption algorithms */ -#define SADB_EALG_NONE 0 -#define SADB_EALG_DESCBC 1 -#define SADB_EALG_3DESCBC 2 -#define SADB_EALG_NULL 11 -#define SADB_EALG_MAX 11 +#define SADB_EALG_NONE 0 +#define SADB_EALG_DESCBC 1 +#define SADB_EALG_3DESCBC 2 +#define SADB_X_EALG_CASTCBC 6 +#define SADB_X_EALG_BLOWFISHCBC 7 +#define SADB_EALG_NULL 11 +#define SADB_X_EALG_AESCBC 12 +#define SADB_EALG_MAX 12 /* Extension Header values */ #define SADB_EXT_RESERVED 0 diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 37cb371e930a..82d2187eeb2a 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -1,13 +1,19 @@ +#ifndef _NET_XFRM_H +#define _NET_XFRM_H + #include <linux/xfrm.h> #include <linux/spinlock.h> #include <linux/list.h> #include <linux/skbuff.h> #include <linux/netdevice.h> #include <linux/crypto.h> +#include <linux/pfkeyv2.h> #include <net/dst.h> #include <net/route.h> +#define XFRM_ALIGN8(len) (((len) + 7) & ~7) + extern struct semaphore xfrm_cfg_sem; /* Organization of SPD aka "XFRM rules" @@ -347,6 +353,29 @@ static inline void xfrm_sk_free_policy(struct sock *sk) } } +/* + * xfrm algorithm information + */ +struct xfrm_algo_auth_info { + u16 icv_truncbits; + u16 icv_fullbits; +}; + +struct xfrm_algo_encr_info { + u16 blockbits; + u16 defkeybits; +}; + +struct xfrm_algo_desc { + char *name; + u8 available:1; + union { + struct xfrm_algo_auth_info auth; + struct xfrm_algo_encr_info encr; + } uinfo; + struct sadb_alg desc; +}; + extern void xfrm_state_init(void); extern void xfrm_input_init(void); extern int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*), void *); @@ -385,3 +414,15 @@ extern wait_queue_head_t km_waitq; extern void km_warn_expired(struct xfrm_state *x); extern void km_expired(struct xfrm_state *x); extern int km_query(struct xfrm_state *x, struct xfrm_tmpl *, struct xfrm_policy *pol); + +extern void xfrm_probe_algs(void); +extern int xfrm_count_auth_supported(void); +extern int xfrm_count_enc_supported(void); +extern struct xfrm_algo_desc *xfrm_aalg_get_byidx(unsigned int idx); +extern struct xfrm_algo_desc *xfrm_ealg_get_byidx(unsigned int idx); +extern struct xfrm_algo_desc *xfrm_aalg_get_byid(int alg_id); +extern struct xfrm_algo_desc *xfrm_ealg_get_byid(int alg_id); +extern struct xfrm_algo_desc *xfrm_aalg_get_byname(char *name); +extern struct xfrm_algo_desc *xfrm_ealg_get_byname(char *name); + +#endif /* _NET_XFRM_H */ diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile index 5e758522316d..7ce979fcaae4 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile @@ -22,4 +22,4 @@ obj-$(CONFIG_IP_PNP) += ipconfig.o obj-$(CONFIG_NETFILTER) += netfilter/ obj-$(CONFIG_XFRM_USER) += xfrm_user.o -obj-y += xfrm_policy.o xfrm_state.o xfrm_input.o +obj-y += xfrm_policy.o xfrm_state.o xfrm_input.o xfrm_algo.o diff --git a/net/ipv4/ah.c b/net/ipv4/ah.c index efccce969e55..ba5abf93f0aa 100644 --- a/net/ipv4/ah.c +++ b/net/ipv4/ah.c @@ -7,26 +7,31 @@ #include <net/icmp.h> #include <asm/scatterlist.h> +#define AH_HLEN_NOICV 12 + +typedef void (icv_update_fn_t)(struct crypto_tfm *, + struct scatterlist *, unsigned int); + struct ah_data { u8 *key; int key_len; - u8 *work_digest; - int digest_len; + u8 *work_icv; + int icv_full_len; + int icv_trunc_len; - void (*digest)(struct ah_data*, - struct sk_buff *skb, - u8 *digest); + void (*icv)(struct ah_data*, + struct sk_buff *skb, u8 *icv); struct crypto_tfm *tfm; }; /* Clear mutable options and find final destination to substitute - * into IP header for digest calculation. Options are already checked + * into IP header for icv calculation. Options are already checked * for validity, so paranoia is not required. */ -int ip_clear_mutable_options(struct iphdr *iph, u32 *daddr) +static int ip_clear_mutable_options(struct iphdr *iph, u32 *daddr) { unsigned char * optptr = (unsigned char*)(iph+1); int l = iph->ihl*4 - 20; @@ -66,7 +71,8 @@ int ip_clear_mutable_options(struct iphdr *iph, u32 *daddr) return 0; } -void skb_ah_walk(const struct sk_buff *skb, struct crypto_tfm *tfm) +static void skb_ah_walk(const struct sk_buff *skb, + struct crypto_tfm *tfm, icv_update_fn_t icv_update) { int offset = 0; int len = skb->len; @@ -83,7 +89,7 @@ void skb_ah_walk(const struct sk_buff *skb, struct crypto_tfm *tfm) sg.offset = (unsigned long)(skb->data + offset) % PAGE_SIZE; sg.length = copy; - crypto_hmac_update(tfm, &sg, 1); + icv_update(tfm, &sg, 1); if ((len -= copy) == 0) return; @@ -106,7 +112,7 @@ void skb_ah_walk(const struct sk_buff *skb, struct crypto_tfm *tfm) sg.offset = frag->page_offset + offset-start; sg.length = copy; - crypto_hmac_update(tfm, &sg, 1); + icv_update(tfm, &sg, 1); if (!(len -= copy)) return; @@ -127,7 +133,7 @@ void skb_ah_walk(const struct sk_buff *skb, struct crypto_tfm *tfm) if ((copy = end - offset) > 0) { if (copy > len) copy = len; - skb_ah_walk(list, tfm); + skb_ah_walk(list, tfm, icv_update); if ((len -= copy) == 0) return; offset += copy; @@ -144,14 +150,14 @@ ah_hmac_digest(struct ah_data *ahp, struct sk_buff *skb, u8 *auth_data) { struct crypto_tfm *tfm = ahp->tfm; - memset(auth_data, 0, ahp->digest_len); + memset(auth_data, 0, ahp->icv_trunc_len); crypto_hmac_init(tfm, ahp->key, &ahp->key_len); - skb_ah_walk(skb, tfm); - crypto_hmac_final(tfm, ahp->key, &ahp->key_len, ahp->work_digest); - memcpy(auth_data, ahp->work_digest, ahp->digest_len); + skb_ah_walk(skb, tfm, crypto_hmac_update); + crypto_hmac_final(tfm, ahp->key, &ahp->key_len, ahp->work_icv); + memcpy(auth_data, ahp->work_icv, ahp->icv_trunc_len); } -int ah_output(struct sk_buff *skb) +static int ah_output(struct sk_buff *skb) { int err; struct dst_entry *dst = skb->dst; @@ -210,11 +216,13 @@ int ah_output(struct sk_buff *skb) ah->nexthdr = iph->protocol; } ahp = x->data; - ah->hdrlen = (((ahp->digest_len + 12 + 7)&~7)>>2)-2; + ah->hdrlen = (XFRM_ALIGN8(ahp->icv_trunc_len + + AH_HLEN_NOICV) >> 2) - 2; + ah->reserved = 0; ah->spi = x->id.spi; ah->seq_no = htonl(++x->replay.oseq); - ahp->digest(ahp, skb, ah->auth_data); + ahp->icv(ahp, skb, ah->auth_data); top_iph->tos = iph->tos; top_iph->ttl = iph->ttl; if (x->props.mode) { @@ -246,6 +254,7 @@ error_nolock: int ah_input(struct xfrm_state *x, struct sk_buff *skb) { + int ah_hlen; struct iphdr *iph; struct ip_auth_hdr *ah; struct ah_data *ahp; @@ -255,13 +264,14 @@ int ah_input(struct xfrm_state *x, struct sk_buff *skb) goto out; ah = (struct ip_auth_hdr*)skb->data; - ahp = x->data; - - if (((ah->hdrlen+2)<<2) != ((ahp->digest_len + 12 + 7)&~7)) + ah_hlen = (ah->hdrlen + 2) << 2; + + if (ah_hlen != XFRM_ALIGN8(ahp->icv_full_len + AH_HLEN_NOICV) && + ah_hlen != XFRM_ALIGN8(ahp->icv_trunc_len + AH_HLEN_NOICV)) goto out; - if (!pskb_may_pull(skb, (ah->hdrlen+2)<<2)) + if (!pskb_may_pull(skb, ah_hlen)) goto out; /* We are going to _remove_ AH header to keep sockets happy, @@ -285,17 +295,18 @@ int ah_input(struct xfrm_state *x, struct sk_buff *skb) goto out; } { - u8 auth_data[ahp->digest_len]; - memcpy(auth_data, ah->auth_data, ahp->digest_len); + u8 auth_data[ahp->icv_trunc_len]; + + memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len); skb_push(skb, skb->data - skb->nh.raw); - ahp->digest(ahp, skb, ah->auth_data); - if (memcmp(ah->auth_data, auth_data, ahp->digest_len)) { + ahp->icv(ahp, skb, ah->auth_data); + if (memcmp(ah->auth_data, auth_data, ahp->icv_trunc_len)) { x->stats.integrity_failed++; goto out; } } ((struct iphdr*)work_buf)->protocol = ah->nexthdr; - skb->nh.raw = skb_pull(skb, (ah->hdrlen+2)<<2); + skb->nh.raw = skb_pull(skb, ah_hlen); memcpy(skb->nh.raw, work_buf, iph->ihl*4); skb->nh.iph->tot_len = htons(skb->len); skb_pull(skb, skb->nh.iph->ihl*4); @@ -325,12 +336,13 @@ void ah4_err(struct sk_buff *skb, u32 info) xfrm_state_put(x); } -int ah_init_state(struct xfrm_state *x, void *args) +static int ah_init_state(struct xfrm_state *x, void *args) { struct ah_data *ahp = NULL; + struct xfrm_algo_desc *aalg_desc; - if (x->aalg == NULL || x->aalg->alg_key_len == 0 || - x->aalg->alg_key_len > 512) + /* null auth can use a zero length key */ + if (x->aalg->alg_key_len > 512) goto error; ahp = kmalloc(sizeof(*ahp), GFP_KERNEL); @@ -344,13 +356,33 @@ int ah_init_state(struct xfrm_state *x, void *args) ahp->tfm = crypto_alloc_tfm(x->aalg->alg_name, 0); if (!ahp->tfm) goto error; - ahp->digest = ah_hmac_digest; - ahp->digest_len = 12; - ahp->work_digest = kmalloc(crypto_tfm_alg_digestsize(ahp->tfm), - GFP_KERNEL); - if (!ahp->work_digest) + ahp->icv = ah_hmac_digest; + + /* + * Lookup the algorithm description maintained by pfkey, + * verify crypto transform properties, and store information + * we need for AH processing. This lookup cannot fail here + * after a successful crypto_alloc_tfm(). + */ + aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name); + BUG_ON(!aalg_desc); + + if (aalg_desc->uinfo.auth.icv_fullbits/8 != + crypto_tfm_alg_digestsize(ahp->tfm)) { + printk(KERN_INFO "AH: %s digestsize %u != %hu\n", + x->aalg->alg_name, crypto_tfm_alg_digestsize(ahp->tfm), + aalg_desc->uinfo.auth.icv_fullbits/8); + goto error; + } + + ahp->icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8; + ahp->icv_trunc_len = aalg_desc->uinfo.auth.icv_truncbits/8; + + ahp->work_icv = kmalloc(ahp->icv_full_len, GFP_KERNEL); + if (!ahp->work_icv) goto error; - x->props.header_len = (12 + ahp->digest_len + 7)&~7; + + x->props.header_len = XFRM_ALIGN8(ahp->icv_trunc_len + AH_HLEN_NOICV); if (x->props.mode) x->props.header_len += 20; x->data = ahp; @@ -359,8 +391,8 @@ int ah_init_state(struct xfrm_state *x, void *args) error: if (ahp) { - if (ahp->work_digest) - kfree(ahp->work_digest); + if (ahp->work_icv) + kfree(ahp->work_icv); if (ahp->tfm) crypto_free_tfm(ahp->tfm); kfree(ahp); @@ -368,13 +400,13 @@ error: return -EINVAL; } -void ah_destroy(struct xfrm_state *x) +static void ah_destroy(struct xfrm_state *x) { struct ah_data *ahp = x->data; - if (ahp->work_digest) { - kfree(ahp->work_digest); - ahp->work_digest = NULL; + if (ahp->work_icv) { + kfree(ahp->work_icv); + ahp->work_icv = NULL; } if (ahp->tfm) { crypto_free_tfm(ahp->tfm); @@ -399,7 +431,7 @@ static struct inet_protocol ah4_protocol = { .no_policy = 1, }; -int __init ah4_init(void) +static int __init ah4_init(void) { SET_MODULE_OWNER(&ah_type); if (xfrm_register_type(&ah_type) < 0) { diff --git a/net/ipv4/xfrm_algo.c b/net/ipv4/xfrm_algo.c new file mode 100644 index 000000000000..07744c5a953e --- /dev/null +++ b/net/ipv4/xfrm_algo.c @@ -0,0 +1,348 @@ +/* + * xfrm algorithm interface + * + * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> + * + * 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. + */ +#include <linux/kernel.h> +#include <linux/pfkeyv2.h> +#include <net/xfrm.h> + +/* + * Algorithms supported by IPsec. These entries contain properties which + * are used in key negotiation and xfrm processing, and are used to verify + * that instantiated crypto transforms have correct parameters for IPsec + * purposes. + */ +static struct xfrm_algo_desc aalg_list[] = { +{ + .name = "digest_null", + + .uinfo = { + .auth = { + .icv_truncbits = 0, + .icv_fullbits = 0, + } + }, + + .desc = { + .sadb_alg_id = SADB_X_AALG_NULL, + .sadb_alg_ivlen = 0, + .sadb_alg_minbits = 0, + .sadb_alg_maxbits = 0 + } +}, +{ + .name = "md5", + + .uinfo = { + .auth = { + .icv_truncbits = 96, + .icv_fullbits = 128, + } + }, + + .desc = { + .sadb_alg_id = SADB_AALG_MD5HMAC, + .sadb_alg_ivlen = 0, + .sadb_alg_minbits = 128, + .sadb_alg_maxbits = 128 + } +}, +{ + .name = "sha1", + + .uinfo = { + .auth = { + .icv_truncbits = 96, + .icv_fullbits = 160, + } + }, + + .desc = { + .sadb_alg_id = SADB_AALG_SHA1HMAC, + .sadb_alg_ivlen = 0, + .sadb_alg_minbits = 160, + .sadb_alg_maxbits = 160 + } +}, +{ + .name = "sha256", + + .uinfo = { + .auth = { + .icv_truncbits = 128, + .icv_fullbits = 256, + } + }, + + .desc = { + .sadb_alg_id = SADB_X_AALG_SHA2_256HMAC, + .sadb_alg_ivlen = 0, + .sadb_alg_minbits = 256, + .sadb_alg_maxbits = 256 + } +}, +{ + .name = "ripemd160", + + .uinfo = { + .auth = { + .icv_truncbits = 96, + .icv_fullbits = 160, + } + }, + + .desc = { + .sadb_alg_id = SADB_X_AALG_RIPEMD160HMAC, + .sadb_alg_ivlen = 0, + .sadb_alg_minbits = 160, + .sadb_alg_maxbits = 160 + } +}, +}; + +static struct xfrm_algo_desc ealg_list[] = { +{ + .name = "cipher_null", + + .uinfo = { + .encr = { + .blockbits = 8, + .defkeybits = 0, + } + }, + + .desc = { + .sadb_alg_id = SADB_EALG_NULL, + .sadb_alg_ivlen = 0, + .sadb_alg_minbits = 0, + .sadb_alg_maxbits = 0 + } +}, +{ + .name = "des", + + .uinfo = { + .encr = { + .blockbits = 64, + .defkeybits = 64, + } + }, + + .desc = { + .sadb_alg_id = SADB_EALG_DESCBC, + .sadb_alg_ivlen = 8, + .sadb_alg_minbits = 64, + .sadb_alg_maxbits = 64 + } +}, +{ + .name = "des3_ede", + + .uinfo = { + .encr = { + .blockbits = 64, + .defkeybits = 192, + } + }, + + .desc = { + .sadb_alg_id = SADB_EALG_3DESCBC, + .sadb_alg_ivlen = 8, + .sadb_alg_minbits = 192, + .sadb_alg_maxbits = 192 + } +}, +{ + .name = "cast128", + + .uinfo = { + .encr = { + .blockbits = 64, + .defkeybits = 128, + } + }, + + .desc = { + .sadb_alg_id = SADB_X_EALG_CASTCBC, + .sadb_alg_ivlen = 8, + .sadb_alg_minbits = 40, + .sadb_alg_maxbits = 128 + } +}, +{ + .name = "blowfish", + + .uinfo = { + .encr = { + .blockbits = 64, + .defkeybits = 128, + } + }, + + .desc = { + .sadb_alg_id = SADB_X_EALG_BLOWFISHCBC, + .sadb_alg_ivlen = 8, + .sadb_alg_minbits = 40, + .sadb_alg_maxbits = 448 + } +}, +{ + .name = "aes", + + .uinfo = { + .encr = { + .blockbits = 128, + .defkeybits = 128, + } + }, + + .desc = { + .sadb_alg_id = SADB_X_EALG_AESCBC, + .sadb_alg_ivlen = 8, + .sadb_alg_minbits = 128, + .sadb_alg_maxbits = 256 + } +}, +}; + +static inline int aalg_entries(void) +{ + return sizeof(aalg_list) / sizeof(aalg_list[0]); +} + +static inline int ealg_entries(void) +{ + return sizeof(ealg_list) / sizeof(ealg_list[0]); +} + +struct xfrm_algo_desc *xfrm_aalg_get_byid(int alg_id) +{ + int i; + + for (i = 0; i < aalg_entries(); i++) { + if (aalg_list[i].desc.sadb_alg_id == alg_id) { + if (aalg_list[i].available) + return &aalg_list[i]; + else + break; + } + } + return NULL; +} + +struct xfrm_algo_desc *xfrm_ealg_get_byid(int alg_id) +{ + int i; + + for (i = 0; i < ealg_entries(); i++) { + if (ealg_list[i].desc.sadb_alg_id == alg_id) { + if (ealg_list[i].available) + return &ealg_list[i]; + else + break; + } + } + return NULL; +} + +struct xfrm_algo_desc *xfrm_aalg_get_byname(char *name) +{ + int i; + + if (!name) + return NULL; + + for (i=0; i < aalg_entries(); i++) { + if (strcmp(name, aalg_list[i].name) == 0) { + if (aalg_list[i].available) + return &aalg_list[i]; + else + break; + } + } + return NULL; +} + +struct xfrm_algo_desc *xfrm_ealg_get_byname(char *name) +{ + int i; + + if (!name) + return NULL; + + for (i=0; i < ealg_entries(); i++) { + if (strcmp(name, ealg_list[i].name) == 0) { + if (ealg_list[i].available) + return &ealg_list[i]; + else + break; + } + } + return NULL; +} + +struct xfrm_algo_desc *xfrm_aalg_get_byidx(unsigned int idx) +{ + if (idx >= aalg_entries()) + return NULL; + + return &aalg_list[idx]; +} + +struct xfrm_algo_desc *xfrm_ealg_get_byidx(unsigned int idx) +{ + if (idx >= ealg_entries()) + return NULL; + + return &ealg_list[idx]; +} + +/* + * Probe for the availability of crypto algorithms, and set the available + * flag for any algorithms found on the system. This is typically called by + * pfkey during userspace SA add, update or register. + */ +void xfrm_probe_algs(void) +{ + int i, status; + + BUG_ON(in_softirq()); + + for (i = 0; i < aalg_entries(); i++) { + status = crypto_alg_available(aalg_list[i].name, 0); + if (aalg_list[i].available != status) + aalg_list[i].available = status; + } + + for (i = 0; i < ealg_entries(); i++) { + status = crypto_alg_available(ealg_list[i].name, 0); + if (ealg_list[i].available != status) + ealg_list[i].available = status; + } +} + +int xfrm_count_auth_supported(void) +{ + int i, n; + + for (i = 0, n = 0; i < aalg_entries(); i++) + if (aalg_list[i].available) + n++; + return n; +} + +int xfrm_count_enc_supported(void) +{ + int i, n; + + for (i = 0, n = 0; i < ealg_entries(); i++) + if (ealg_list[i].available) + n++; + return n; +} diff --git a/net/key/af_key.c b/net/key/af_key.c index f26b06de650e..f2b013194120 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -553,118 +553,6 @@ static struct xfrm_state *pfkey_xfrm_state_lookup(struct sadb_msg *hdr, void ** return x; } -/* Table of algos supported by pfkeyv2 interface. */ - -struct algo_desc { - char *id; - struct sadb_alg desc; -}; - -struct algo_desc aalg_list[] = { -{ .id = NULL, - .desc = { - .sadb_alg_id = SADB_AALG_NONE, - .sadb_alg_ivlen = 0, - .sadb_alg_minbits = 0, - .sadb_alg_maxbits = 0 - } -}, -{ .id = "md5", - .desc = { - .sadb_alg_id = SADB_AALG_MD5HMAC, - .sadb_alg_ivlen = 0, - .sadb_alg_minbits = 128, - .sadb_alg_maxbits = 128 - } -}, -{ .id = "sha1", - .desc = { - .sadb_alg_id = SADB_AALG_SHA1HMAC, - .sadb_alg_ivlen = 0, - .sadb_alg_minbits = 160, - .sadb_alg_maxbits = 160 - } -} -}; - -struct algo_desc ealg_list[] = { -{ .id = NULL, - .desc = { - .sadb_alg_id = SADB_EALG_NONE, - .sadb_alg_ivlen = 0, - .sadb_alg_minbits = 0, - .sadb_alg_maxbits = 2048 - } -}, -{ .id = "des", - .desc = { - .sadb_alg_id = SADB_EALG_DESCBC, - .sadb_alg_ivlen = 8, - .sadb_alg_minbits = 64, - .sadb_alg_maxbits = 64 - } -}, -{ .id = "des3_ede", - .desc = { - .sadb_alg_id = SADB_EALG_3DESCBC, - .sadb_alg_ivlen = 8, - .sadb_alg_minbits = 192, - .sadb_alg_maxbits = 192 - } -} -}; - -static struct algo_desc *aalg_get_byid(int alg_id) -{ - int i; - - for (i=0; i<sizeof(aalg_list)/sizeof(aalg_list[0]); i++) { - if (aalg_list[i].desc.sadb_alg_id == alg_id) - return &aalg_list[i]; - } - return NULL; -} - -static struct algo_desc *ealg_get_byid(int alg_id) -{ - int i; - - for (i=0; i<sizeof(ealg_list)/sizeof(ealg_list[0]); i++) { - if (ealg_list[i].desc.sadb_alg_id == alg_id) - return &ealg_list[i]; - } - return NULL; -} - -static struct algo_desc *aalg_get_byname(char *name) -{ - int i; - - if (!name) - return NULL; - - for (i=1; i<sizeof(aalg_list)/sizeof(aalg_list[0]); i++) { - if (strcmp(name, aalg_list[i].id) == 0) - return &aalg_list[i]; - } - return NULL; -} - -static struct algo_desc *ealg_get_byname(char *name) -{ - int i; - - if (!name) - return NULL; - - for (i=1; i<sizeof(ealg_list)/sizeof(ealg_list[0]); i++) { - if (strcmp(name, ealg_list[i].id) == 0) - return &ealg_list[i]; - } - return NULL; -} - - #define PFKEY_ALIGN8(a) (1 + (((a) - 1) | (8 - 1))) static struct sk_buff * pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys, int hsc) { @@ -730,12 +618,12 @@ static struct sk_buff * pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys, sa->sadb_sa_state = SADB_SASTATE_DEAD; sa->sadb_sa_auth = 0; if (x->aalg) { - struct algo_desc *a = aalg_get_byname(x->aalg->alg_name); + struct xfrm_algo_desc *a = xfrm_aalg_get_byname(x->aalg->alg_name); sa->sadb_sa_auth = a ? a->desc.sadb_alg_id : 0; } sa->sadb_sa_encrypt = 0; if (x->ealg) { - struct algo_desc *a = ealg_get_byname(x->ealg->alg_name); + struct xfrm_algo_desc *a = xfrm_ealg_get_byname(x->ealg->alg_name); sa->sadb_sa_encrypt = a ? a->desc.sadb_alg_id : 0; } sa->sadb_sa_flags = 0; @@ -938,7 +826,7 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr, key = (struct sadb_key*) ext_hdrs[SADB_EXT_KEY_AUTH-1]; if (sa->sadb_sa_auth) { int keysize = 0; - struct algo_desc *a = aalg_get_byid(sa->sadb_sa_auth); + struct xfrm_algo_desc *a = xfrm_aalg_get_byid(sa->sadb_sa_auth); if (!a) goto out; if (key) @@ -946,7 +834,7 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr, x->aalg = kmalloc(sizeof(*x->aalg) + keysize, GFP_KERNEL); if (!x->aalg) goto out; - strcpy(x->aalg->alg_name, a->id); + strcpy(x->aalg->alg_name, a->name); x->aalg->alg_key_len = 0; if (key) { x->aalg->alg_key_len = key->sadb_key_bits; @@ -958,7 +846,7 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr, key = (struct sadb_key*) ext_hdrs[SADB_EXT_KEY_ENCRYPT-1]; if (sa->sadb_sa_encrypt) { int keysize = 0; - struct algo_desc *a = ealg_get_byid(sa->sadb_sa_encrypt); + struct xfrm_algo_desc *a = xfrm_ealg_get_byid(sa->sadb_sa_encrypt); if (!a) goto out; if (key) @@ -966,7 +854,7 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr, x->ealg = kmalloc(sizeof(*x->ealg) + keysize, GFP_KERNEL); if (!x->ealg) goto out; - strcpy(x->ealg->alg_name, a->id); + strcpy(x->ealg->alg_name, a->name); x->ealg->alg_key_len = 0; if (key) { x->ealg->alg_key_len = key->sadb_key_bits; @@ -1131,6 +1019,8 @@ static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, struct xfrm_state *x; struct xfrm_state *x1; + xfrm_probe_algs(); + x = pfkey_msg2xfrm_state(hdr, ext_hdrs); if (IS_ERR(x)) return PTR_ERR(x); @@ -1238,17 +1128,21 @@ static struct sk_buff *compose_sadb_supported(struct sadb_msg *orig, int allocat { struct sk_buff *skb; struct sadb_msg *hdr; - int len, ah_len, esp_len, i; - - ah_len = sizeof(aalg_list)/sizeof(aalg_list[0]) - 1; - ah_len *= sizeof(struct sadb_alg); - esp_len = sizeof(ealg_list)/sizeof(ealg_list[0]) - 1; - esp_len *= sizeof(struct sadb_alg); - if (ah_len) - ah_len += sizeof(struct sadb_supported); - if (esp_len) - esp_len += sizeof(struct sadb_supported); - len = esp_len + ah_len + sizeof(struct sadb_msg); + 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); + } + + enc_len = xfrm_count_enc_supported(); + if (enc_len) { + enc_len *= sizeof(struct sadb_alg); + enc_len += sizeof(struct sadb_supported); + } + + len = enc_len + auth_len + sizeof(struct sadb_msg); skb = alloc_skb(len + 16, allocation); if (!skb) @@ -1259,32 +1153,42 @@ static struct sk_buff *compose_sadb_supported(struct sadb_msg *orig, int allocat hdr->sadb_msg_errno = 0; hdr->sadb_msg_len = len / sizeof(uint64_t); - if (ah_len) { + if (auth_len) { struct sadb_supported *sp; struct sadb_alg *ap; - sp = (struct sadb_supported *) skb_put(skb, ah_len); + sp = (struct sadb_supported *) skb_put(skb, auth_len); ap = (struct sadb_alg *) (sp + 1); - sp->sadb_supported_len = ah_len / sizeof(uint64_t); + sp->sadb_supported_len = auth_len / sizeof(uint64_t); sp->sadb_supported_exttype = SADB_EXT_SUPPORTED_AUTH; - for (i=1; i<sizeof(aalg_list)/sizeof(aalg_list[0]); i++) - *ap++ = aalg_list[i].desc; + for (i = 0; ; i++) { + struct xfrm_algo_desc *aalg = xfrm_aalg_get_byidx(i); + if (!aalg) + break; + if (aalg->available) + *ap++ = aalg->desc; + } } - if (esp_len) { + if (enc_len) { struct sadb_supported *sp; struct sadb_alg *ap; - sp = (struct sadb_supported *) skb_put(skb, esp_len); + sp = (struct sadb_supported *) skb_put(skb, enc_len); ap = (struct sadb_alg *) (sp + 1); - sp->sadb_supported_len = esp_len / sizeof(uint64_t); + sp->sadb_supported_len = enc_len / sizeof(uint64_t); sp->sadb_supported_exttype = SADB_EXT_SUPPORTED_ENCRYPT; - for (i=1; i<sizeof(ealg_list)/sizeof(ealg_list[0]); i++) - *ap++ = ealg_list[i].desc; + 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: @@ -1305,6 +1209,8 @@ static int pfkey_register(struct sock *sk, struct sk_buff *skb, struct sadb_msg pfk->registered |= (1<<hdr->sadb_msg_satype); } + xfrm_probe_algs(); + supp_skb = compose_sadb_supported(hdr, GFP_KERNEL); if (!supp_skb) { if (hdr->sadb_msg_satype != SADB_SATYPE_UNSPEC) @@ -1955,35 +1861,55 @@ static struct sadb_msg *pfkey_get_base_msg(struct sk_buff *skb, int *errp) return hdr; } -int count_ah_combs(struct xfrm_tmpl *t) +static inline int aalg_tmpl_set(struct xfrm_tmpl *t, struct xfrm_algo_desc *d) { - int sz = 0; - int i; + return t->aalgos & (1 << d->desc.sadb_alg_id); +} - for (i=1; i<sizeof(aalg_list)/sizeof(aalg_list[0]); i++) { - if (t->aalgos&(1<<aalg_list[i].desc.sadb_alg_id)) +static inline int ealg_tmpl_set(struct xfrm_tmpl *t, struct xfrm_algo_desc *d) +{ + return t->ealgos & (1 << d->desc.sadb_alg_id); +} + +static int count_ah_combs(struct xfrm_tmpl *t) +{ + int i, sz = 0; + + for (i = 0; ; i++) { + struct xfrm_algo_desc *aalg = xfrm_aalg_get_byidx(i); + if (!aalg) + break; + if (aalg_tmpl_set(t, aalg) && aalg->available) sz += sizeof(struct sadb_comb); } return sz + sizeof(struct sadb_prop); } -int count_esp_combs(struct xfrm_tmpl *t) +static int count_esp_combs(struct xfrm_tmpl *t) { - int sz = 0; - int i, k; + int i, k, sz = 0; - for (i=1; i<sizeof(ealg_list)/sizeof(ealg_list[0]); i++) { - if (!(t->ealgos&(1<<ealg_list[i].desc.sadb_alg_id))) + for (i = 0; ; i++) { + struct xfrm_algo_desc *ealg = xfrm_ealg_get_byidx(i); + if (!ealg) + break; + + if (!(ealg_tmpl_set(t, ealg) && ealg->available)) continue; - for (k=1; k<sizeof(aalg_list)/sizeof(aalg_list[0]); k++) { - if (t->aalgos&(1<<aalg_list[i].desc.sadb_alg_id)) + + for (k = 1; ; k++) { + struct xfrm_algo_desc *aalg = xfrm_aalg_get_byidx(k); + if (!aalg) + break; + + if (aalg_tmpl_set(t, aalg) && aalg->available) sz += sizeof(struct sadb_comb); } } return sz + sizeof(struct sadb_prop); } -void dump_ah_combs(struct sk_buff *skb, struct xfrm_tmpl *t) +static void dump_ah_combs(struct sk_buff *skb, struct xfrm_tmpl *t) { struct sadb_prop *p; int i; @@ -1993,15 +1919,19 @@ void dump_ah_combs(struct sk_buff *skb, struct xfrm_tmpl *t) p->sadb_prop_exttype = SADB_EXT_PROPOSAL; p->sadb_prop_replay = 32; - for (i=1; i<sizeof(aalg_list)/sizeof(aalg_list[0]); i++) { - if (t->aalgos&(1<<aalg_list[i].desc.sadb_alg_id)) { + for (i = 0; ; i++) { + struct xfrm_algo_desc *aalg = xfrm_aalg_get_byidx(i); + 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_list[i].desc.sadb_alg_id; - c->sadb_comb_auth_minbits = aalg_list[i].desc.sadb_alg_minbits; - c->sadb_comb_auth_maxbits = aalg_list[i].desc.sadb_alg_maxbits; + 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; @@ -2010,7 +1940,7 @@ void dump_ah_combs(struct sk_buff *skb, struct xfrm_tmpl *t) } } -void dump_esp_combs(struct sk_buff *skb, struct xfrm_tmpl *t) +static void dump_esp_combs(struct sk_buff *skb, struct xfrm_tmpl *t) { struct sadb_prop *p; int i, k; @@ -2020,22 +1950,30 @@ void dump_esp_combs(struct sk_buff *skb, struct xfrm_tmpl *t) p->sadb_prop_exttype = SADB_EXT_PROPOSAL; p->sadb_prop_replay = 32; - for (i=1; i<sizeof(ealg_list)/sizeof(ealg_list[0]); i++) { - if (!(t->ealgos&(1<<ealg_list[i].desc.sadb_alg_id))) + for (i=0; ; i++) { + struct xfrm_algo_desc *ealg = xfrm_ealg_get_byidx(i); + if (!ealg) + break; + + if (!(ealg_tmpl_set(t, ealg) && ealg->available)) continue; - for (k=1; k<sizeof(aalg_list)/sizeof(aalg_list[0]); k++) { + + for (k = 1; ; k++) { struct sadb_comb *c; - if (!(t->aalgos&(1<<aalg_list[i].desc.sadb_alg_id))) + struct xfrm_algo_desc *aalg = xfrm_aalg_get_byidx(k); + 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_list[k].desc.sadb_alg_id; - c->sadb_comb_auth_minbits = aalg_list[k].desc.sadb_alg_minbits; - c->sadb_comb_auth_maxbits = aalg_list[k].desc.sadb_alg_maxbits; - c->sadb_comb_encrypt = ealg_list[i].desc.sadb_alg_id; - c->sadb_comb_encrypt_minbits = ealg_list[i].desc.sadb_alg_minbits; - c->sadb_comb_encrypt_maxbits = ealg_list[i].desc.sadb_alg_maxbits; + 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; diff --git a/net/netsyms.c b/net/netsyms.c index c387bd415bd3..0528cd35b100 100644 --- a/net/netsyms.c +++ b/net/netsyms.c @@ -323,6 +323,15 @@ EXPORT_SYMBOL(xfrm_policy_flush); EXPORT_SYMBOL(xfrm_policy_byid); EXPORT_SYMBOL(xfrm_policy_list); +EXPORT_SYMBOL_GPL(xfrm_probe_algs); +EXPORT_SYMBOL_GPL(xfrm_count_auth_supported); +EXPORT_SYMBOL_GPL(xfrm_count_enc_supported); +EXPORT_SYMBOL_GPL(xfrm_aalg_get_byidx); +EXPORT_SYMBOL_GPL(xfrm_ealg_get_byidx); +EXPORT_SYMBOL_GPL(xfrm_aalg_get_byid); +EXPORT_SYMBOL_GPL(xfrm_ealg_get_byid); +EXPORT_SYMBOL_GPL(xfrm_aalg_get_byname); +EXPORT_SYMBOL_GPL(xfrm_ealg_get_byname); #if defined (CONFIG_IPV6_MODULE) || defined (CONFIG_IP_SCTP_MODULE) /* inet functions common to v4 and v6 */ |
