Commit 42e8e6d9 authored by David S. Miller's avatar David S. Miller

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

Steffen Klassert says:

====================
1) Refactor selftests to use an array of structs in xfrm_fill_key().
   From Gautam Menghani.

2) Drop an unused argument from xfrm_policy_match.
   From Hongbin Wang.

3) Support collect metadata mode for xfrm interfaces.
   From Eyal Birger.

4) Add netlink extack support to xfrm.
   From Sabrina Dubroca.

Please note, there is a merge conflict in:

include/net/dst_metadata.h

between commit:

0a28bfd4 ("net/macsec: Add MACsec skb_metadata_dst Tx Data path support")

from the net-next tree and commit:

5182a5d4 ("net: allow storing xfrm interface metadata in metadata_dst")

from the ipsec-next tree.

Can be solved as done in linux-next.

Please pull or let me know if there are problems.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 9d435073 c39596f6
......@@ -11,6 +11,7 @@ enum metadata_type {
METADATA_IP_TUNNEL,
METADATA_HW_PORT_MUX,
METADATA_MACSEC,
METADATA_XFRM,
};
struct hw_port_info {
......@@ -22,6 +23,11 @@ struct macsec_info {
sci_t sci;
};
struct xfrm_md_info {
u32 if_id;
int link;
};
struct metadata_dst {
struct dst_entry dst;
enum metadata_type type;
......@@ -29,6 +35,7 @@ struct metadata_dst {
struct ip_tunnel_info tun_info;
struct hw_port_info port_info;
struct macsec_info macsec_info;
struct xfrm_md_info xfrm_info;
} u;
};
......@@ -60,6 +67,27 @@ skb_tunnel_info(const struct sk_buff *skb)
return NULL;
}
static inline struct xfrm_md_info *lwt_xfrm_info(struct lwtunnel_state *lwt)
{
return (struct xfrm_md_info *)lwt->data;
}
static inline struct xfrm_md_info *skb_xfrm_md_info(const struct sk_buff *skb)
{
struct metadata_dst *md_dst = skb_metadata_dst(skb);
struct dst_entry *dst;
if (md_dst && md_dst->type == METADATA_XFRM)
return &md_dst->u.xfrm_info;
dst = skb_dst(skb);
if (dst && dst->lwtstate &&
dst->lwtstate->type == LWTUNNEL_ENCAP_XFRM)
return lwt_xfrm_info(dst->lwtstate);
return NULL;
}
static inline bool skb_valid_dst(const struct sk_buff *skb)
{
struct dst_entry *dst = skb_dst(skb);
......@@ -92,6 +120,9 @@ static inline int skb_metadata_dst_cmp(const struct sk_buff *skb_a,
case METADATA_MACSEC:
return memcmp(&a->u.macsec_info, &b->u.macsec_info,
sizeof(a->u.macsec_info));
case METADATA_XFRM:
return memcmp(&a->u.xfrm_info, &b->u.xfrm_info,
sizeof(a->u.xfrm_info));
default:
return 1;
}
......
......@@ -22,7 +22,7 @@ struct xfrm_state;
int ipcomp_input(struct xfrm_state *x, struct sk_buff *skb);
int ipcomp_output(struct xfrm_state *x, struct sk_buff *skb);
void ipcomp_destroy(struct xfrm_state *x);
int ipcomp_init_state(struct xfrm_state *x);
int ipcomp_init_state(struct xfrm_state *x, struct netlink_ext_ack *extack);
static inline struct ip_comp_hdr *ip_comp_hdr(const struct sk_buff *skb)
{
......
......@@ -312,9 +312,15 @@ struct km_event {
struct net *net;
};
struct xfrm_if_decode_session_result {
struct net *net;
u32 if_id;
};
struct xfrm_if_cb {
struct xfrm_if *(*decode_session)(struct sk_buff *skb,
unsigned short family);
bool (*decode_session)(struct sk_buff *skb,
unsigned short family,
struct xfrm_if_decode_session_result *res);
};
void xfrm_if_register_cb(const struct xfrm_if_cb *ifcb);
......@@ -399,7 +405,8 @@ struct xfrm_type {
#define XFRM_TYPE_LOCAL_COADDR 4
#define XFRM_TYPE_REMOTE_COADDR 8
int (*init_state)(struct xfrm_state *x);
int (*init_state)(struct xfrm_state *x,
struct netlink_ext_ack *extack);
void (*destructor)(struct xfrm_state *);
int (*input)(struct xfrm_state *, struct sk_buff *skb);
int (*output)(struct xfrm_state *, struct sk_buff *pskb);
......@@ -985,6 +992,7 @@ void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev);
struct xfrm_if_parms {
int link; /* ifindex of underlying L2 interface */
u32 if_id; /* interface identifyer */
bool collect_md;
};
struct xfrm_if {
......@@ -1573,9 +1581,10 @@ int xfrm_dev_state_flush(struct net *net, struct net_device *dev, bool task_vali
void xfrm_sad_getinfo(struct net *net, struct xfrmk_sadinfo *si);
void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si);
u32 xfrm_replay_seqhi(struct xfrm_state *x, __be32 net_seq);
int xfrm_init_replay(struct xfrm_state *x);
int xfrm_init_replay(struct xfrm_state *x, struct netlink_ext_ack *extack);
u32 xfrm_state_mtu(struct xfrm_state *x, int mtu);
int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload);
int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload,
struct netlink_ext_ack *extack);
int xfrm_init_state(struct xfrm_state *x);
int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type);
int xfrm_input_resume(struct sk_buff *skb, int nexthdr);
......@@ -1879,7 +1888,8 @@ void xfrm_dev_resume(struct sk_buff *skb);
void xfrm_dev_backlog(struct softnet_data *sd);
struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t features, bool *again);
int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
struct xfrm_user_offload *xuo);
struct xfrm_user_offload *xuo,
struct netlink_ext_ack *extack);
bool xfrm_dev_offload_ok(struct sk_buff *skb, struct xfrm_state *x);
static inline void xfrm_dev_state_advance_esn(struct xfrm_state *x)
......@@ -1942,7 +1952,7 @@ static inline struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_fea
return skb;
}
static inline int xfrm_dev_state_add(struct net *net, struct xfrm_state *x, struct xfrm_user_offload *xuo)
static inline int xfrm_dev_state_add(struct net *net, struct xfrm_state *x, struct xfrm_user_offload *xuo, struct netlink_ext_ack *extack)
{
return 0;
}
......
......@@ -695,6 +695,7 @@ enum {
IFLA_XFRM_UNSPEC,
IFLA_XFRM_LINK,
IFLA_XFRM_IF_ID,
IFLA_XFRM_COLLECT_METADATA,
__IFLA_XFRM_MAX
};
......
......@@ -15,6 +15,7 @@ enum lwtunnel_encap_types {
LWTUNNEL_ENCAP_SEG6_LOCAL,
LWTUNNEL_ENCAP_RPL,
LWTUNNEL_ENCAP_IOAM6,
LWTUNNEL_ENCAP_XFRM,
__LWTUNNEL_ENCAP_MAX,
};
......@@ -111,4 +112,13 @@ enum {
#define LWT_BPF_MAX_HEADROOM 256
enum {
LWT_XFRM_UNSPEC,
LWT_XFRM_IF_ID,
LWT_XFRM_LINK,
__LWT_XFRM_MAX,
};
#define LWT_XFRM_MAX (__LWT_XFRM_MAX - 1)
#endif /* _UAPI_LWTUNNEL_H_ */
......@@ -50,6 +50,7 @@ static const char *lwtunnel_encap_str(enum lwtunnel_encap_types encap_type)
return "IOAM6";
case LWTUNNEL_ENCAP_IP6:
case LWTUNNEL_ENCAP_IP:
case LWTUNNEL_ENCAP_XFRM:
case LWTUNNEL_ENCAP_NONE:
case __LWTUNNEL_ENCAP_MAX:
/* should not have got here */
......
......@@ -471,30 +471,38 @@ static int ah4_err(struct sk_buff *skb, u32 info)
return 0;
}
static int ah_init_state(struct xfrm_state *x)
static int ah_init_state(struct xfrm_state *x, struct netlink_ext_ack *extack)
{
struct ah_data *ahp = NULL;
struct xfrm_algo_desc *aalg_desc;
struct crypto_ahash *ahash;
if (!x->aalg)
if (!x->aalg) {
NL_SET_ERR_MSG(extack, "AH requires a state with an AUTH algorithm");
goto error;
}
if (x->encap)
if (x->encap) {
NL_SET_ERR_MSG(extack, "AH is not compatible with encapsulation");
goto error;
}
ahp = kzalloc(sizeof(*ahp), GFP_KERNEL);
if (!ahp)
return -ENOMEM;
ahash = crypto_alloc_ahash(x->aalg->alg_name, 0, 0);
if (IS_ERR(ahash))
if (IS_ERR(ahash)) {
NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations");
goto error;
}
ahp->ahash = ahash;
if (crypto_ahash_setkey(ahash, x->aalg->alg_key,
(x->aalg->alg_key_len + 7) / 8))
(x->aalg->alg_key_len + 7) / 8)) {
NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations");
goto error;
}
/*
* Lookup the algorithm description maintained by xfrm_algo,
......@@ -507,10 +515,7 @@ static int ah_init_state(struct xfrm_state *x)
if (aalg_desc->uinfo.auth.icv_fullbits/8 !=
crypto_ahash_digestsize(ahash)) {
pr_info("%s: %s digestsize %u != %u\n",
__func__, x->aalg->alg_name,
crypto_ahash_digestsize(ahash),
aalg_desc->uinfo.auth.icv_fullbits / 8);
NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations");
goto error;
}
......
......@@ -1008,16 +1008,17 @@ static void esp_destroy(struct xfrm_state *x)
crypto_free_aead(aead);
}
static int esp_init_aead(struct xfrm_state *x)
static int esp_init_aead(struct xfrm_state *x, struct netlink_ext_ack *extack)
{
char aead_name[CRYPTO_MAX_ALG_NAME];
struct crypto_aead *aead;
int err;
err = -ENAMETOOLONG;
if (snprintf(aead_name, CRYPTO_MAX_ALG_NAME, "%s(%s)",
x->geniv, x->aead->alg_name) >= CRYPTO_MAX_ALG_NAME)
goto error;
x->geniv, x->aead->alg_name) >= CRYPTO_MAX_ALG_NAME) {
NL_SET_ERR_MSG(extack, "Algorithm name is too long");
return -ENAMETOOLONG;
}
aead = crypto_alloc_aead(aead_name, 0, 0);
err = PTR_ERR(aead);
......@@ -1035,11 +1036,15 @@ static int esp_init_aead(struct xfrm_state *x)
if (err)
goto error;
return 0;
error:
NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations");
return err;
}
static int esp_init_authenc(struct xfrm_state *x)
static int esp_init_authenc(struct xfrm_state *x,
struct netlink_ext_ack *extack)
{
struct crypto_aead *aead;
struct crypto_authenc_key_param *param;
......@@ -1050,10 +1055,6 @@ static int esp_init_authenc(struct xfrm_state *x)
unsigned int keylen;
int err;
err = -EINVAL;
if (!x->ealg)
goto error;
err = -ENAMETOOLONG;
if ((x->props.flags & XFRM_STATE_ESN)) {
......@@ -1062,22 +1063,28 @@ static int esp_init_authenc(struct xfrm_state *x)
x->geniv ?: "", x->geniv ? "(" : "",
x->aalg ? x->aalg->alg_name : "digest_null",
x->ealg->alg_name,
x->geniv ? ")" : "") >= CRYPTO_MAX_ALG_NAME)
x->geniv ? ")" : "") >= CRYPTO_MAX_ALG_NAME) {
NL_SET_ERR_MSG(extack, "Algorithm name is too long");
goto error;
}
} else {
if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME,
"%s%sauthenc(%s,%s)%s",
x->geniv ?: "", x->geniv ? "(" : "",
x->aalg ? x->aalg->alg_name : "digest_null",
x->ealg->alg_name,
x->geniv ? ")" : "") >= CRYPTO_MAX_ALG_NAME)
x->geniv ? ")" : "") >= CRYPTO_MAX_ALG_NAME) {
NL_SET_ERR_MSG(extack, "Algorithm name is too long");
goto error;
}
}
aead = crypto_alloc_aead(authenc_name, 0, 0);
err = PTR_ERR(aead);
if (IS_ERR(aead))
if (IS_ERR(aead)) {
NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations");
goto error;
}
x->data = aead;
......@@ -1107,18 +1114,17 @@ static int esp_init_authenc(struct xfrm_state *x)
err = -EINVAL;
if (aalg_desc->uinfo.auth.icv_fullbits / 8 !=
crypto_aead_authsize(aead)) {
pr_info("ESP: %s digestsize %u != %u\n",
x->aalg->alg_name,
crypto_aead_authsize(aead),
aalg_desc->uinfo.auth.icv_fullbits / 8);
NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations");
goto free_key;
}
err = crypto_aead_setauthsize(
aead, x->aalg->alg_trunc_len / 8);
if (err)
if (err) {
NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations");
goto free_key;
}
}
param->enckeylen = cpu_to_be32((x->ealg->alg_key_len + 7) / 8);
memcpy(p, x->ealg->alg_key, (x->ealg->alg_key_len + 7) / 8);
......@@ -1132,7 +1138,7 @@ static int esp_init_authenc(struct xfrm_state *x)
return err;
}
static int esp_init_state(struct xfrm_state *x)
static int esp_init_state(struct xfrm_state *x, struct netlink_ext_ack *extack)
{
struct crypto_aead *aead;
u32 align;
......@@ -1140,10 +1146,14 @@ static int esp_init_state(struct xfrm_state *x)
x->data = NULL;
if (x->aead)
err = esp_init_aead(x);
else
err = esp_init_authenc(x);
if (x->aead) {
err = esp_init_aead(x, extack);
} else if (x->ealg) {
err = esp_init_authenc(x, extack);
} else {
NL_SET_ERR_MSG(extack, "ESP: AEAD or CRYPT must be provided");
err = -EINVAL;
}
if (err)
goto error;
......@@ -1161,6 +1171,7 @@ static int esp_init_state(struct xfrm_state *x)
switch (encap->encap_type) {
default:
NL_SET_ERR_MSG(extack, "Unsupported encapsulation type for ESP");
err = -EINVAL;
goto error;
case UDP_ENCAP_ESPINUDP:
......
......@@ -117,7 +117,8 @@ static int ipcomp_tunnel_attach(struct xfrm_state *x)
return err;
}
static int ipcomp4_init_state(struct xfrm_state *x)
static int ipcomp4_init_state(struct xfrm_state *x,
struct netlink_ext_ack *extack)
{
int err = -EINVAL;
......@@ -129,18 +130,21 @@ static int ipcomp4_init_state(struct xfrm_state *x)
x->props.header_len += sizeof(struct iphdr);
break;
default:
NL_SET_ERR_MSG(extack, "Unsupported XFRM mode for IPcomp");
goto out;
}
err = ipcomp_init_state(x);
err = ipcomp_init_state(x, extack);
if (err)
goto out;
if (x->props.mode == XFRM_MODE_TUNNEL) {
err = ipcomp_tunnel_attach(x);
if (err)
if (err) {
NL_SET_ERR_MSG(extack, "Kernel error: failed to initialize the associated state");
goto out;
}
}
err = 0;
out:
......
......@@ -22,13 +22,17 @@ static int ipip_xfrm_rcv(struct xfrm_state *x, struct sk_buff *skb)
return ip_hdr(skb)->protocol;
}
static int ipip_init_state(struct xfrm_state *x)
static int ipip_init_state(struct xfrm_state *x, struct netlink_ext_ack *extack)
{
if (x->props.mode != XFRM_MODE_TUNNEL)
if (x->props.mode != XFRM_MODE_TUNNEL) {
NL_SET_ERR_MSG(extack, "IPv4 tunnel can only be used with tunnel mode");
return -EINVAL;
}
if (x->encap)
if (x->encap) {
NL_SET_ERR_MSG(extack, "IPv4 tunnel is not compatible with encapsulation");
return -EINVAL;
}
x->props.header_len = sizeof(struct iphdr);
......
......@@ -666,30 +666,38 @@ static int ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
return 0;
}
static int ah6_init_state(struct xfrm_state *x)
static int ah6_init_state(struct xfrm_state *x, struct netlink_ext_ack *extack)
{
struct ah_data *ahp = NULL;
struct xfrm_algo_desc *aalg_desc;
struct crypto_ahash *ahash;
if (!x->aalg)
if (!x->aalg) {
NL_SET_ERR_MSG(extack, "AH requires a state with an AUTH algorithm");
goto error;
}
if (x->encap)
if (x->encap) {
NL_SET_ERR_MSG(extack, "AH is not compatible with encapsulation");
goto error;
}
ahp = kzalloc(sizeof(*ahp), GFP_KERNEL);
if (!ahp)
return -ENOMEM;
ahash = crypto_alloc_ahash(x->aalg->alg_name, 0, 0);
if (IS_ERR(ahash))
if (IS_ERR(ahash)) {
NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations");
goto error;
}
ahp->ahash = ahash;
if (crypto_ahash_setkey(ahash, x->aalg->alg_key,
(x->aalg->alg_key_len + 7) / 8))
(x->aalg->alg_key_len + 7) / 8)) {
NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations");
goto error;
}
/*
* Lookup the algorithm description maintained by xfrm_algo,
......@@ -702,9 +710,7 @@ static int ah6_init_state(struct xfrm_state *x)
if (aalg_desc->uinfo.auth.icv_fullbits/8 !=
crypto_ahash_digestsize(ahash)) {
pr_info("AH: %s digestsize %u != %u\n",
x->aalg->alg_name, crypto_ahash_digestsize(ahash),
aalg_desc->uinfo.auth.icv_fullbits/8);
NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations");
goto error;
}
......@@ -721,6 +727,7 @@ static int ah6_init_state(struct xfrm_state *x)
x->props.header_len += sizeof(struct ipv6hdr);
break;
default:
NL_SET_ERR_MSG(extack, "Invalid mode requested for AH, must be one of TRANSPORT, TUNNEL, BEET");
goto error;
}
x->data = ahp;
......
......@@ -1051,16 +1051,17 @@ static void esp6_destroy(struct xfrm_state *x)
crypto_free_aead(aead);
}
static int esp_init_aead(struct xfrm_state *x)
static int esp_init_aead(struct xfrm_state *x, struct netlink_ext_ack *extack)
{
char aead_name[CRYPTO_MAX_ALG_NAME];
struct crypto_aead *aead;
int err;
err = -ENAMETOOLONG;
if (snprintf(aead_name, CRYPTO_MAX_ALG_NAME, "%s(%s)",
x->geniv, x->aead->alg_name) >= CRYPTO_MAX_ALG_NAME)
goto error;
x->geniv, x->aead->alg_name) >= CRYPTO_MAX_ALG_NAME) {
NL_SET_ERR_MSG(extack, "Algorithm name is too long");
return -ENAMETOOLONG;
}
aead = crypto_alloc_aead(aead_name, 0, 0);
err = PTR_ERR(aead);
......@@ -1078,11 +1079,15 @@ static int esp_init_aead(struct xfrm_state *x)
if (err)
goto error;
return 0;
error:
NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations");
return err;
}
static int esp_init_authenc(struct xfrm_state *x)
static int esp_init_authenc(struct xfrm_state *x,
struct netlink_ext_ack *extack)
{
struct crypto_aead *aead;
struct crypto_authenc_key_param *param;
......@@ -1093,10 +1098,6 @@ static int esp_init_authenc(struct xfrm_state *x)
unsigned int keylen;
int err;
err = -EINVAL;
if (!x->ealg)
goto error;
err = -ENAMETOOLONG;
if ((x->props.flags & XFRM_STATE_ESN)) {
......@@ -1105,22 +1106,28 @@ static int esp_init_authenc(struct xfrm_state *x)
x->geniv ?: "", x->geniv ? "(" : "",
x->aalg ? x->aalg->alg_name : "digest_null",
x->ealg->alg_name,
x->geniv ? ")" : "") >= CRYPTO_MAX_ALG_NAME)
x->geniv ? ")" : "") >= CRYPTO_MAX_ALG_NAME) {
NL_SET_ERR_MSG(extack, "Algorithm name is too long");
goto error;
}
} else {
if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME,
"%s%sauthenc(%s,%s)%s",
x->geniv ?: "", x->geniv ? "(" : "",
x->aalg ? x->aalg->alg_name : "digest_null",
x->ealg->alg_name,
x->geniv ? ")" : "") >= CRYPTO_MAX_ALG_NAME)
x->geniv ? ")" : "") >= CRYPTO_MAX_ALG_NAME) {
NL_SET_ERR_MSG(extack, "Algorithm name is too long");
goto error;
}
}
aead = crypto_alloc_aead(authenc_name, 0, 0);
err = PTR_ERR(aead);
if (IS_ERR(aead))
if (IS_ERR(aead)) {
NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations");
goto error;
}
x->data = aead;
......@@ -1150,18 +1157,17 @@ static int esp_init_authenc(struct xfrm_state *x)
err = -EINVAL;
if (aalg_desc->uinfo.auth.icv_fullbits / 8 !=
crypto_aead_authsize(aead)) {
pr_info("ESP: %s digestsize %u != %u\n",
x->aalg->alg_name,
crypto_aead_authsize(aead),
aalg_desc->uinfo.auth.icv_fullbits / 8);
NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations");
goto free_key;
}
err = crypto_aead_setauthsize(
aead, x->aalg->alg_trunc_len / 8);
if (err)
if (err) {
NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations");
goto free_key;
}
}
param->enckeylen = cpu_to_be32((x->ealg->alg_key_len + 7) / 8);
memcpy(p, x->ealg->alg_key, (x->ealg->alg_key_len + 7) / 8);
......@@ -1175,7 +1181,7 @@ static int esp_init_authenc(struct xfrm_state *x)
return err;
}
static int esp6_init_state(struct xfrm_state *x)
static int esp6_init_state(struct xfrm_state *x, struct netlink_ext_ack *extack)
{
struct crypto_aead *aead;
u32 align;
......@@ -1183,10 +1189,14 @@ static int esp6_init_state(struct xfrm_state *x)
x->data = NULL;
if (x->aead)
err = esp_init_aead(x);
else
err = esp_init_authenc(x);
if (x->aead) {
err = esp_init_aead(x, extack);
} else if (x->ealg) {
err = esp_init_authenc(x, extack);
} else {
NL_SET_ERR_MSG(extack, "ESP: AEAD or CRYPT must be provided");
err = -EINVAL;
}
if (err)
goto error;
......@@ -1214,6 +1224,7 @@ static int esp6_init_state(struct xfrm_state *x)
switch (encap->encap_type) {
default:
NL_SET_ERR_MSG(extack, "Unsupported encapsulation type for ESP");
err = -EINVAL;
goto error;
case UDP_ENCAP_ESPINUDP:
......
......@@ -136,7 +136,8 @@ static int ipcomp6_tunnel_attach(struct xfrm_state *x)
return err;
}
static int ipcomp6_init_state(struct xfrm_state *x)
static int ipcomp6_init_state(struct xfrm_state *x,
struct netlink_ext_ack *extack)
{
int err = -EINVAL;
......@@ -148,18 +149,21 @@ static int ipcomp6_init_state(struct xfrm_state *x)
x->props.header_len += sizeof(struct ipv6hdr);
break;
default:
NL_SET_ERR_MSG(extack, "Unsupported XFRM mode for IPcomp");
goto out;
}
err = ipcomp_init_state(x);
err = ipcomp_init_state(x, extack);
if (err)
goto out;
if (x->props.mode == XFRM_MODE_TUNNEL) {
err = ipcomp6_tunnel_attach(x);
if (err)
if (err) {
NL_SET_ERR_MSG(extack, "Kernel error: failed to initialize the associated state");
goto out;
}
}
err = 0;
out:
......
......@@ -247,15 +247,14 @@ static int mip6_destopt_reject(struct xfrm_state *x, struct sk_buff *skb,
return err;
}
static int mip6_destopt_init_state(struct xfrm_state *x)
static int mip6_destopt_init_state(struct xfrm_state *x, struct netlink_ext_ack *extack)
{
if (x->id.spi) {
pr_info("%s: spi is not 0: %u\n", __func__, x->id.spi);
NL_SET_ERR_MSG(extack, "SPI must be 0");
return -EINVAL;
}
if (x->props.mode != XFRM_MODE_ROUTEOPTIMIZATION) {
pr_info("%s: state's mode is not %u: %u\n",
__func__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode);
NL_SET_ERR_MSG(extack, "XFRM mode must be XFRM_MODE_ROUTEOPTIMIZATION");
return -EINVAL;
}
......@@ -333,15 +332,14 @@ static int mip6_rthdr_output(struct xfrm_state *x, struct sk_buff *skb)
return 0;
}
static int mip6_rthdr_init_state(struct xfrm_state *x)
static int mip6_rthdr_init_state(struct xfrm_state *x, struct netlink_ext_ack *extack)
{
if (x->id.spi) {
pr_info("%s: spi is not 0: %u\n", __func__, x->id.spi);
NL_SET_ERR_MSG(extack, "SPI must be 0");
return -EINVAL;
}
if (x->props.mode != XFRM_MODE_ROUTEOPTIMIZATION) {
pr_info("%s: state's mode is not %u: %u\n",
__func__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode);
NL_SET_ERR_MSG(extack, "XFRM mode must be XFRM_MODE_ROUTEOPTIMIZATION");
return -EINVAL;
}
......
......@@ -270,13 +270,17 @@ static int xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
return 0;
}
static int xfrm6_tunnel_init_state(struct xfrm_state *x)
static int xfrm6_tunnel_init_state(struct xfrm_state *x, struct netlink_ext_ack *extack)
{
if (x->props.mode != XFRM_MODE_TUNNEL)
if (x->props.mode != XFRM_MODE_TUNNEL) {
NL_SET_ERR_MSG(extack, "IPv6 tunnel can only be used with tunnel mode");
return -EINVAL;
}
if (x->encap)
if (x->encap) {
NL_SET_ERR_MSG(extack, "IPv6 tunnel is not compatible with encapsulation");
return -EINVAL;
}
x->props.header_len = sizeof(struct ipv6hdr);
......
......@@ -207,7 +207,8 @@ struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t featur
EXPORT_SYMBOL_GPL(validate_xmit_xfrm);
int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
struct xfrm_user_offload *xuo)
struct xfrm_user_offload *xuo,
struct netlink_ext_ack *extack)
{
int err;
struct dst_entry *dst;
......@@ -216,15 +217,21 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
xfrm_address_t *saddr;
xfrm_address_t *daddr;
if (!x->type_offload)
if (!x->type_offload) {
NL_SET_ERR_MSG(extack, "Type doesn't support offload");
return -EINVAL;
}
/* We don't yet support UDP encapsulation and TFC padding. */
if (x->encap || x->tfcpad)
if (x->encap || x->tfcpad) {
NL_SET_ERR_MSG(extack, "Encapsulation and TFC padding can't be offloaded");
return -EINVAL;
}
if (xuo->flags & ~(XFRM_OFFLOAD_IPV6 | XFRM_OFFLOAD_INBOUND))
if (xuo->flags & ~(XFRM_OFFLOAD_IPV6 | XFRM_OFFLOAD_INBOUND)) {
NL_SET_ERR_MSG(extack, "Unrecognized flags in offload request");
return -EINVAL;
}
dev = dev_get_by_index(net, xuo->ifindex);
if (!dev) {
......@@ -256,6 +263,7 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
if (x->props.flags & XFRM_STATE_ESN &&
!dev->xfrmdev_ops->xdo_dev_state_advance_esn) {
NL_SET_ERR_MSG(extack, "Device doesn't support offload with ESN");
xso->dev = NULL;
dev_put(dev);
return -EINVAL;
......@@ -277,9 +285,11 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
xso->real_dev = NULL;
netdev_put(dev, &xso->dev_tracker);
if (err != -EOPNOTSUPP)
if (err != -EOPNOTSUPP) {
NL_SET_ERR_MSG(extack, "Device failed to offload this state");
return err;
}
}
return 0;
}
......
......@@ -20,6 +20,7 @@
#include <net/xfrm.h>
#include <net/ip_tunnels.h>
#include <net/ip6_tunnel.h>
#include <net/dst_metadata.h>
#include "xfrm_inout.h"
......@@ -719,6 +720,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
sp = skb_sec_path(skb);
if (sp)
sp->olen = 0;
if (skb_valid_dst(skb))
skb_dst_drop(skb);
gro_cells_receive(&gro_cells, skb);
return 0;
......@@ -737,6 +739,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
sp = skb_sec_path(skb);
if (sp)
sp->olen = 0;
if (skb_valid_dst(skb))
skb_dst_drop(skb);
gro_cells_receive(&gro_cells, skb);
return err;
......
......@@ -41,6 +41,7 @@
#include <net/addrconf.h>
#include <net/xfrm.h>
#include <net/net_namespace.h>
#include <net/dst_metadata.h>
#include <net/netns/generic.h>
#include <linux/etherdevice.h>
......@@ -56,6 +57,89 @@ static const struct net_device_ops xfrmi_netdev_ops;
struct xfrmi_net {
/* lists for storing interfaces in use */
struct xfrm_if __rcu *xfrmi[XFRMI_HASH_SIZE];
struct xfrm_if __rcu *collect_md_xfrmi;
};
static const struct nla_policy xfrm_lwt_policy[LWT_XFRM_MAX + 1] = {
[LWT_XFRM_IF_ID] = NLA_POLICY_MIN(NLA_U32, 1),
[LWT_XFRM_LINK] = NLA_POLICY_MIN(NLA_U32, 1),
};
static void xfrmi_destroy_state(struct lwtunnel_state *lwt)
{
}
static int xfrmi_build_state(struct net *net, struct nlattr *nla,
unsigned int family, const void *cfg,
struct lwtunnel_state **ts,
struct netlink_ext_ack *extack)
{
struct nlattr *tb[LWT_XFRM_MAX + 1];
struct lwtunnel_state *new_state;
struct xfrm_md_info *info;
int ret;
ret = nla_parse_nested(tb, LWT_XFRM_MAX, nla, xfrm_lwt_policy, extack);
if (ret < 0)
return ret;
if (!tb[LWT_XFRM_IF_ID]) {
NL_SET_ERR_MSG(extack, "if_id must be set");
return -EINVAL;
}
new_state = lwtunnel_state_alloc(sizeof(*info));
if (!new_state) {
NL_SET_ERR_MSG(extack, "failed to create encap info");
return -ENOMEM;
}
new_state->type = LWTUNNEL_ENCAP_XFRM;
info = lwt_xfrm_info(new_state);
info->if_id = nla_get_u32(tb[LWT_XFRM_IF_ID]);
if (tb[LWT_XFRM_LINK])
info->link = nla_get_u32(tb[LWT_XFRM_LINK]);
*ts = new_state;
return 0;
}
static int xfrmi_fill_encap_info(struct sk_buff *skb,
struct lwtunnel_state *lwt)
{
struct xfrm_md_info *info = lwt_xfrm_info(lwt);
if (nla_put_u32(skb, LWT_XFRM_IF_ID, info->if_id) ||
(info->link && nla_put_u32(skb, LWT_XFRM_LINK, info->link)))
return -EMSGSIZE;
return 0;
}
static int xfrmi_encap_nlsize(struct lwtunnel_state *lwtstate)
{
return nla_total_size(sizeof(u32)) + /* LWT_XFRM_IF_ID */
nla_total_size(sizeof(u32)); /* LWT_XFRM_LINK */
}
static int xfrmi_encap_cmp(struct lwtunnel_state *a, struct lwtunnel_state *b)
{
struct xfrm_md_info *a_info = lwt_xfrm_info(a);
struct xfrm_md_info *b_info = lwt_xfrm_info(b);
return memcmp(a_info, b_info, sizeof(*a_info));
}
static const struct lwtunnel_encap_ops xfrmi_encap_ops = {
.build_state = xfrmi_build_state,
.destroy_state = xfrmi_destroy_state,
.fill_encap = xfrmi_fill_encap_info,
.get_encap_size = xfrmi_encap_nlsize,
.cmp_encap = xfrmi_encap_cmp,
.owner = THIS_MODULE,
};
#define for_each_xfrmi_rcu(start, xi) \
......@@ -77,17 +161,23 @@ static struct xfrm_if *xfrmi_lookup(struct net *net, struct xfrm_state *x)
return xi;
}
xi = rcu_dereference(xfrmn->collect_md_xfrmi);
if (xi && (xi->dev->flags & IFF_UP))
return xi;
return NULL;
}
static struct xfrm_if *xfrmi_decode_session(struct sk_buff *skb,
unsigned short family)
static bool xfrmi_decode_session(struct sk_buff *skb,
unsigned short family,
struct xfrm_if_decode_session_result *res)
{
struct net_device *dev;
struct xfrm_if *xi;
int ifindex = 0;
if (!secpath_exists(skb) || !skb->dev)
return NULL;
return false;
switch (family) {
case AF_INET6:
......@@ -107,11 +197,18 @@ static struct xfrm_if *xfrmi_decode_session(struct sk_buff *skb,
}
if (!dev || !(dev->flags & IFF_UP))
return NULL;
return false;
if (dev->netdev_ops != &xfrmi_netdev_ops)
return NULL;
return false;
xi = netdev_priv(dev);
res->net = xi->net;
return netdev_priv(dev);
if (xi->p.collect_md)
res->if_id = xfrm_input_state(skb)->if_id;
else
res->if_id = xi->p.if_id;
return true;
}
static void xfrmi_link(struct xfrmi_net *xfrmn, struct xfrm_if *xi)
......@@ -157,6 +254,9 @@ static int xfrmi_create(struct net_device *dev)
if (err < 0)
goto out;
if (xi->p.collect_md)
rcu_assign_pointer(xfrmn->collect_md_xfrmi, xi);
else
xfrmi_link(xfrmn, xi);
return 0;
......@@ -185,6 +285,9 @@ static void xfrmi_dev_uninit(struct net_device *dev)
struct xfrm_if *xi = netdev_priv(dev);
struct xfrmi_net *xfrmn = net_generic(xi->net, xfrmi_net_id);
if (xi->p.collect_md)
RCU_INIT_POINTER(xfrmn->collect_md_xfrmi, NULL);
else
xfrmi_unlink(xfrmn, xi);
}
......@@ -214,6 +317,7 @@ static int xfrmi_rcv_cb(struct sk_buff *skb, int err)
struct xfrm_state *x;
struct xfrm_if *xi;
bool xnet;
int link;
if (err && !secpath_exists(skb))
return 0;
......@@ -224,6 +328,7 @@ static int xfrmi_rcv_cb(struct sk_buff *skb, int err)
if (!xi)
return 1;
link = skb->dev->ifindex;
dev = xi->dev;
skb->dev = dev;
......@@ -254,6 +359,17 @@ static int xfrmi_rcv_cb(struct sk_buff *skb, int err)
}
xfrmi_scrub_packet(skb, xnet);
if (xi->p.collect_md) {
struct metadata_dst *md_dst;
md_dst = metadata_dst_alloc(0, METADATA_XFRM, GFP_ATOMIC);
if (!md_dst)
return -ENOMEM;
md_dst->u.xfrm_info.if_id = x->if_id;
md_dst->u.xfrm_info.link = link;
skb_dst_set(skb, (struct dst_entry *)md_dst);
}
dev_sw_netstats_rx_add(dev, skb->len);
return 0;
......@@ -269,10 +385,23 @@ xfrmi_xmit2(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
struct net_device *tdev;
struct xfrm_state *x;
int err = -1;
u32 if_id;
int mtu;
if (xi->p.collect_md) {
struct xfrm_md_info *md_info = skb_xfrm_md_info(skb);
if (unlikely(!md_info))
return -EINVAL;
if_id = md_info->if_id;
fl->flowi_oif = md_info->link;
} else {
if_id = xi->p.if_id;
}
dst_hold(dst);
dst = xfrm_lookup_with_ifid(xi->net, dst, fl, NULL, 0, xi->p.if_id);
dst = xfrm_lookup_with_ifid(xi->net, dst, fl, NULL, 0, if_id);
if (IS_ERR(dst)) {
err = PTR_ERR(dst);
dst = NULL;
......@@ -283,7 +412,7 @@ xfrmi_xmit2(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
if (!x)
goto tx_err_link_failure;
if (x->if_id != xi->p.if_id)
if (x->if_id != if_id)
goto tx_err_link_failure;
tdev = dst->dev;
......@@ -633,6 +762,9 @@ static void xfrmi_netlink_parms(struct nlattr *data[],
if (data[IFLA_XFRM_IF_ID])
parms->if_id = nla_get_u32(data[IFLA_XFRM_IF_ID]);
if (data[IFLA_XFRM_COLLECT_METADATA])
parms->collect_md = true;
}
static int xfrmi_newlink(struct net *src_net, struct net_device *dev,
......@@ -645,6 +777,18 @@ static int xfrmi_newlink(struct net *src_net, struct net_device *dev,
int err;
xfrmi_netlink_parms(data, &p);
if (p.collect_md) {
struct xfrmi_net *xfrmn = net_generic(net, xfrmi_net_id);
if (p.link || p.if_id) {
NL_SET_ERR_MSG(extack, "link and if_id must be zero");
return -EINVAL;
}
if (rtnl_dereference(xfrmn->collect_md_xfrmi))
return -EEXIST;
} else {
if (!p.if_id) {
NL_SET_ERR_MSG(extack, "if_id must be non zero");
return -EINVAL;
......@@ -653,6 +797,7 @@ static int xfrmi_newlink(struct net *src_net, struct net_device *dev,
xi = xfrmi_locate(net, &p);
if (xi)
return -EEXIST;
}
xi = netdev_priv(dev);
xi->p = p;
......@@ -682,12 +827,22 @@ static int xfrmi_changelink(struct net_device *dev, struct nlattr *tb[],
return -EINVAL;
}
if (p.collect_md) {
NL_SET_ERR_MSG(extack, "collect_md can't be changed");
return -EINVAL;
}
xi = xfrmi_locate(net, &p);
if (!xi) {
xi = netdev_priv(dev);
} else {
if (xi->dev != dev)
return -EEXIST;
if (xi->p.collect_md) {
NL_SET_ERR_MSG(extack,
"device can't be changed to collect_md");
return -EINVAL;
}
}
return xfrmi_update(xi, &p);
......@@ -700,6 +855,8 @@ static size_t xfrmi_get_size(const struct net_device *dev)
nla_total_size(4) +
/* IFLA_XFRM_IF_ID */
nla_total_size(4) +
/* IFLA_XFRM_COLLECT_METADATA */
nla_total_size(0) +
0;
}
......@@ -709,7 +866,8 @@ static int xfrmi_fill_info(struct sk_buff *skb, const struct net_device *dev)
struct xfrm_if_parms *parm = &xi->p;
if (nla_put_u32(skb, IFLA_XFRM_LINK, parm->link) ||
nla_put_u32(skb, IFLA_XFRM_IF_ID, parm->if_id))
nla_put_u32(skb, IFLA_XFRM_IF_ID, parm->if_id) ||
(xi->p.collect_md && nla_put_flag(skb, IFLA_XFRM_COLLECT_METADATA)))
goto nla_put_failure;
return 0;
......@@ -725,8 +883,10 @@ static struct net *xfrmi_get_link_net(const struct net_device *dev)
}
static const struct nla_policy xfrmi_policy[IFLA_XFRM_MAX + 1] = {
[IFLA_XFRM_UNSPEC] = { .strict_start_type = IFLA_XFRM_COLLECT_METADATA },
[IFLA_XFRM_LINK] = { .type = NLA_U32 },
[IFLA_XFRM_IF_ID] = { .type = NLA_U32 },
[IFLA_XFRM_COLLECT_METADATA] = { .type = NLA_FLAG },
};
static struct rtnl_link_ops xfrmi_link_ops __read_mostly = {
......@@ -762,6 +922,9 @@ static void __net_exit xfrmi_exit_batch_net(struct list_head *net_exit_list)
xip = &xi->next)
unregister_netdevice_queue(xi->dev, &list);
}
xi = rtnl_dereference(xfrmn->collect_md_xfrmi);
if (xi)
unregister_netdevice_queue(xi->dev, &list);
}
unregister_netdevice_many(&list);
rtnl_unlock();
......@@ -999,6 +1162,8 @@ static int __init xfrmi_init(void)
if (err < 0)
goto rtnl_link_failed;
lwtunnel_encap_add_ops(&xfrmi_encap_ops, LWTUNNEL_ENCAP_XFRM);
xfrm_if_register_cb(&xfrm_if_cb);
return err;
......@@ -1017,6 +1182,7 @@ static int __init xfrmi_init(void)
static void __exit xfrmi_fini(void)
{
xfrm_if_unregister_cb();
lwtunnel_encap_del_ops(&xfrmi_encap_ops, LWTUNNEL_ENCAP_XFRM);
rtnl_link_unregister(&xfrmi_link_ops);
xfrmi4_fini();
xfrmi6_fini();
......
......@@ -325,18 +325,22 @@ void ipcomp_destroy(struct xfrm_state *x)
}
EXPORT_SYMBOL_GPL(ipcomp_destroy);
int ipcomp_init_state(struct xfrm_state *x)
int ipcomp_init_state(struct xfrm_state *x, struct netlink_ext_ack *extack)
{
int err;
struct ipcomp_data *ipcd;
struct xfrm_algo_desc *calg_desc;
err = -EINVAL;
if (!x->calg)
if (!x->calg) {
NL_SET_ERR_MSG(extack, "Missing required compression algorithm");
goto out;
}
if (x->encap)
if (x->encap) {
NL_SET_ERR_MSG(extack, "IPComp is not compatible with encapsulation");
goto out;
}
err = -ENOMEM;
ipcd = kzalloc(sizeof(*ipcd), GFP_KERNEL);
......
......@@ -1889,7 +1889,7 @@ EXPORT_SYMBOL(xfrm_policy_walk_done);
*/
static int xfrm_policy_match(const struct xfrm_policy *pol,
const struct flowi *fl,
u8 type, u16 family, int dir, u32 if_id)
u8 type, u16 family, u32 if_id)
{
const struct xfrm_selector *sel = &pol->selector;
int ret = -ESRCH;
......@@ -2014,7 +2014,7 @@ static struct xfrm_policy *
__xfrm_policy_eval_candidates(struct hlist_head *chain,
struct xfrm_policy *prefer,
const struct flowi *fl,
u8 type, u16 family, int dir, u32 if_id)
u8 type, u16 family, u32 if_id)
{
u32 priority = prefer ? prefer->priority : ~0u;
struct xfrm_policy *pol;
......@@ -2028,7 +2028,7 @@ __xfrm_policy_eval_candidates(struct hlist_head *chain,
if (pol->priority > priority)
break;
err = xfrm_policy_match(pol, fl, type, family, dir, if_id);
err = xfrm_policy_match(pol, fl, type, family, if_id);
if (err) {
if (err != -ESRCH)
return ERR_PTR(err);
......@@ -2053,7 +2053,7 @@ static struct xfrm_policy *
xfrm_policy_eval_candidates(struct xfrm_pol_inexact_candidates *cand,
struct xfrm_policy *prefer,
const struct flowi *fl,
u8 type, u16 family, int dir, u32 if_id)
u8 type, u16 family, u32 if_id)
{
struct xfrm_policy *tmp;
int i;
......@@ -2061,8 +2061,7 @@ xfrm_policy_eval_candidates(struct xfrm_pol_inexact_candidates *cand,
for (i = 0; i < ARRAY_SIZE(cand->res); i++) {
tmp = __xfrm_policy_eval_candidates(cand->res[i],
prefer,
fl, type, family, dir,
if_id);
fl, type, family, if_id);
if (!tmp)
continue;
......@@ -2101,7 +2100,7 @@ static struct xfrm_policy *xfrm_policy_lookup_bytype(struct net *net, u8 type,
ret = NULL;
hlist_for_each_entry_rcu(pol, chain, bydst) {
err = xfrm_policy_match(pol, fl, type, family, dir, if_id);
err = xfrm_policy_match(pol, fl, type, family, if_id);
if (err) {
if (err == -ESRCH)
continue;
......@@ -2120,7 +2119,7 @@ static struct xfrm_policy *xfrm_policy_lookup_bytype(struct net *net, u8 type,
goto skip_inexact;
pol = xfrm_policy_eval_candidates(&cand, ret, fl, type,
family, dir, if_id);
family, if_id);
if (pol) {
ret = pol;
if (IS_ERR(pol))
......@@ -3516,17 +3515,17 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
int xerr_idx = -1;
const struct xfrm_if_cb *ifcb;
struct sec_path *sp;
struct xfrm_if *xi;
u32 if_id = 0;
rcu_read_lock();
ifcb = xfrm_if_get_cb();
if (ifcb) {
xi = ifcb->decode_session(skb, family);
if (xi) {
if_id = xi->p.if_id;
net = xi->net;
struct xfrm_if_decode_session_result r;
if (ifcb->decode_session(skb, family, &r)) {
if_id = r.if_id;
net = r.net;
}
}
rcu_read_unlock();
......
......@@ -766,18 +766,22 @@ int xfrm_replay_overflow(struct xfrm_state *x, struct sk_buff *skb)
}
#endif
int xfrm_init_replay(struct xfrm_state *x)
int xfrm_init_replay(struct xfrm_state *x, struct netlink_ext_ack *extack)
{
struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
if (replay_esn) {
if (replay_esn->replay_window >
replay_esn->bmp_len * sizeof(__u32) * 8)
replay_esn->bmp_len * sizeof(__u32) * 8) {
NL_SET_ERR_MSG(extack, "ESN replay window is too large for the chosen bitmap size");
return -EINVAL;
}
if (x->props.flags & XFRM_STATE_ESN) {
if (replay_esn->replay_window == 0)
if (replay_esn->replay_window == 0) {
NL_SET_ERR_MSG(extack, "ESN replay window must be > 0");
return -EINVAL;
}
x->repl_mode = XFRM_REPLAY_MODE_ESN;
} else {
x->repl_mode = XFRM_REPLAY_MODE_BMP;
......
......@@ -2611,7 +2611,8 @@ u32 xfrm_state_mtu(struct xfrm_state *x, int mtu)
}
EXPORT_SYMBOL_GPL(xfrm_state_mtu);
int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload)
int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload,
struct netlink_ext_ack *extack)
{
const struct xfrm_mode *inner_mode;
const struct xfrm_mode *outer_mode;
......@@ -2626,12 +2627,16 @@ int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload)
if (x->sel.family != AF_UNSPEC) {
inner_mode = xfrm_get_mode(x->props.mode, x->sel.family);
if (inner_mode == NULL)
if (inner_mode == NULL) {
NL_SET_ERR_MSG(extack, "Requested mode not found");
goto error;
}
if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL) &&
family != x->sel.family)
family != x->sel.family) {
NL_SET_ERR_MSG(extack, "Only tunnel modes can accommodate a change of family");
goto error;
}
x->inner_mode = *inner_mode;
} else {
......@@ -2639,11 +2644,15 @@ int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload)
int iafamily = AF_INET;
inner_mode = xfrm_get_mode(x->props.mode, x->props.family);
if (inner_mode == NULL)
if (inner_mode == NULL) {
NL_SET_ERR_MSG(extack, "Requested mode not found");
goto error;
}
if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL))
if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL)) {
NL_SET_ERR_MSG(extack, "Only tunnel modes can accommodate an AF_UNSPEC selector");
goto error;
}
x->inner_mode = *inner_mode;
......@@ -2658,24 +2667,27 @@ int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload)
}
x->type = xfrm_get_type(x->id.proto, family);
if (x->type == NULL)
if (x->type == NULL) {
NL_SET_ERR_MSG(extack, "Requested type not found");
goto error;
}
x->type_offload = xfrm_get_type_offload(x->id.proto, family, offload);
err = x->type->init_state(x);
err = x->type->init_state(x, extack);
if (err)
goto error;
outer_mode = xfrm_get_mode(x->props.mode, family);
if (!outer_mode) {
NL_SET_ERR_MSG(extack, "Requested mode not found");
err = -EPROTONOSUPPORT;
goto error;
}
x->outer_mode = *outer_mode;
if (init_replay) {
err = xfrm_init_replay(x);
err = xfrm_init_replay(x, extack);
if (err)
goto error;
}
......@@ -2690,7 +2702,7 @@ int xfrm_init_state(struct xfrm_state *x)
{
int err;
err = __xfrm_init_state(x, true, false);
err = __xfrm_init_state(x, true, false, NULL);
if (!err)
x->km.state = XFRM_STATE_VALID;
......
This diff is collapsed.
......@@ -58,6 +58,8 @@
#define VETH_FMT "ktst-%d"
#define VETH_LEN 12
#define XFRM_ALGO_NR_KEYS 29
static int nsfd_parent = -1;
static int nsfd_childa = -1;
static int nsfd_childb = -1;
......@@ -75,6 +77,43 @@ const unsigned int ping_timeout = 300;
const unsigned int ping_count = 100;
const unsigned int ping_success = 80;
struct xfrm_key_entry {
char algo_name[35];
int key_len;
};
struct xfrm_key_entry xfrm_key_entries[] = {
{"digest_null", 0},
{"ecb(cipher_null)", 0},
{"cbc(des)", 64},
{"hmac(md5)", 128},
{"cmac(aes)", 128},
{"xcbc(aes)", 128},
{"cbc(cast5)", 128},
{"cbc(serpent)", 128},
{"hmac(sha1)", 160},
{"hmac(rmd160)", 160},
{"cbc(des3_ede)", 192},
{"hmac(sha256)", 256},
{"cbc(aes)", 256},
{"cbc(camellia)", 256},
{"cbc(twofish)", 256},
{"rfc3686(ctr(aes))", 288},
{"hmac(sha384)", 384},
{"cbc(blowfish)", 448},
{"hmac(sha512)", 512},
{"rfc4106(gcm(aes))-128", 160},
{"rfc4543(gcm(aes))-128", 160},
{"rfc4309(ccm(aes))-128", 152},
{"rfc4106(gcm(aes))-192", 224},
{"rfc4543(gcm(aes))-192", 224},
{"rfc4309(ccm(aes))-192", 216},
{"rfc4106(gcm(aes))-256", 288},
{"rfc4543(gcm(aes))-256", 288},
{"rfc4309(ccm(aes))-256", 280},
{"rfc7539(chacha20,poly1305)-128", 0}
};
static void randomize_buffer(void *buf, size_t buflen)
{
int *p = (int *)buf;
......@@ -767,65 +806,12 @@ static int do_ping(int cmd_fd, char *buf, size_t buf_len, struct in_addr from,
static int xfrm_fill_key(char *name, char *buf,
size_t buf_len, unsigned int *key_len)
{
/* TODO: use set/map instead */
if (strncmp(name, "digest_null", ALGO_LEN) == 0)
*key_len = 0;
else if (strncmp(name, "ecb(cipher_null)", ALGO_LEN) == 0)
*key_len = 0;
else if (strncmp(name, "cbc(des)", ALGO_LEN) == 0)
*key_len = 64;
else if (strncmp(name, "hmac(md5)", ALGO_LEN) == 0)
*key_len = 128;
else if (strncmp(name, "cmac(aes)", ALGO_LEN) == 0)
*key_len = 128;
else if (strncmp(name, "xcbc(aes)", ALGO_LEN) == 0)
*key_len = 128;
else if (strncmp(name, "cbc(cast5)", ALGO_LEN) == 0)
*key_len = 128;
else if (strncmp(name, "cbc(serpent)", ALGO_LEN) == 0)
*key_len = 128;
else if (strncmp(name, "hmac(sha1)", ALGO_LEN) == 0)
*key_len = 160;
else if (strncmp(name, "hmac(rmd160)", ALGO_LEN) == 0)
*key_len = 160;
else if (strncmp(name, "cbc(des3_ede)", ALGO_LEN) == 0)
*key_len = 192;
else if (strncmp(name, "hmac(sha256)", ALGO_LEN) == 0)
*key_len = 256;
else if (strncmp(name, "cbc(aes)", ALGO_LEN) == 0)
*key_len = 256;
else if (strncmp(name, "cbc(camellia)", ALGO_LEN) == 0)
*key_len = 256;
else if (strncmp(name, "cbc(twofish)", ALGO_LEN) == 0)
*key_len = 256;
else if (strncmp(name, "rfc3686(ctr(aes))", ALGO_LEN) == 0)
*key_len = 288;
else if (strncmp(name, "hmac(sha384)", ALGO_LEN) == 0)
*key_len = 384;
else if (strncmp(name, "cbc(blowfish)", ALGO_LEN) == 0)
*key_len = 448;
else if (strncmp(name, "hmac(sha512)", ALGO_LEN) == 0)
*key_len = 512;
else if (strncmp(name, "rfc4106(gcm(aes))-128", ALGO_LEN) == 0)
*key_len = 160;
else if (strncmp(name, "rfc4543(gcm(aes))-128", ALGO_LEN) == 0)
*key_len = 160;
else if (strncmp(name, "rfc4309(ccm(aes))-128", ALGO_LEN) == 0)
*key_len = 152;
else if (strncmp(name, "rfc4106(gcm(aes))-192", ALGO_LEN) == 0)
*key_len = 224;
else if (strncmp(name, "rfc4543(gcm(aes))-192", ALGO_LEN) == 0)
*key_len = 224;
else if (strncmp(name, "rfc4309(ccm(aes))-192", ALGO_LEN) == 0)
*key_len = 216;
else if (strncmp(name, "rfc4106(gcm(aes))-256", ALGO_LEN) == 0)
*key_len = 288;
else if (strncmp(name, "rfc4543(gcm(aes))-256", ALGO_LEN) == 0)
*key_len = 288;
else if (strncmp(name, "rfc4309(ccm(aes))-256", ALGO_LEN) == 0)
*key_len = 280;
else if (strncmp(name, "rfc7539(chacha20,poly1305)-128", ALGO_LEN) == 0)
*key_len = 0;
int i;
for (i = 0; i < XFRM_ALGO_NR_KEYS; i++) {
if (strncmp(name, xfrm_key_entries[i].algo_name, ALGO_LEN) == 0)
*key_len = xfrm_key_entries[i].key_len;
}
if (*key_len > buf_len) {
printk("Can't pack a key - too big for buffer");
......
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