Commit bfe169a1 authored by James Morris's avatar James Morris Committed by David S. Miller

[IPSEC] Add initial compression support for pfkey and xfrm_algo.

parent e5c1202f
......@@ -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
......
......@@ -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)
{
......
......@@ -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
}
......
......@@ -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 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr,
kfree(x->aalg);
if (x->ealg)
kfree(x->ealg);
if (x->calg)
kfree(x->calg);
kfree(x);
return ERR_PTR(-ENOBUFS);
}
......
......@@ -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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment