Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 13c1d189 authored by Arnaud Ebalard's avatar Arnaud Ebalard Committed by David S. Miller
Browse files

xfrm: MIGRATE enhancements (draft-ebalard-mext-pfkey-enhanced-migrate)



Provides implementation of the enhancements of XFRM/PF_KEY MIGRATE mechanism
specified in draft-ebalard-mext-pfkey-enhanced-migrate-00. Defines associated
PF_KEY SADB_X_EXT_KMADDRESS extension and XFRM/netlink XFRMA_KMADDRESS
attribute.

Signed-off-by: default avatarArnaud Ebalard <arno@natisbad.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 95430c0b
Loading
Loading
Loading
Loading
+12 −1
Original line number Diff line number Diff line
@@ -226,6 +226,15 @@ struct sadb_x_sec_ctx {
} __attribute__((packed));
/* sizeof(struct sadb_sec_ctx) = 8 */

/* Used by MIGRATE to pass addresses IKE will use to perform
 * negotiation with the peer */
struct sadb_x_kmaddress {
	uint16_t	sadb_x_kmaddress_len;
	uint16_t	sadb_x_kmaddress_exttype;
	uint32_t	sadb_x_kmaddress_reserved;
} __attribute__((packed));
/* sizeof(struct sadb_x_kmaddress) == 8 */

/* Message types */
#define SADB_RESERVED		0
#define SADB_GETSPI		1
@@ -346,7 +355,9 @@ struct sadb_x_sec_ctx {
#define SADB_X_EXT_NAT_T_DPORT		22
#define SADB_X_EXT_NAT_T_OA		23
#define SADB_X_EXT_SEC_CTX		24
#define SADB_EXT_MAX			24
/* Used with MIGRATE to pass @ to IKE for negotiation */
#define SADB_X_EXT_KMADDRESS		25
#define SADB_EXT_MAX			25

/* Identity Extension values */
#define SADB_IDENTTYPE_RESERVED	0
+10 −0
Original line number Diff line number Diff line
@@ -279,6 +279,7 @@ enum xfrm_attr_type_t {
	XFRMA_POLICY_TYPE,	/* struct xfrm_userpolicy_type */
	XFRMA_MIGRATE,
	XFRMA_ALG_AEAD,		/* struct xfrm_algo_aead */
	XFRMA_KMADDRESS,        /* struct xfrm_user_kmaddress */
	__XFRMA_MAX

#define XFRMA_MAX (__XFRMA_MAX - 1)
@@ -415,6 +416,15 @@ struct xfrm_user_report {
	struct xfrm_selector		sel;
};

/* Used by MIGRATE to pass addresses IKE should use to perform
 * SA negotiation with the peer */
struct xfrm_user_kmaddress {
	xfrm_address_t                  local;
	xfrm_address_t                  remote;
	__u32				reserved;
	__u16				family;
};

struct xfrm_user_migrate {
	xfrm_address_t			old_daddr;
	xfrm_address_t			old_saddr;
+12 −3
Original line number Diff line number Diff line
@@ -492,6 +492,13 @@ struct xfrm_policy
	struct xfrm_tmpl       	xfrm_vec[XFRM_MAX_DEPTH];
};

struct xfrm_kmaddress {
	xfrm_address_t          local;
	xfrm_address_t          remote;
	u32			reserved;
	u16			family;
};

struct xfrm_migrate {
	xfrm_address_t		old_daddr;
	xfrm_address_t		old_saddr;
@@ -531,7 +538,7 @@ struct xfrm_mgr
	int			(*new_mapping)(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport);
	int			(*notify_policy)(struct xfrm_policy *x, int dir, struct km_event *c);
	int			(*report)(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr);
	int			(*migrate)(struct xfrm_selector *sel, u8 dir, u8 type, struct xfrm_migrate *m, int num_bundles);
	int			(*migrate)(struct xfrm_selector *sel, u8 dir, u8 type, struct xfrm_migrate *m, int num_bundles, struct xfrm_kmaddress *k);
};

extern int xfrm_register_km(struct xfrm_mgr *km);
@@ -1432,12 +1439,14 @@ extern int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *xdst,

#ifdef CONFIG_XFRM_MIGRATE
extern int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
		      struct xfrm_migrate *m, int num_bundles);
		      struct xfrm_migrate *m, int num_bundles,
		      struct xfrm_kmaddress *k);
extern struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m);
extern struct xfrm_state * xfrm_state_migrate(struct xfrm_state *x,
					      struct xfrm_migrate *m);
extern int xfrm_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
			struct xfrm_migrate *m, int num_bundles);
			struct xfrm_migrate *m, int num_bundles,
			struct xfrm_kmaddress *k);
#endif

extern wait_queue_head_t km_waitq;
+69 −17
Original line number Diff line number Diff line
@@ -398,6 +398,7 @@ static u8 sadb_ext_min_len[] = {
	[SADB_X_EXT_NAT_T_DPORT]	= (u8) sizeof(struct sadb_x_nat_t_port),
	[SADB_X_EXT_NAT_T_OA]		= (u8) sizeof(struct sadb_address),
	[SADB_X_EXT_SEC_CTX]		= (u8) sizeof(struct sadb_x_sec_ctx),
	[SADB_X_EXT_KMADDRESS]		= (u8) sizeof(struct sadb_x_kmaddress),
};

/* Verify sadb_address_{len,prefixlen} against sa_family.  */
@@ -2384,24 +2385,21 @@ static int pfkey_sockaddr_pair_size(sa_family_t family)
	return PFKEY_ALIGN8(pfkey_sockaddr_len(family) * 2);
}

static int parse_sockaddr_pair(struct sadb_x_ipsecrequest *rq,
static int parse_sockaddr_pair(struct sockaddr *sa, int ext_len,
			       xfrm_address_t *saddr, xfrm_address_t *daddr,
			       u16 *family)
{
	u8 *sa = (u8 *) (rq + 1);
	int af, socklen;

	if (rq->sadb_x_ipsecrequest_len <
	    pfkey_sockaddr_pair_size(((struct sockaddr *)sa)->sa_family))
	if (ext_len < pfkey_sockaddr_pair_size(sa->sa_family))
		return -EINVAL;

	af = pfkey_sockaddr_extract((struct sockaddr *) sa,
				    saddr);
	af = pfkey_sockaddr_extract(sa, saddr);
	if (!af)
		return -EINVAL;

	socklen = pfkey_sockaddr_len(af);
	if (pfkey_sockaddr_extract((struct sockaddr *) (sa + socklen),
	if (pfkey_sockaddr_extract((struct sockaddr *) (((u8 *)sa) + socklen),
				   daddr) != af)
		return -EINVAL;

@@ -2421,7 +2419,9 @@ static int ipsecrequests_to_migrate(struct sadb_x_ipsecrequest *rq1, int len,
		return -EINVAL;

	/* old endoints */
	err = parse_sockaddr_pair(rq1, &m->old_saddr, &m->old_daddr,
	err = parse_sockaddr_pair((struct sockaddr *)(rq1 + 1),
				  rq1->sadb_x_ipsecrequest_len,
				  &m->old_saddr, &m->old_daddr,
				  &m->old_family);
	if (err)
		return err;
@@ -2434,7 +2434,9 @@ static int ipsecrequests_to_migrate(struct sadb_x_ipsecrequest *rq1, int len,
		return -EINVAL;

	/* new endpoints */
	err = parse_sockaddr_pair(rq2, &m->new_saddr, &m->new_daddr,
	err = parse_sockaddr_pair((struct sockaddr *)(rq2 + 1),
				  rq2->sadb_x_ipsecrequest_len,
				  &m->new_saddr, &m->new_daddr,
				  &m->new_family);
	if (err)
		return err;
@@ -2460,10 +2462,12 @@ static int pfkey_migrate(struct sock *sk, struct sk_buff *skb,
	int i, len, ret, err = -EINVAL;
	u8 dir;
	struct sadb_address *sa;
	struct sadb_x_kmaddress *kma;
	struct sadb_x_policy *pol;
	struct sadb_x_ipsecrequest *rq;
	struct xfrm_selector sel;
	struct xfrm_migrate m[XFRM_MAX_DEPTH];
	struct xfrm_kmaddress k;

	if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC - 1],
				     ext_hdrs[SADB_EXT_ADDRESS_DST - 1]) ||
@@ -2472,16 +2476,25 @@ static int pfkey_migrate(struct sock *sk, struct sk_buff *skb,
		goto out;
	}

	kma = ext_hdrs[SADB_X_EXT_KMADDRESS - 1];
	pol = ext_hdrs[SADB_X_EXT_POLICY - 1];
	if (!pol) {

	if (pol->sadb_x_policy_dir >= IPSEC_DIR_MAX) {
		err = -EINVAL;
		goto out;
	}

	if (pol->sadb_x_policy_dir >= IPSEC_DIR_MAX) {
		err = -EINVAL;
	if (kma) {
		/* convert sadb_x_kmaddress to xfrm_kmaddress */
		k.reserved = kma->sadb_x_kmaddress_reserved;
		ret = parse_sockaddr_pair((struct sockaddr *)(kma + 1),
					  8*(kma->sadb_x_kmaddress_len) - sizeof(*kma),
					  &k.local, &k.remote, &k.family);
		if (ret < 0) {
			err = ret;
			goto out;
		}
	}

	dir = pol->sadb_x_policy_dir - 1;
	memset(&sel, 0, sizeof(sel));
@@ -2527,7 +2540,8 @@ static int pfkey_migrate(struct sock *sk, struct sk_buff *skb,
		goto out;
	}

	return xfrm_migrate(&sel, dir, XFRM_POLICY_TYPE_MAIN, m, i);
	return xfrm_migrate(&sel, dir, XFRM_POLICY_TYPE_MAIN, m, i,
			    kma ? &k : NULL);

 out:
	return err;
@@ -3319,6 +3333,32 @@ static int set_sadb_address(struct sk_buff *skb, int sasize, int type,
	return 0;
}


static int set_sadb_kmaddress(struct sk_buff *skb, struct xfrm_kmaddress *k)
{
	struct sadb_x_kmaddress *kma;
	u8 *sa;
	int family = k->family;
	int socklen = pfkey_sockaddr_len(family);
	int size_req;

	size_req = (sizeof(struct sadb_x_kmaddress) +
		    pfkey_sockaddr_pair_size(family));

	kma = (struct sadb_x_kmaddress *)skb_put(skb, size_req);
	memset(kma, 0, size_req);
	kma->sadb_x_kmaddress_len = size_req / 8;
	kma->sadb_x_kmaddress_exttype = SADB_X_EXT_KMADDRESS;
	kma->sadb_x_kmaddress_reserved = k->reserved;

	sa = (u8 *)(kma + 1);
	if (!pfkey_sockaddr_fill(&k->local, 0, (struct sockaddr *)sa, family) ||
	    !pfkey_sockaddr_fill(&k->remote, 0, (struct sockaddr *)(sa+socklen), family))
		return -EINVAL;

	return 0;
}

static int set_ipsecrequest(struct sk_buff *skb,
			    uint8_t proto, uint8_t mode, int level,
			    uint32_t reqid, uint8_t family,
@@ -3351,7 +3391,8 @@ static int set_ipsecrequest(struct sk_buff *skb,

#ifdef CONFIG_NET_KEY_MIGRATE
static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
			      struct xfrm_migrate *m, int num_bundles)
			      struct xfrm_migrate *m, int num_bundles,
			      struct xfrm_kmaddress *k)
{
	int i;
	int sasize_sel;
@@ -3368,6 +3409,12 @@ static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
	if (num_bundles <= 0 || num_bundles > XFRM_MAX_DEPTH)
		return -EINVAL;

	if (k != NULL) {
		/* addresses for KM */
		size += PFKEY_ALIGN8(sizeof(struct sadb_x_kmaddress) +
				     pfkey_sockaddr_pair_size(k->family));
	}

	/* selector */
	sasize_sel = pfkey_sockaddr_size(sel->family);
	if (!sasize_sel)
@@ -3404,6 +3451,10 @@ static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
	hdr->sadb_msg_seq = 0;
	hdr->sadb_msg_pid = 0;

	/* Addresses to be used by KM for negotiation, if ext is available */
	if (k != NULL && (set_sadb_kmaddress(skb, k) < 0))
		return -EINVAL;

	/* selector src */
	set_sadb_address(skb, sasize_sel, SADB_EXT_ADDRESS_SRC, sel);

@@ -3449,7 +3500,8 @@ static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
}
#else
static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
			      struct xfrm_migrate *m, int num_bundles)
			      struct xfrm_migrate *m, int num_bundles,
			      struct xfrm_kmaddress *k)
{
	return -ENOPROTOOPT;
}
+3 −2
Original line number Diff line number Diff line
@@ -2679,7 +2679,8 @@ static int xfrm_migrate_check(struct xfrm_migrate *m, int num_migrate)
}

int xfrm_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
		 struct xfrm_migrate *m, int num_migrate)
		 struct xfrm_migrate *m, int num_migrate,
		 struct xfrm_kmaddress *k)
{
	int i, err, nx_cur = 0, nx_new = 0;
	struct xfrm_policy *pol = NULL;
@@ -2723,7 +2724,7 @@ int xfrm_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
	}

	/* Stage 5 - announce */
	km_migrate(sel, dir, type, m, num_migrate);
	km_migrate(sel, dir, type, m, num_migrate, k);

	xfrm_pol_put(pol);

Loading