summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Morris <jmorris@intercode.com.au>2003-03-22 10:09:21 -0800
committerDavid S. Miller <davem@nuts.ninka.net>2003-03-22 10:09:21 -0800
commitbfe169a17ab83d4a3295c22eef8f376d6a12ef4c (patch)
treee06642dad552c207b3e167f380037ac7750b7488
parente5c1202f2ad98663dc1ecaaa4a21a6773ea1c9fb (diff)
[IPSEC] Add initial compression support for pfkey and xfrm_algo.
-rw-r--r--include/linux/pfkeyv2.h8
-rw-r--r--include/net/xfrm.h8
-rw-r--r--net/ipv4/xfrm_algo.c83
-rw-r--r--net/key/af_key.c54
-rw-r--r--net/netsyms.c3
5 files changed, 140 insertions, 16 deletions
diff --git a/include/linux/pfkeyv2.h b/include/linux/pfkeyv2.h
index c6e4e6e29f10..efb41c857ea3 100644
--- a/include/linux/pfkeyv2.h
+++ b/include/linux/pfkeyv2.h
@@ -262,6 +262,14 @@ struct sadb_x_ipsecrequest {
#define SADB_X_EALG_AESCBC 12
#define SADB_EALG_MAX 12
+/* Compression algorithms */
+#define SADB_X_CALG_NONE 0
+#define SADB_X_CALG_OUI 1
+#define SADB_X_CALG_DEFLATE 2
+#define SADB_X_CALG_LZS 3
+#define SADB_X_CALG_LZJH 4
+#define SADB_X_CALG_MAX 4
+
/* Extension Header values */
#define SADB_EXT_RESERVED 0
#define SADB_EXT_SA 1
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index f8b5e811c161..d6ffb9aed327 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -391,12 +391,17 @@ struct xfrm_algo_encr_info {
u16 defkeybits;
};
+struct xfrm_algo_comp_info {
+ u16 threshold;
+};
+
struct xfrm_algo_desc {
char *name;
u8 available:1;
union {
struct xfrm_algo_auth_info auth;
struct xfrm_algo_encr_info encr;
+ struct xfrm_algo_comp_info comp;
} uinfo;
struct sadb_alg desc;
};
@@ -453,10 +458,13 @@ 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_calg_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_calg_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);
+extern struct xfrm_algo_desc *xfrm_calg_get_byname(char *name);
static __inline__ int addr_match(void *token1, void *token2, int prefixlen)
{
diff --git a/net/ipv4/xfrm_algo.c b/net/ipv4/xfrm_algo.c
index 5ff82327c232..920e9dc667df 100644
--- a/net/ipv4/xfrm_algo.c
+++ b/net/ipv4/xfrm_algo.c
@@ -219,6 +219,36 @@ static struct xfrm_algo_desc ealg_list[] = {
},
};
+static struct xfrm_algo_desc calg_list[] = {
+{
+ .name = "deflate",
+ .uinfo = {
+ .comp = {
+ .threshold = 90,
+ }
+ },
+ .desc = { .sadb_alg_id = SADB_X_CALG_DEFLATE }
+},
+{
+ .name = "lzs",
+ .uinfo = {
+ .comp = {
+ .threshold = 90,
+ }
+ },
+ .desc = { .sadb_alg_id = SADB_X_CALG_LZS }
+},
+{
+ .name = "lzjh",
+ .uinfo = {
+ .comp = {
+ .threshold = 50,
+ }
+ },
+ .desc = { .sadb_alg_id = SADB_X_CALG_LZJH }
+},
+};
+
static inline int aalg_entries(void)
{
return sizeof(aalg_list) / sizeof(aalg_list[0]);
@@ -229,6 +259,12 @@ static inline int ealg_entries(void)
return sizeof(ealg_list) / sizeof(ealg_list[0]);
}
+static inline int calg_entries(void)
+{
+ return sizeof(calg_list) / sizeof(calg_list[0]);
+}
+
+/* Todo: generic iterators */
struct xfrm_algo_desc *xfrm_aalg_get_byid(int alg_id)
{
int i;
@@ -259,6 +295,21 @@ struct xfrm_algo_desc *xfrm_ealg_get_byid(int alg_id)
return NULL;
}
+struct xfrm_algo_desc *xfrm_calg_get_byid(int alg_id)
+{
+ int i;
+
+ for (i = 0; i < calg_entries(); i++) {
+ if (calg_list[i].desc.sadb_alg_id == alg_id) {
+ if (calg_list[i].available)
+ return &calg_list[i];
+ else
+ break;
+ }
+ }
+ return NULL;
+}
+
struct xfrm_algo_desc *xfrm_aalg_get_byname(char *name)
{
int i;
@@ -295,6 +346,24 @@ struct xfrm_algo_desc *xfrm_ealg_get_byname(char *name)
return NULL;
}
+struct xfrm_algo_desc *xfrm_calg_get_byname(char *name)
+{
+ int i;
+
+ if (!name)
+ return NULL;
+
+ for (i=0; i < calg_entries(); i++) {
+ if (strcmp(name, calg_list[i].name) == 0) {
+ if (calg_list[i].available)
+ return &calg_list[i];
+ else
+ break;
+ }
+ }
+ return NULL;
+}
+
struct xfrm_algo_desc *xfrm_aalg_get_byidx(unsigned int idx)
{
if (idx >= aalg_entries())
@@ -311,6 +380,14 @@ struct xfrm_algo_desc *xfrm_ealg_get_byidx(unsigned int idx)
return &ealg_list[idx];
}
+struct xfrm_algo_desc *xfrm_calg_get_byidx(unsigned int idx)
+{
+ if (idx >= calg_entries())
+ return NULL;
+
+ return &calg_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
@@ -334,6 +411,12 @@ void xfrm_probe_algs(void)
if (ealg_list[i].available != status)
ealg_list[i].available = status;
}
+
+ for (i = 0; i < calg_entries(); i++) {
+ status = crypto_alg_available(calg_list[i].name, 0);
+ if (calg_list[i].available != status)
+ calg_list[i].available = status;
+ }
#endif
}
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 3e1ffac2c473..e9d2ebedb153 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -667,10 +667,17 @@ static struct sk_buff * pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys,
sa->sadb_sa_auth = a ? a->desc.sadb_alg_id : 0;
}
sa->sadb_sa_encrypt = 0;
+ BUG_ON(x->ealg && x->calg);
if (x->ealg) {
struct xfrm_algo_desc *a = xfrm_ealg_get_byname(x->ealg->alg_name);
sa->sadb_sa_encrypt = a ? a->desc.sadb_alg_id : 0;
}
+ /* KAME compatible: sadb_sa_encrypt is overloaded with calg id */
+ if (x->calg) {
+ struct xfrm_algo_desc *a = xfrm_calg_get_byname(x->calg->alg_name);
+ sa->sadb_sa_encrypt = a ? a->desc.sadb_alg_id : 0;
+ }
+
sa->sadb_sa_flags = 0;
/* hard time */
@@ -896,6 +903,8 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr,
Hence, we have to _ignore_ sadb_sa_state, which is also reasonable.
*/
if (sa->sadb_sa_auth > SADB_AALG_MAX ||
+ (hdr->sadb_msg_satype == SADB_X_SATYPE_IPCOMP &&
+ sa->sadb_sa_encrypt > SADB_X_CALG_MAX) ||
sa->sadb_sa_encrypt > SADB_EALG_MAX)
return ERR_PTR(-EINVAL);
key = (struct sadb_key*) ext_hdrs[SADB_EXT_KEY_AUTH-1];
@@ -953,24 +962,35 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr,
x->props.aalgo = sa->sadb_sa_auth;
/* x->algo.flags = sa->sadb_sa_flags; */
}
- key = (struct sadb_key*) ext_hdrs[SADB_EXT_KEY_ENCRYPT-1];
if (sa->sadb_sa_encrypt) {
- int keysize = 0;
- struct xfrm_algo_desc *a = xfrm_ealg_get_byid(sa->sadb_sa_encrypt);
- if (!a)
- goto out;
- if (key)
- keysize = (key->sadb_key_bits + 7) / 8;
- x->ealg = kmalloc(sizeof(*x->ealg) + keysize, GFP_KERNEL);
- if (!x->ealg)
- goto out;
- strcpy(x->ealg->alg_name, a->name);
- x->ealg->alg_key_len = 0;
- if (key) {
- x->ealg->alg_key_len = key->sadb_key_bits;
- memcpy(x->ealg->alg_key, key+1, keysize);
+ if (hdr->sadb_msg_satype == SADB_X_SATYPE_IPCOMP) {
+ struct xfrm_algo_desc *a = xfrm_calg_get_byid(sa->sadb_sa_encrypt);
+ if (!a)
+ goto out;
+ x->calg = kmalloc(sizeof(*x->calg), GFP_KERNEL);
+ if (!x->calg)
+ goto out;
+ strcpy(x->calg->alg_name, a->name);
+ x->props.calgo = sa->sadb_sa_encrypt;
+ } else {
+ int keysize = 0;
+ struct xfrm_algo_desc *a = xfrm_ealg_get_byid(sa->sadb_sa_encrypt);
+ if (!a)
+ goto out;
+ key = (struct sadb_key*) ext_hdrs[SADB_EXT_KEY_ENCRYPT-1];
+ if (key)
+ keysize = (key->sadb_key_bits + 7) / 8;
+ x->ealg = kmalloc(sizeof(*x->ealg) + keysize, GFP_KERNEL);
+ if (!x->ealg)
+ goto out;
+ strcpy(x->ealg->alg_name, a->name);
+ x->ealg->alg_key_len = 0;
+ if (key) {
+ x->ealg->alg_key_len = key->sadb_key_bits;
+ memcpy(x->ealg->alg_key, key+1, keysize);
+ }
+ x->props.ealgo = sa->sadb_sa_encrypt;
}
- x->props.ealgo = sa->sadb_sa_encrypt;
}
/* x->algo.flags = sa->sadb_sa_flags; */
@@ -1024,6 +1044,8 @@ out:
kfree(x->aalg);
if (x->ealg)
kfree(x->ealg);
+ if (x->calg)
+ kfree(x->calg);
kfree(x);
return ERR_PTR(-ENOBUFS);
}
diff --git a/net/netsyms.c b/net/netsyms.c
index 0fb028543f3d..52b0b4ec1146 100644
--- a/net/netsyms.c
+++ b/net/netsyms.c
@@ -349,10 +349,13 @@ 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_calg_get_byidx);
EXPORT_SYMBOL_GPL(xfrm_aalg_get_byid);
EXPORT_SYMBOL_GPL(xfrm_ealg_get_byid);
+EXPORT_SYMBOL_GPL(xfrm_calg_get_byid);
EXPORT_SYMBOL_GPL(xfrm_aalg_get_byname);
EXPORT_SYMBOL_GPL(xfrm_ealg_get_byname);
+EXPORT_SYMBOL_GPL(xfrm_calg_get_byname);
#if defined(CONFIG_INET_AH) || defined(CONFIG_INET_AH_MODULE) || defined(CONFIG_INET6_AH) || defined(CONFIG_INET6_AH_MODULE)
EXPORT_SYMBOL_GPL(skb_ah_walk);
#endif