Commit 7ac64f45 authored by Christian Hopps's avatar Christian Hopps Committed by Steffen Klassert
Browse files

xfrm: add mode_cbs module functionality



Add a set of callbacks xfrm_mode_cbs to xfrm_state. These callbacks
enable the addition of new xfrm modes, such as IP-TFS to be defined
in modules.

Signed-off-by: default avatarChristian Hopps <chopps@labn.net>
Tested-by: default avatarAntony Antony <antony.antony@secunet.com>
Signed-off-by: default avatarSteffen Klassert <steffen.klassert@secunet.com>
parent f69eb4f6
Loading
Loading
Loading
Loading
+43 −0
Original line number Diff line number Diff line
@@ -213,6 +213,7 @@ struct xfrm_state {
		u16		family;
		xfrm_address_t	saddr;
		int		header_len;
		int		enc_hdr_len;
		int		trailer_len;
		u32		extra_flags;
		struct xfrm_mark	smark;
@@ -303,6 +304,9 @@ struct xfrm_state {
	 * interpreted by xfrm_type methods. */
	void			*data;
	u8			dir;

	const struct xfrm_mode_cbs	*mode_cbs;
	void				*mode_data;
};

static inline struct net *xs_net(struct xfrm_state *x)
@@ -460,6 +464,45 @@ struct xfrm_type_offload {
int xfrm_register_type_offload(const struct xfrm_type_offload *type, unsigned short family);
void xfrm_unregister_type_offload(const struct xfrm_type_offload *type, unsigned short family);

/**
 * struct xfrm_mode_cbs - XFRM mode callbacks
 * @owner: module owner or NULL
 * @init_state: Add/init mode specific state in `xfrm_state *x`
 * @clone_state: Copy mode specific values from `orig` to new state `x`
 * @destroy_state: Cleanup mode specific state from `xfrm_state *x`
 * @user_init: Process mode specific netlink attributes from user
 * @copy_to_user: Add netlink attributes to `attrs` based on state in `x`
 * @sa_len: Return space required to store mode specific netlink attributes
 * @get_inner_mtu: Return avail payload space after removing encap overhead
 * @input: Process received packet from SA using mode
 * @output: Output given packet using mode
 * @prepare_output: Add mode specific encapsulation to packet in skb. On return
 *	`transport_header` should point at ESP header, `network_header` should
 *	point at outer IP header and `mac_header` should opint at the
 *	protocol/nexthdr field of the outer IP.
 *
 * One should examine and understand the specific uses of these callbacks in
 * xfrm for further detail on how and when these functions are called. RTSL.
 */
struct xfrm_mode_cbs {
	struct module	*owner;
	int	(*init_state)(struct xfrm_state *x);
	int	(*clone_state)(struct xfrm_state *x, struct xfrm_state *orig);
	void	(*destroy_state)(struct xfrm_state *x);
	int	(*user_init)(struct net *net, struct xfrm_state *x,
			     struct nlattr **attrs,
			     struct netlink_ext_ack *extack);
	int	(*copy_to_user)(struct xfrm_state *x, struct sk_buff *skb);
	unsigned int (*sa_len)(const struct xfrm_state *x);
	u32	(*get_inner_mtu)(struct xfrm_state *x, int outer_mtu);
	int	(*input)(struct xfrm_state *x, struct sk_buff *skb);
	int	(*output)(struct net *net, struct sock *sk, struct sk_buff *skb);
	int	(*prepare_output)(struct xfrm_state *x, struct sk_buff *skb);
};

int xfrm_register_mode_cbs(u8 mode, const struct xfrm_mode_cbs *mode_cbs);
void xfrm_unregister_mode_cbs(u8 mode);

static inline int xfrm_af2proto(unsigned int family)
{
	switch(family) {
+2 −1
Original line number Diff line number Diff line
@@ -42,7 +42,8 @@ static void __xfrm_mode_tunnel_prep(struct xfrm_state *x, struct sk_buff *skb,
		skb->transport_header = skb->network_header + hsize;

	skb_reset_mac_len(skb);
	pskb_pull(skb, skb->mac_len + x->props.header_len);
	pskb_pull(skb,
		  skb->mac_len + x->props.header_len - x->props.enc_hdr_len);
}

static void __xfrm_mode_beet_prep(struct xfrm_state *x, struct sk_buff *skb,
+16 −2
Original line number Diff line number Diff line
@@ -446,6 +446,9 @@ static int xfrm_inner_mode_input(struct xfrm_state *x,
		WARN_ON_ONCE(1);
		break;
	default:
		if (x->mode_cbs && x->mode_cbs->input)
			return x->mode_cbs->input(x, skb);

		WARN_ON_ONCE(1);
		break;
	}
@@ -453,6 +456,10 @@ static int xfrm_inner_mode_input(struct xfrm_state *x,
	return -EOPNOTSUPP;
}

/* NOTE: encap_type - In addition to the normal (non-negative) values for
 * encap_type, a negative value of -1 or -2 can be used to resume/restart this
 * function after a previous invocation early terminated for async operation.
 */
int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
{
	const struct xfrm_state_afinfo *afinfo;
@@ -489,6 +496,10 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)

		family = x->props.family;

		/* An encap_type of -2 indicates reconstructed inner packet */
		if (encap_type == -2)
			goto resume_decapped;

		/* An encap_type of -1 indicates async resumption. */
		if (encap_type == -1) {
			async = 1;
@@ -679,11 +690,14 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)

		XFRM_MODE_SKB_CB(skb)->protocol = nexthdr;

		if (xfrm_inner_mode_input(x, skb)) {
		err = xfrm_inner_mode_input(x, skb);
		if (err == -EINPROGRESS)
			return 0;
		else if (err) {
			XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR);
			goto drop;
		}

resume_decapped:
		if (x->outer_mode.flags & XFRM_MODE_FLAG_TUNNEL) {
			decaps = 1;
			break;
+2 −0
Original line number Diff line number Diff line
@@ -472,6 +472,8 @@ static int xfrm_outer_mode_output(struct xfrm_state *x, struct sk_buff *skb)
		WARN_ON_ONCE(1);
		break;
	default:
		if (x->mode_cbs && x->mode_cbs->prepare_output)
			return x->mode_cbs->prepare_output(x, skb);
		WARN_ON_ONCE(1);
		break;
	}
+11 −7
Original line number Diff line number Diff line
@@ -2748,6 +2748,9 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,

		dst1->input = dst_discard;

		if (xfrm[i]->mode_cbs && xfrm[i]->mode_cbs->output) {
			dst1->output = xfrm[i]->mode_cbs->output;
		} else {
			rcu_read_lock();
			afinfo = xfrm_state_afinfo_get_rcu(inner_mode->family);
			if (likely(afinfo))
@@ -2755,6 +2758,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
			else
				dst1->output = dst_discard_out;
			rcu_read_unlock();
		}

		xdst_prev = xdst;

Loading