forked from Minki/linux
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:0a28bfd497
("net/macsec: Add MACsec skb_metadata_dst Tx Data path support") from the net-next tree and commit:5182a5d48c
("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: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
42e8e6d906
@ -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,17 +1114,16 @@ 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);
|
||||
@ -1132,7 +1138,7 @@ error:
|
||||
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 @@ out:
|
||||
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,17 +130,20 @@ 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;
|
||||
|
@ -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,17 +1157,16 @@ 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);
|
||||
@ -1175,7 +1181,7 @@ error:
|
||||
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 @@ out:
|
||||
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,17 +149,20 @@ 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;
|
||||
|
@ -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,8 +285,10 @@ 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,7 +720,8 @@ resume:
|
||||
sp = skb_sec_path(skb);
|
||||
if (sp)
|
||||
sp->olen = 0;
|
||||
skb_dst_drop(skb);
|
||||
if (skb_valid_dst(skb))
|
||||
skb_dst_drop(skb);
|
||||
gro_cells_receive(&gro_cells, skb);
|
||||
return 0;
|
||||
} else {
|
||||
@ -737,7 +739,8 @@ resume:
|
||||
sp = skb_sec_path(skb);
|
||||
if (sp)
|
||||
sp->olen = 0;
|
||||
skb_dst_drop(skb);
|
||||
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;
|
||||
|
||||
return netdev_priv(dev);
|
||||
xi = netdev_priv(dev);
|
||||
res->net = xi->net;
|
||||
|
||||
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,7 +254,10 @@ static int xfrmi_create(struct net_device *dev)
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
xfrmi_link(xfrmn, xi);
|
||||
if (xi->p.collect_md)
|
||||
rcu_assign_pointer(xfrmn->collect_md_xfrmi, xi);
|
||||
else
|
||||
xfrmi_link(xfrmn, xi);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -185,7 +285,10 @@ 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);
|
||||
|
||||
xfrmi_unlink(xfrmn, xi);
|
||||
if (xi->p.collect_md)
|
||||
RCU_INIT_POINTER(xfrmn->collect_md_xfrmi, NULL);
|
||||
else
|
||||
xfrmi_unlink(xfrmn, xi);
|
||||
}
|
||||
|
||||
static void xfrmi_scrub_packet(struct sk_buff *skb, bool xnet)
|
||||
@ -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,14 +777,27 @@ static int xfrmi_newlink(struct net *src_net, struct net_device *dev,
|
||||
int err;
|
||||
|
||||
xfrmi_netlink_parms(data, &p);
|
||||
if (!p.if_id) {
|
||||
NL_SET_ERR_MSG(extack, "if_id must be non zero");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (p.collect_md) {
|
||||
struct xfrmi_net *xfrmn = net_generic(net, xfrmi_net_id);
|
||||
|
||||
xi = xfrmi_locate(net, &p);
|
||||
if (xi)
|
||||
return -EEXIST;
|
||||
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;
|
||||
}
|
||||
|
||||
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_LINK] = { .type = NLA_U32 },
|
||||
[IFLA_XFRM_IF_ID] = { .type = NLA_U32 },
|
||||
[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 @@ pernet_dev_failed:
|
||||
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;
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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");
|
||||
|
Loading…
Reference in New Issue
Block a user