Commit e0376d00 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec-next



Steffen Klassert says:

====================
1) Remove a duplicated call to skb_orphan() in pf_key, from Cong Wang.

2) Prepare xfrm and pf_key for algorithms without pf_key support,
   from Jussi Kivilinna.

3) Fix an unbalanced lock in xfrm_output_one(), from Li RongQing.

4) Add an IPsec state resolution packet queue to handle
   packets that are send before the states are resolved.

5) xfrm4_policy_fini() is unused since 2.6.11, time to remove it.
   From Michal Kubecek.

6) The xfrm gc threshold was configurable just in the initial
   namespace, make it configurable in all namespaces. From
   Michal Kubecek.

7) We currently can not insert policies with mark and mask
   such that some flows would be matched from both policies.
   Allow this if the priorities of these policies are different,
   the one with the higher priority is used in this case.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 15004cab 7cb8a939
......@@ -61,6 +61,7 @@ struct dst_entry {
#define DST_NOPEER 0x0040
#define DST_FAKE_RTABLE 0x0080
#define DST_XFRM_TUNNEL 0x0100
#define DST_XFRM_QUEUE 0x0200
unsigned short pending_confirm;
......
......@@ -22,6 +22,7 @@ struct netns_ipv4 {
struct ctl_table_header *frags_hdr;
struct ctl_table_header *ipv4_hdr;
struct ctl_table_header *route_hdr;
struct ctl_table_header *xfrm4_hdr;
#endif
struct ipv4_devconf *devconf_all;
struct ipv4_devconf *devconf_dflt;
......
......@@ -16,6 +16,7 @@ struct netns_sysctl_ipv6 {
struct ctl_table_header *route_hdr;
struct ctl_table_header *icmp_hdr;
struct ctl_table_header *frags_hdr;
struct ctl_table_header *xfrm6_hdr;
#endif
int bindv6only;
int flush_delay;
......
......@@ -501,6 +501,12 @@ struct xfrm_policy_walk {
u32 seq;
};
struct xfrm_policy_queue {
struct sk_buff_head hold_queue;
struct timer_list hold_timer;
unsigned long timeout;
};
struct xfrm_policy {
#ifdef CONFIG_NET_NS
struct net *xp_net;
......@@ -522,6 +528,7 @@ struct xfrm_policy {
struct xfrm_lifetime_cfg lft;
struct xfrm_lifetime_cur curlft;
struct xfrm_policy_walk_entry walk;
struct xfrm_policy_queue polq;
u8 type;
u8 action;
u8 flags;
......@@ -1320,6 +1327,7 @@ struct xfrm_algo_desc {
char *name;
char *compat;
u8 available:1;
u8 pfkey_supported:1;
union {
struct xfrm_algo_aead_info aead;
struct xfrm_algo_auth_info auth;
......@@ -1561,8 +1569,8 @@ extern void xfrm_input_init(void);
extern int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq);
extern void xfrm_probe_algs(void);
extern int xfrm_count_auth_supported(void);
extern int xfrm_count_enc_supported(void);
extern int xfrm_count_pfkey_auth_supported(void);
extern int xfrm_count_pfkey_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);
......
......@@ -262,21 +262,56 @@ static struct ctl_table xfrm4_policy_table[] = {
{ }
};
static struct ctl_table_header *sysctl_hdr;
#endif
static void __init xfrm4_policy_init(void)
static int __net_init xfrm4_net_init(struct net *net)
{
xfrm_policy_register_afinfo(&xfrm4_policy_afinfo);
struct ctl_table *table;
struct ctl_table_header *hdr;
table = xfrm4_policy_table;
if (!net_eq(net, &init_net)) {
table = kmemdup(table, sizeof(xfrm4_policy_table), GFP_KERNEL);
if (!table)
goto err_alloc;
table[0].data = &net->xfrm.xfrm4_dst_ops.gc_thresh;
}
hdr = register_net_sysctl(net, "net/ipv4", table);
if (!hdr)
goto err_reg;
net->ipv4.xfrm4_hdr = hdr;
return 0;
err_reg:
if (!net_eq(net, &init_net))
kfree(table);
err_alloc:
return -ENOMEM;
}
static void __exit xfrm4_policy_fini(void)
static void __net_exit xfrm4_net_exit(struct net *net)
{
#ifdef CONFIG_SYSCTL
if (sysctl_hdr)
unregister_net_sysctl_table(sysctl_hdr);
struct ctl_table *table;
if (net->ipv4.xfrm4_hdr == NULL)
return;
table = net->ipv4.xfrm4_hdr->ctl_table_arg;
unregister_net_sysctl_table(net->ipv4.xfrm4_hdr);
if (!net_eq(net, &init_net))
kfree(table);
}
static struct pernet_operations __net_initdata xfrm4_net_ops = {
.init = xfrm4_net_init,
.exit = xfrm4_net_exit,
};
#endif
xfrm_policy_unregister_afinfo(&xfrm4_policy_afinfo);
static void __init xfrm4_policy_init(void)
{
xfrm_policy_register_afinfo(&xfrm4_policy_afinfo);
}
void __init xfrm4_init(void)
......@@ -286,8 +321,7 @@ void __init xfrm4_init(void)
xfrm4_state_init();
xfrm4_policy_init();
#ifdef CONFIG_SYSCTL
sysctl_hdr = register_net_sysctl(&init_net, "net/ipv4",
xfrm4_policy_table);
register_pernet_subsys(&xfrm4_net_ops);
#endif
}
......@@ -320,7 +320,51 @@ static struct ctl_table xfrm6_policy_table[] = {
{ }
};
static struct ctl_table_header *sysctl_hdr;
static int __net_init xfrm6_net_init(struct net *net)
{
struct ctl_table *table;
struct ctl_table_header *hdr;
table = xfrm6_policy_table;
if (!net_eq(net, &init_net)) {
table = kmemdup(table, sizeof(xfrm6_policy_table), GFP_KERNEL);
if (!table)
goto err_alloc;
table[0].data = &net->xfrm.xfrm6_dst_ops.gc_thresh;
}
hdr = register_net_sysctl(net, "net/ipv6", table);
if (!hdr)
goto err_reg;
net->ipv6.sysctl.xfrm6_hdr = hdr;
return 0;
err_reg:
if (!net_eq(net, &init_net))
kfree(table);
err_alloc:
return -ENOMEM;
}
static void __net_exit xfrm6_net_exit(struct net *net)
{
struct ctl_table *table;
if (net->ipv6.sysctl.xfrm6_hdr == NULL)
return;
table = net->ipv6.sysctl.xfrm6_hdr->ctl_table_arg;
unregister_net_sysctl_table(net->ipv6.sysctl.xfrm6_hdr);
if (!net_eq(net, &init_net))
kfree(table);
}
static struct pernet_operations xfrm6_net_ops = {
.init = xfrm6_net_init,
.exit = xfrm6_net_exit,
};
#endif
int __init xfrm6_init(void)
......@@ -339,8 +383,7 @@ int __init xfrm6_init(void)
goto out_policy;
#ifdef CONFIG_SYSCTL
sysctl_hdr = register_net_sysctl(&init_net, "net/ipv6",
xfrm6_policy_table);
register_pernet_subsys(&xfrm6_net_ops);
#endif
out:
return ret;
......@@ -352,8 +395,7 @@ int __init xfrm6_init(void)
void xfrm6_fini(void)
{
#ifdef CONFIG_SYSCTL
if (sysctl_hdr)
unregister_net_sysctl_table(sysctl_hdr);
unregister_pernet_subsys(&xfrm6_net_ops);
#endif
xfrm6_policy_fini();
xfrm6_state_fini();
......
......@@ -203,7 +203,6 @@ static int pfkey_broadcast_one(struct sk_buff *skb, struct sk_buff **skb2,
}
if (*skb2 != NULL) {
if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) {
skb_orphan(*skb2);
skb_set_owner_r(*skb2, sk);
skb_queue_tail(&sk->sk_receive_queue, *skb2);
sk->sk_data_ready(sk, (*skb2)->len);
......@@ -816,18 +815,21 @@ static struct sk_buff *__pfkey_xfrm_state2msg(const struct xfrm_state *x,
sa->sadb_sa_auth = 0;
if (x->aalg) {
struct xfrm_algo_desc *a = xfrm_aalg_get_byname(x->aalg->alg_name, 0);
sa->sadb_sa_auth = a ? a->desc.sadb_alg_id : 0;
sa->sadb_sa_auth = (a && a->pfkey_supported) ?
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, 0);
sa->sadb_sa_encrypt = a ? a->desc.sadb_alg_id : 0;
sa->sadb_sa_encrypt = (a && a->pfkey_supported) ?
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, 0);
sa->sadb_sa_encrypt = a ? a->desc.sadb_alg_id : 0;
sa->sadb_sa_encrypt = (a && a->pfkey_supported) ?
a->desc.sadb_alg_id : 0;
}
sa->sadb_sa_flags = 0;
......@@ -1138,7 +1140,7 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct net *net,
if (sa->sadb_sa_auth) {
int keysize = 0;
struct xfrm_algo_desc *a = xfrm_aalg_get_byid(sa->sadb_sa_auth);
if (!a) {
if (!a || !a->pfkey_supported) {
err = -ENOSYS;
goto out;
}
......@@ -1160,7 +1162,7 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct net *net,
if (sa->sadb_sa_encrypt) {
if (hdr->sadb_msg_satype == SADB_X_SATYPE_IPCOMP) {
struct xfrm_algo_desc *a = xfrm_calg_get_byid(sa->sadb_sa_encrypt);
if (!a) {
if (!a || !a->pfkey_supported) {
err = -ENOSYS;
goto out;
}
......@@ -1172,7 +1174,7 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct net *net,
} else {
int keysize = 0;
struct xfrm_algo_desc *a = xfrm_ealg_get_byid(sa->sadb_sa_encrypt);
if (!a) {
if (!a || !a->pfkey_supported) {
err = -ENOSYS;
goto out;
}
......@@ -1578,13 +1580,13 @@ static struct sk_buff *compose_sadb_supported(const struct sadb_msg *orig,
struct sadb_msg *hdr;
int len, auth_len, enc_len, i;
auth_len = xfrm_count_auth_supported();
auth_len = xfrm_count_pfkey_auth_supported();
if (auth_len) {
auth_len *= sizeof(struct sadb_alg);
auth_len += sizeof(struct sadb_supported);
}
enc_len = xfrm_count_enc_supported();
enc_len = xfrm_count_pfkey_enc_supported();
if (enc_len) {
enc_len *= sizeof(struct sadb_alg);
enc_len += sizeof(struct sadb_supported);
......@@ -1615,6 +1617,8 @@ static struct sk_buff *compose_sadb_supported(const struct sadb_msg *orig,
struct xfrm_algo_desc *aalg = xfrm_aalg_get_byidx(i);
if (!aalg)
break;
if (!aalg->pfkey_supported)
continue;
if (aalg->available)
*ap++ = aalg->desc;
}
......@@ -1634,6 +1638,8 @@ static struct sk_buff *compose_sadb_supported(const struct sadb_msg *orig,
struct xfrm_algo_desc *ealg = xfrm_ealg_get_byidx(i);
if (!ealg)
break;
if (!ealg->pfkey_supported)
continue;
if (ealg->available)
*ap++ = ealg->desc;
}
......@@ -2825,6 +2831,8 @@ static int count_ah_combs(const struct xfrm_tmpl *t)
const struct xfrm_algo_desc *aalg = xfrm_aalg_get_byidx(i);
if (!aalg)
break;
if (!aalg->pfkey_supported)
continue;
if (aalg_tmpl_set(t, aalg) && aalg->available)
sz += sizeof(struct sadb_comb);
}
......@@ -2840,6 +2848,9 @@ static int count_esp_combs(const struct xfrm_tmpl *t)
if (!ealg)
break;
if (!ealg->pfkey_supported)
continue;
if (!(ealg_tmpl_set(t, ealg) && ealg->available))
continue;
......@@ -2848,6 +2859,9 @@ static int count_esp_combs(const struct xfrm_tmpl *t)
if (!aalg)
break;
if (!aalg->pfkey_supported)
continue;
if (aalg_tmpl_set(t, aalg) && aalg->available)
sz += sizeof(struct sadb_comb);
}
......@@ -2871,6 +2885,9 @@ static void dump_ah_combs(struct sk_buff *skb, const struct xfrm_tmpl *t)
if (!aalg)
break;
if (!aalg->pfkey_supported)
continue;
if (aalg_tmpl_set(t, aalg) && aalg->available) {
struct sadb_comb *c;
c = (struct sadb_comb*)skb_put(skb, sizeof(struct sadb_comb));
......@@ -2903,6 +2920,9 @@ static void dump_esp_combs(struct sk_buff *skb, const struct xfrm_tmpl *t)
if (!ealg)
break;
if (!ealg->pfkey_supported)
continue;
if (!(ealg_tmpl_set(t, ealg) && ealg->available))
continue;
......@@ -2911,6 +2931,8 @@ static void dump_esp_combs(struct sk_buff *skb, const struct xfrm_tmpl *t)
const struct xfrm_algo_desc *aalg = xfrm_aalg_get_byidx(k);
if (!aalg)
break;
if (!aalg->pfkey_supported)
continue;
if (!(aalg_tmpl_set(t, aalg) && aalg->available))
continue;
c = (struct sadb_comb*)skb_put(skb, sizeof(struct sadb_comb));
......
......@@ -35,6 +35,8 @@ static struct xfrm_algo_desc aead_list[] = {
}
},
.pfkey_supported = 1,
.desc = {
.sadb_alg_id = SADB_X_EALG_AES_GCM_ICV8,
.sadb_alg_ivlen = 8,
......@@ -51,6 +53,8 @@ static struct xfrm_algo_desc aead_list[] = {
}
},
.pfkey_supported = 1,
.desc = {
.sadb_alg_id = SADB_X_EALG_AES_GCM_ICV12,
.sadb_alg_ivlen = 8,
......@@ -67,6 +71,8 @@ static struct xfrm_algo_desc aead_list[] = {
}
},
.pfkey_supported = 1,
.desc = {
.sadb_alg_id = SADB_X_EALG_AES_GCM_ICV16,
.sadb_alg_ivlen = 8,
......@@ -83,6 +89,8 @@ static struct xfrm_algo_desc aead_list[] = {
}
},
.pfkey_supported = 1,
.desc = {
.sadb_alg_id = SADB_X_EALG_AES_CCM_ICV8,
.sadb_alg_ivlen = 8,
......@@ -99,6 +107,8 @@ static struct xfrm_algo_desc aead_list[] = {
}
},
.pfkey_supported = 1,
.desc = {
.sadb_alg_id = SADB_X_EALG_AES_CCM_ICV12,
.sadb_alg_ivlen = 8,
......@@ -115,6 +125,8 @@ static struct xfrm_algo_desc aead_list[] = {
}
},
.pfkey_supported = 1,
.desc = {
.sadb_alg_id = SADB_X_EALG_AES_CCM_ICV16,
.sadb_alg_ivlen = 8,
......@@ -131,6 +143,8 @@ static struct xfrm_algo_desc aead_list[] = {
}
},
.pfkey_supported = 1,
.desc = {
.sadb_alg_id = SADB_X_EALG_NULL_AES_GMAC,
.sadb_alg_ivlen = 8,
......@@ -151,6 +165,8 @@ static struct xfrm_algo_desc aalg_list[] = {
}
},
.pfkey_supported = 1,
.desc = {
.sadb_alg_id = SADB_X_AALG_NULL,
.sadb_alg_ivlen = 0,
......@@ -169,6 +185,8 @@ static struct xfrm_algo_desc aalg_list[] = {
}
},
.pfkey_supported = 1,
.desc = {
.sadb_alg_id = SADB_AALG_MD5HMAC,
.sadb_alg_ivlen = 0,
......@@ -187,6 +205,8 @@ static struct xfrm_algo_desc aalg_list[] = {
}
},
.pfkey_supported = 1,
.desc = {
.sadb_alg_id = SADB_AALG_SHA1HMAC,
.sadb_alg_ivlen = 0,
......@@ -205,6 +225,8 @@ static struct xfrm_algo_desc aalg_list[] = {
}
},
.pfkey_supported = 1,
.desc = {
.sadb_alg_id = SADB_X_AALG_SHA2_256HMAC,
.sadb_alg_ivlen = 0,
......@@ -222,6 +244,8 @@ static struct xfrm_algo_desc aalg_list[] = {
}
},
.pfkey_supported = 1,
.desc = {
.sadb_alg_id = SADB_X_AALG_SHA2_384HMAC,
.sadb_alg_ivlen = 0,
......@@ -239,6 +263,8 @@ static struct xfrm_algo_desc aalg_list[] = {
}
},
.pfkey_supported = 1,
.desc = {
.sadb_alg_id = SADB_X_AALG_SHA2_512HMAC,
.sadb_alg_ivlen = 0,
......@@ -257,6 +283,8 @@ static struct xfrm_algo_desc aalg_list[] = {
}
},
.pfkey_supported = 1,
.desc = {
.sadb_alg_id = SADB_X_AALG_RIPEMD160HMAC,
.sadb_alg_ivlen = 0,
......@@ -274,6 +302,8 @@ static struct xfrm_algo_desc aalg_list[] = {
}
},
.pfkey_supported = 1,
.desc = {
.sadb_alg_id = SADB_X_AALG_AES_XCBC_MAC,
.sadb_alg_ivlen = 0,
......@@ -295,6 +325,8 @@ static struct xfrm_algo_desc ealg_list[] = {
}
},
.pfkey_supported = 1,
.desc = {
.sadb_alg_id = SADB_EALG_NULL,
.sadb_alg_ivlen = 0,
......@@ -313,6 +345,8 @@ static struct xfrm_algo_desc ealg_list[] = {
}
},
.pfkey_supported = 1,
.desc = {
.sadb_alg_id = SADB_EALG_DESCBC,
.sadb_alg_ivlen = 8,
......@@ -331,6 +365,8 @@ static struct xfrm_algo_desc ealg_list[] = {
}
},
.pfkey_supported = 1,
.desc = {
.sadb_alg_id = SADB_EALG_3DESCBC,
.sadb_alg_ivlen = 8,
......@@ -349,6 +385,8 @@ static struct xfrm_algo_desc ealg_list[] = {
}
},
.pfkey_supported = 1,
.desc = {
.sadb_alg_id = SADB_X_EALG_CASTCBC,
.sadb_alg_ivlen = 8,
......@@ -367,6 +405,8 @@ static struct xfrm_algo_desc ealg_list[] = {
}
},
.pfkey_supported = 1,
.desc = {
.sadb_alg_id = SADB_X_EALG_BLOWFISHCBC,
.sadb_alg_ivlen = 8,
......@@ -385,6 +425,8 @@ static struct xfrm_algo_desc ealg_list[] = {
}
},
.pfkey_supported = 1,
.desc = {
.sadb_alg_id = SADB_X_EALG_AESCBC,
.sadb_alg_ivlen = 8,
......@@ -403,6 +445,8 @@ static struct xfrm_algo_desc ealg_list[] = {
}
},
.pfkey_supported = 1,
.desc = {
.sadb_alg_id = SADB_X_EALG_SERPENTCBC,
.sadb_alg_ivlen = 8,
......@@ -421,6 +465,8 @@ static struct xfrm_algo_desc ealg_list[] = {
}
},
.pfkey_supported = 1,
.desc = {
.sadb_alg_id = SADB_X_EALG_CAMELLIACBC,
.sadb_alg_ivlen = 8,
......@@ -439,6 +485,8 @@ static struct xfrm_algo_desc ealg_list[] = {
}
},
.pfkey_supported = 1,
.desc = {
.sadb_alg_id = SADB_X_EALG_TWOFISHCBC,
.sadb_alg_ivlen = 8,
......@@ -456,6 +504,8 @@ static struct xfrm_algo_desc ealg_list[] = {
}
},
.pfkey_supported = 1,
.desc = {
.sadb_alg_id = SADB_X_EALG_AESCTR,
.sadb_alg_ivlen = 8,
......@@ -473,6 +523,7 @@ static struct xfrm_algo_desc calg_list[] = {
.threshold = 90,
}
},
.pfkey_supported = 1,
.desc = { .sadb_alg_id = SADB_X_CALG_DEFLATE }
},
{
......@@ -482,6 +533,7 @@ static struct xfrm_algo_desc calg_list[] = {
.threshold = 90,
}
},
.pfkey_supported = 1,
.desc = { .sadb_alg_id = SADB_X_CALG_LZS }
},
{
......@@ -491,6 +543,7 @@ static struct xfrm_algo_desc calg_list[] = {
.threshold = 50,
}
},
.pfkey_supported = 1,
.desc = { .sadb_alg_id = SADB_X_CALG_LZJH }
},
};
......@@ -714,27 +767,27 @@ void xfrm_probe_algs(void)
}
EXPORT_SYMBOL_GPL(xfrm_probe_algs);
int xfrm_count_auth_supported(void)
int xfrm_count_pfkey_auth_supported(void)
{
int i, n;
for (i = 0, n = 0; i < aalg_entries(); i++)
if (aalg_list[i].available)
if (aalg_list[i].available && aalg_list[i].pfkey_supported)
n++;
return n;
}
EXPORT_SYMBOL_GPL(xfrm_count_auth_supported);
EXPORT_SYMBOL_GPL(xfrm_count_pfkey_auth_supported);
int xfrm_count_enc_supported(void)
int xfrm_count_pfkey_enc_supported(void)
{
int i, n;
for (i = 0, n = 0; i < ealg_entries(); i++)
if (ealg_list[i].available)
if (ealg_list[i].available && ealg_list[i].pfkey_supported)
n++;
return n;
}
EXPORT_SYMBOL_GPL(xfrm_count_enc_supported);
EXPORT_SYMBOL_GPL(xfrm_count_pfkey_enc_supported);
#if defined(CONFIG_INET_ESP) || defined(CONFIG_INET_ESP_MODULE) || defined(CONFIG_INET6_ESP) || defined(CONFIG_INET6_ESP_MODULE)
......
......@@ -64,7 +64,7 @@ static int xfrm_output_one(struct sk_buff *skb, int err)
if (unlikely(x->km.state != XFRM_STATE_VALID)) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEINVALID);
goto error_nolock;
goto error;
}
err = xfrm_state_check_expire(x);
......
......@@ -35,6 +35,10 @@
#include "xfrm_hash.h"