#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
+#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"
}
}
+/*
+ * 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 *);
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 */
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
#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;
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;
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;
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;
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;
{
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;
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) {
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;
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,
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);
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);
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;
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);
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);
.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) {
--- /dev/null
+/*
+ * 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;
+}
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)
{
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;
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)
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;
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)
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;
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);
{
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)
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:
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)
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;
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;
}
}
-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;
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;
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 */