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

Commit c35fe410 authored by Steffen Klassert's avatar Steffen Klassert
Browse files

xfrm: Add mode handlers for IPsec on layer 2



This patch adds a gso_segment and xmit callback for the
xfrm_mode and implement these functions for tunnel and
transport mode.

Signed-off-by: default avatarSteffen Klassert <steffen.klassert@secunet.com>
parent 21f42cc9
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -444,6 +444,16 @@ struct xfrm_mode {
	 */
	int (*output)(struct xfrm_state *x, struct sk_buff *skb);

	/*
	 * Adjust pointers into the packet and do GSO segmentation.
	 */
	struct sk_buff *(*gso_segment)(struct xfrm_state *x, struct sk_buff *skb, netdev_features_t features);

	/*
	 * Adjust pointers into the packet when IPsec is done at layer2.
	 */
	void (*xmit)(struct xfrm_state *x, struct sk_buff *skb);

	struct xfrm_state_afinfo *afinfo;
	struct module *owner;
	unsigned int encap;
+32 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
#include <net/dst.h>
#include <net/ip.h>
#include <net/xfrm.h>
#include <net/protocol.h>

/* Add encapsulation header.
 *
@@ -56,9 +57,40 @@ static int xfrm4_transport_input(struct xfrm_state *x, struct sk_buff *skb)
	return 0;
}

static struct sk_buff *xfrm4_transport_gso_segment(struct xfrm_state *x,
						   struct sk_buff *skb,
						   netdev_features_t features)
{
	const struct net_offload *ops;
	struct sk_buff *segs = ERR_PTR(-EINVAL);
	struct xfrm_offload *xo = xfrm_offload(skb);

	skb->transport_header += x->props.header_len;
	ops = rcu_dereference(inet_offloads[xo->proto]);
	if (likely(ops && ops->callbacks.gso_segment))
		segs = ops->callbacks.gso_segment(skb, features);

	return segs;
}

static void xfrm4_transport_xmit(struct xfrm_state *x, struct sk_buff *skb)
{
	struct xfrm_offload *xo = xfrm_offload(skb);

	skb_reset_mac_len(skb);
	pskb_pull(skb, skb->mac_len + sizeof(struct iphdr) + x->props.header_len);

	if (xo->flags & XFRM_GSO_SEGMENT) {
		 skb_reset_transport_header(skb);
		 skb->transport_header -= x->props.header_len;
	}
}

static struct xfrm_mode xfrm4_transport_mode = {
	.input = xfrm4_transport_input,
	.output = xfrm4_transport_output,
	.gso_segment = xfrm4_transport_gso_segment,
	.xmit = xfrm4_transport_xmit,
	.owner = THIS_MODULE,
	.encap = XFRM_MODE_TRANSPORT,
};
+25 −0
Original line number Diff line number Diff line
@@ -96,11 +96,36 @@ static int xfrm4_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
	return err;
}

static struct sk_buff *xfrm4_mode_tunnel_gso_segment(struct xfrm_state *x,
						     struct sk_buff *skb,
						     netdev_features_t features)
{
	__skb_push(skb, skb->mac_len);
	return skb_mac_gso_segment(skb, features);

}

static void xfrm4_mode_tunnel_xmit(struct xfrm_state *x, struct sk_buff *skb)
{
	struct xfrm_offload *xo = xfrm_offload(skb);

	if (xo->flags & XFRM_GSO_SEGMENT) {
		skb->network_header = skb->network_header - x->props.header_len;
		skb->transport_header = skb->network_header +
					sizeof(struct iphdr);
	}

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

static struct xfrm_mode xfrm4_tunnel_mode = {
	.input2 = xfrm4_mode_tunnel_input,
	.input = xfrm_prepare_input,
	.output2 = xfrm4_mode_tunnel_output,
	.output = xfrm4_prepare_output,
	.gso_segment = xfrm4_mode_tunnel_gso_segment,
	.xmit = xfrm4_mode_tunnel_xmit,
	.owner = THIS_MODULE,
	.encap = XFRM_MODE_TUNNEL,
	.flags = XFRM_MODE_FLAG_TUNNEL,
+33 −0
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
#include <net/dst.h>
#include <net/ipv6.h>
#include <net/xfrm.h>
#include <net/protocol.h>

/* Add encapsulation header.
 *
@@ -61,9 +62,41 @@ static int xfrm6_transport_input(struct xfrm_state *x, struct sk_buff *skb)
	return 0;
}

static struct sk_buff *xfrm4_transport_gso_segment(struct xfrm_state *x,
						   struct sk_buff *skb,
						   netdev_features_t features)
{
	const struct net_offload *ops;
	struct sk_buff *segs = ERR_PTR(-EINVAL);
	struct xfrm_offload *xo = xfrm_offload(skb);

	skb->transport_header += x->props.header_len;
	ops = rcu_dereference(inet6_offloads[xo->proto]);
	if (likely(ops && ops->callbacks.gso_segment))
		segs = ops->callbacks.gso_segment(skb, features);

	return segs;
}

static void xfrm6_transport_xmit(struct xfrm_state *x, struct sk_buff *skb)
{
	struct xfrm_offload *xo = xfrm_offload(skb);

	skb_reset_mac_len(skb);
	pskb_pull(skb, skb->mac_len + sizeof(struct ipv6hdr) + x->props.header_len);

	if (xo->flags & XFRM_GSO_SEGMENT) {
		 skb_reset_transport_header(skb);
		 skb->transport_header -= x->props.header_len;
	}
}


static struct xfrm_mode xfrm6_transport_mode = {
	.input = xfrm6_transport_input,
	.output = xfrm6_transport_output,
	.gso_segment = xfrm4_transport_gso_segment,
	.xmit = xfrm6_transport_xmit,
	.owner = THIS_MODULE,
	.encap = XFRM_MODE_TRANSPORT,
};
+24 −0
Original line number Diff line number Diff line
@@ -96,11 +96,35 @@ static int xfrm6_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
	return err;
}

static struct sk_buff *xfrm6_mode_tunnel_gso_segment(struct xfrm_state *x,
						     struct sk_buff *skb,
						     netdev_features_t features)
{
	__skb_push(skb, skb->mac_len);
	return skb_mac_gso_segment(skb, features);

}

static void xfrm6_mode_tunnel_xmit(struct xfrm_state *x, struct sk_buff *skb)
{
	struct xfrm_offload *xo = xfrm_offload(skb);

	if (xo->flags & XFRM_GSO_SEGMENT) {
		skb->network_header = skb->network_header - x->props.header_len;
		skb->transport_header = skb->network_header + sizeof(struct ipv6hdr);
	}

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

static struct xfrm_mode xfrm6_tunnel_mode = {
	.input2 = xfrm6_mode_tunnel_input,
	.input = xfrm_prepare_input,
	.output2 = xfrm6_mode_tunnel_output,
	.output = xfrm6_prepare_output,
	.gso_segment = xfrm6_mode_tunnel_gso_segment,
	.xmit = xfrm6_mode_tunnel_xmit,
	.owner = THIS_MODULE,
	.encap = XFRM_MODE_TUNNEL,
	.flags = XFRM_MODE_FLAG_TUNNEL,