@@ -153,7 +153,8 @@ static int nsim_ipsec_add_sa(struct xfrm_state *xs,
return -EINVAL;
}
- if (xs->xso.type != XFRM_DEV_OFFLOAD_CRYPTO) {
+ if (xs->xso.type != XFRM_DEV_OFFLOAD_CRYPTO &&
+ xs->xso.type != XFRM_DEV_OFFLOAD_PACKET) {
NL_SET_ERR_MSG_MOD(extack, "Unsupported ipsec offload type");
return -EINVAL;
}
@@ -169,6 +170,7 @@ static int nsim_ipsec_add_sa(struct xfrm_state *xs,
memset(&sa, 0, sizeof(sa));
sa.used = true;
sa.xs = xs;
+ sa.if_id = xs->if_id;
if (sa.xs->id.proto & IPPROTO_ESP)
sa.crypt = xs->ealg || xs->aead;
@@ -227,10 +229,24 @@ static bool nsim_ipsec_offload_ok(struct sk_buff *skb, struct xfrm_state *xs)
return true;
}
+static int nsim_ipsec_add_policy(struct xfrm_policy *policy,
+ struct netlink_ext_ack *extack)
+{
+ return 0;
+}
+
+static void nsim_ipsec_del_policy(struct xfrm_policy *policy)
+{
+}
+
static const struct xfrmdev_ops nsim_xfrmdev_ops = {
.xdo_dev_state_add = nsim_ipsec_add_sa,
.xdo_dev_state_delete = nsim_ipsec_del_sa,
.xdo_dev_offload_ok = nsim_ipsec_offload_ok,
+
+ .xdo_dev_policy_add = nsim_ipsec_add_policy,
+ .xdo_dev_policy_delete = nsim_ipsec_del_policy,
+
};
bool nsim_ipsec_tx(struct netdevsim *ns, struct sk_buff *skb)
@@ -240,6 +256,7 @@ bool nsim_ipsec_tx(struct netdevsim *ns, struct sk_buff *skb)
struct xfrm_state *xs;
struct nsim_sa *tsa;
u32 sa_idx;
+ struct xfrm_offload *xo;
/* do we even need to check this packet? */
if (!sp)
@@ -275,6 +292,19 @@ bool nsim_ipsec_tx(struct netdevsim *ns, struct sk_buff *skb)
return false;
}
+ if (xs->if_id) {
+ if (xs->if_id != tsa->if_id) {
+ netdev_err(ns->netdev, "unmatched if_id %d %d\n",
+ xs->if_id, tsa->if_id);
+ return false;
+ }
+ xo = xfrm_offload(skb);
+ if (!xo || !(xo->flags & XFRM_XMIT)) {
+ netdev_err(ns->netdev, "offload flag missing or wrong\n");
+ return false;
+ }
+ }
+
ipsec->tx++;
return true;
@@ -41,6 +41,7 @@ struct nsim_sa {
__be32 ipaddr[4];
u32 key[4];
u32 salt;
+ u32 if_id;
bool used;
bool crypt;
bool rx;
@@ -706,6 +706,8 @@ int xfrm_output(struct sock *sk, struct sk_buff *skb)
struct xfrm_state *x = skb_dst(skb)->xfrm;
int family;
int err;
+ struct xfrm_offload *xo;
+ struct sec_path *sp;
family = (x->xso.type != XFRM_DEV_OFFLOAD_PACKET) ? x->outer_mode.family
: skb_dst(skb)->ops->family;
@@ -728,7 +730,27 @@ int xfrm_output(struct sock *sk, struct sk_buff *skb)
kfree_skb(skb);
return -EHOSTUNREACH;
}
+ if (x->if_id) {
+ sp = secpath_set(skb);
+ if (!sp) {
+ XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
+ kfree_skb(skb);
+ return -ENOMEM;
+ }
+
+ sp->olen++;
+ sp->xvec[sp->len++] = x;
+ xfrm_state_hold(x);
+ xo = xfrm_offload(skb);
+ if (!xo) {
+ secpath_reset(skb);
+ XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
+ kfree_skb(skb);
+ return -EINVAL;
+ }
+ xo->flags |= XFRM_XMIT;
+ }
return xfrm_output_resume(sk, skb, 0);
}