xref: /OK3568_Linux_fs/kernel/drivers/net/netdevsim/ipsec.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /* Copyright(c) 2018 Oracle and/or its affiliates. All rights reserved. */
3*4882a593Smuzhiyun 
4*4882a593Smuzhiyun #include <crypto/aead.h>
5*4882a593Smuzhiyun #include <linux/debugfs.h>
6*4882a593Smuzhiyun #include <net/xfrm.h>
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include "netdevsim.h"
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #define NSIM_IPSEC_AUTH_BITS	128
11*4882a593Smuzhiyun 
nsim_dbg_netdev_ops_read(struct file * filp,char __user * buffer,size_t count,loff_t * ppos)12*4882a593Smuzhiyun static ssize_t nsim_dbg_netdev_ops_read(struct file *filp,
13*4882a593Smuzhiyun 					char __user *buffer,
14*4882a593Smuzhiyun 					size_t count, loff_t *ppos)
15*4882a593Smuzhiyun {
16*4882a593Smuzhiyun 	struct netdevsim *ns = filp->private_data;
17*4882a593Smuzhiyun 	struct nsim_ipsec *ipsec = &ns->ipsec;
18*4882a593Smuzhiyun 	size_t bufsize;
19*4882a593Smuzhiyun 	char *buf, *p;
20*4882a593Smuzhiyun 	int len;
21*4882a593Smuzhiyun 	int i;
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun 	/* the buffer needed is
24*4882a593Smuzhiyun 	 * (num SAs * 3 lines each * ~60 bytes per line) + one more line
25*4882a593Smuzhiyun 	 */
26*4882a593Smuzhiyun 	bufsize = (ipsec->count * 4 * 60) + 60;
27*4882a593Smuzhiyun 	buf = kzalloc(bufsize, GFP_KERNEL);
28*4882a593Smuzhiyun 	if (!buf)
29*4882a593Smuzhiyun 		return -ENOMEM;
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun 	p = buf;
32*4882a593Smuzhiyun 	p += scnprintf(p, bufsize - (p - buf),
33*4882a593Smuzhiyun 		       "SA count=%u tx=%u\n",
34*4882a593Smuzhiyun 		       ipsec->count, ipsec->tx);
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun 	for (i = 0; i < NSIM_IPSEC_MAX_SA_COUNT; i++) {
37*4882a593Smuzhiyun 		struct nsim_sa *sap = &ipsec->sa[i];
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun 		if (!sap->used)
40*4882a593Smuzhiyun 			continue;
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun 		p += scnprintf(p, bufsize - (p - buf),
43*4882a593Smuzhiyun 			       "sa[%i] %cx ipaddr=0x%08x %08x %08x %08x\n",
44*4882a593Smuzhiyun 			       i, (sap->rx ? 'r' : 't'), sap->ipaddr[0],
45*4882a593Smuzhiyun 			       sap->ipaddr[1], sap->ipaddr[2], sap->ipaddr[3]);
46*4882a593Smuzhiyun 		p += scnprintf(p, bufsize - (p - buf),
47*4882a593Smuzhiyun 			       "sa[%i]    spi=0x%08x proto=0x%x salt=0x%08x crypt=%d\n",
48*4882a593Smuzhiyun 			       i, be32_to_cpu(sap->xs->id.spi),
49*4882a593Smuzhiyun 			       sap->xs->id.proto, sap->salt, sap->crypt);
50*4882a593Smuzhiyun 		p += scnprintf(p, bufsize - (p - buf),
51*4882a593Smuzhiyun 			       "sa[%i]    key=0x%08x %08x %08x %08x\n",
52*4882a593Smuzhiyun 			       i, sap->key[0], sap->key[1],
53*4882a593Smuzhiyun 			       sap->key[2], sap->key[3]);
54*4882a593Smuzhiyun 	}
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun 	len = simple_read_from_buffer(buffer, count, ppos, buf, p - buf);
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	kfree(buf);
59*4882a593Smuzhiyun 	return len;
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun static const struct file_operations ipsec_dbg_fops = {
63*4882a593Smuzhiyun 	.owner = THIS_MODULE,
64*4882a593Smuzhiyun 	.open = simple_open,
65*4882a593Smuzhiyun 	.read = nsim_dbg_netdev_ops_read,
66*4882a593Smuzhiyun };
67*4882a593Smuzhiyun 
nsim_ipsec_find_empty_idx(struct nsim_ipsec * ipsec)68*4882a593Smuzhiyun static int nsim_ipsec_find_empty_idx(struct nsim_ipsec *ipsec)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun 	u32 i;
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun 	if (ipsec->count == NSIM_IPSEC_MAX_SA_COUNT)
73*4882a593Smuzhiyun 		return -ENOSPC;
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun 	/* search sa table */
76*4882a593Smuzhiyun 	for (i = 0; i < NSIM_IPSEC_MAX_SA_COUNT; i++) {
77*4882a593Smuzhiyun 		if (!ipsec->sa[i].used)
78*4882a593Smuzhiyun 			return i;
79*4882a593Smuzhiyun 	}
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	return -ENOSPC;
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun 
nsim_ipsec_parse_proto_keys(struct xfrm_state * xs,u32 * mykey,u32 * mysalt)84*4882a593Smuzhiyun static int nsim_ipsec_parse_proto_keys(struct xfrm_state *xs,
85*4882a593Smuzhiyun 				       u32 *mykey, u32 *mysalt)
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun 	const char aes_gcm_name[] = "rfc4106(gcm(aes))";
88*4882a593Smuzhiyun 	struct net_device *dev = xs->xso.real_dev;
89*4882a593Smuzhiyun 	unsigned char *key_data;
90*4882a593Smuzhiyun 	char *alg_name = NULL;
91*4882a593Smuzhiyun 	int key_len;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	if (!xs->aead) {
94*4882a593Smuzhiyun 		netdev_err(dev, "Unsupported IPsec algorithm\n");
95*4882a593Smuzhiyun 		return -EINVAL;
96*4882a593Smuzhiyun 	}
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	if (xs->aead->alg_icv_len != NSIM_IPSEC_AUTH_BITS) {
99*4882a593Smuzhiyun 		netdev_err(dev, "IPsec offload requires %d bit authentication\n",
100*4882a593Smuzhiyun 			   NSIM_IPSEC_AUTH_BITS);
101*4882a593Smuzhiyun 		return -EINVAL;
102*4882a593Smuzhiyun 	}
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 	key_data = &xs->aead->alg_key[0];
105*4882a593Smuzhiyun 	key_len = xs->aead->alg_key_len;
106*4882a593Smuzhiyun 	alg_name = xs->aead->alg_name;
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 	if (strcmp(alg_name, aes_gcm_name)) {
109*4882a593Smuzhiyun 		netdev_err(dev, "Unsupported IPsec algorithm - please use %s\n",
110*4882a593Smuzhiyun 			   aes_gcm_name);
111*4882a593Smuzhiyun 		return -EINVAL;
112*4882a593Smuzhiyun 	}
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	/* 160 accounts for 16 byte key and 4 byte salt */
115*4882a593Smuzhiyun 	if (key_len > NSIM_IPSEC_AUTH_BITS) {
116*4882a593Smuzhiyun 		*mysalt = ((u32 *)key_data)[4];
117*4882a593Smuzhiyun 	} else if (key_len == NSIM_IPSEC_AUTH_BITS) {
118*4882a593Smuzhiyun 		*mysalt = 0;
119*4882a593Smuzhiyun 	} else {
120*4882a593Smuzhiyun 		netdev_err(dev, "IPsec hw offload only supports 128 bit keys with optional 32 bit salt\n");
121*4882a593Smuzhiyun 		return -EINVAL;
122*4882a593Smuzhiyun 	}
123*4882a593Smuzhiyun 	memcpy(mykey, key_data, 16);
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	return 0;
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun 
nsim_ipsec_add_sa(struct xfrm_state * xs)128*4882a593Smuzhiyun static int nsim_ipsec_add_sa(struct xfrm_state *xs)
129*4882a593Smuzhiyun {
130*4882a593Smuzhiyun 	struct nsim_ipsec *ipsec;
131*4882a593Smuzhiyun 	struct net_device *dev;
132*4882a593Smuzhiyun 	struct netdevsim *ns;
133*4882a593Smuzhiyun 	struct nsim_sa sa;
134*4882a593Smuzhiyun 	u16 sa_idx;
135*4882a593Smuzhiyun 	int ret;
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun 	dev = xs->xso.real_dev;
138*4882a593Smuzhiyun 	ns = netdev_priv(dev);
139*4882a593Smuzhiyun 	ipsec = &ns->ipsec;
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	if (xs->id.proto != IPPROTO_ESP && xs->id.proto != IPPROTO_AH) {
142*4882a593Smuzhiyun 		netdev_err(dev, "Unsupported protocol 0x%04x for ipsec offload\n",
143*4882a593Smuzhiyun 			   xs->id.proto);
144*4882a593Smuzhiyun 		return -EINVAL;
145*4882a593Smuzhiyun 	}
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	if (xs->calg) {
148*4882a593Smuzhiyun 		netdev_err(dev, "Compression offload not supported\n");
149*4882a593Smuzhiyun 		return -EINVAL;
150*4882a593Smuzhiyun 	}
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	/* find the first unused index */
153*4882a593Smuzhiyun 	ret = nsim_ipsec_find_empty_idx(ipsec);
154*4882a593Smuzhiyun 	if (ret < 0) {
155*4882a593Smuzhiyun 		netdev_err(dev, "No space for SA in Rx table!\n");
156*4882a593Smuzhiyun 		return ret;
157*4882a593Smuzhiyun 	}
158*4882a593Smuzhiyun 	sa_idx = (u16)ret;
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	memset(&sa, 0, sizeof(sa));
161*4882a593Smuzhiyun 	sa.used = true;
162*4882a593Smuzhiyun 	sa.xs = xs;
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	if (sa.xs->id.proto & IPPROTO_ESP)
165*4882a593Smuzhiyun 		sa.crypt = xs->ealg || xs->aead;
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	/* get the key and salt */
168*4882a593Smuzhiyun 	ret = nsim_ipsec_parse_proto_keys(xs, sa.key, &sa.salt);
169*4882a593Smuzhiyun 	if (ret) {
170*4882a593Smuzhiyun 		netdev_err(dev, "Failed to get key data for SA table\n");
171*4882a593Smuzhiyun 		return ret;
172*4882a593Smuzhiyun 	}
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	if (xs->xso.flags & XFRM_OFFLOAD_INBOUND) {
175*4882a593Smuzhiyun 		sa.rx = true;
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 		if (xs->props.family == AF_INET6)
178*4882a593Smuzhiyun 			memcpy(sa.ipaddr, &xs->id.daddr.a6, 16);
179*4882a593Smuzhiyun 		else
180*4882a593Smuzhiyun 			memcpy(&sa.ipaddr[3], &xs->id.daddr.a4, 4);
181*4882a593Smuzhiyun 	}
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 	/* the preparations worked, so save the info */
184*4882a593Smuzhiyun 	memcpy(&ipsec->sa[sa_idx], &sa, sizeof(sa));
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	/* the XFRM stack doesn't like offload_handle == 0,
187*4882a593Smuzhiyun 	 * so add a bitflag in case our array index is 0
188*4882a593Smuzhiyun 	 */
189*4882a593Smuzhiyun 	xs->xso.offload_handle = sa_idx | NSIM_IPSEC_VALID;
190*4882a593Smuzhiyun 	ipsec->count++;
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	return 0;
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun 
nsim_ipsec_del_sa(struct xfrm_state * xs)195*4882a593Smuzhiyun static void nsim_ipsec_del_sa(struct xfrm_state *xs)
196*4882a593Smuzhiyun {
197*4882a593Smuzhiyun 	struct netdevsim *ns = netdev_priv(xs->xso.real_dev);
198*4882a593Smuzhiyun 	struct nsim_ipsec *ipsec = &ns->ipsec;
199*4882a593Smuzhiyun 	u16 sa_idx;
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	sa_idx = xs->xso.offload_handle & ~NSIM_IPSEC_VALID;
202*4882a593Smuzhiyun 	if (!ipsec->sa[sa_idx].used) {
203*4882a593Smuzhiyun 		netdev_err(ns->netdev, "Invalid SA for delete sa_idx=%d\n",
204*4882a593Smuzhiyun 			   sa_idx);
205*4882a593Smuzhiyun 		return;
206*4882a593Smuzhiyun 	}
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	memset(&ipsec->sa[sa_idx], 0, sizeof(struct nsim_sa));
209*4882a593Smuzhiyun 	ipsec->count--;
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun 
nsim_ipsec_offload_ok(struct sk_buff * skb,struct xfrm_state * xs)212*4882a593Smuzhiyun static bool nsim_ipsec_offload_ok(struct sk_buff *skb, struct xfrm_state *xs)
213*4882a593Smuzhiyun {
214*4882a593Smuzhiyun 	struct netdevsim *ns = netdev_priv(xs->xso.real_dev);
215*4882a593Smuzhiyun 	struct nsim_ipsec *ipsec = &ns->ipsec;
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 	ipsec->ok++;
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 	return true;
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun static const struct xfrmdev_ops nsim_xfrmdev_ops = {
223*4882a593Smuzhiyun 	.xdo_dev_state_add	= nsim_ipsec_add_sa,
224*4882a593Smuzhiyun 	.xdo_dev_state_delete	= nsim_ipsec_del_sa,
225*4882a593Smuzhiyun 	.xdo_dev_offload_ok	= nsim_ipsec_offload_ok,
226*4882a593Smuzhiyun };
227*4882a593Smuzhiyun 
nsim_ipsec_tx(struct netdevsim * ns,struct sk_buff * skb)228*4882a593Smuzhiyun bool nsim_ipsec_tx(struct netdevsim *ns, struct sk_buff *skb)
229*4882a593Smuzhiyun {
230*4882a593Smuzhiyun 	struct sec_path *sp = skb_sec_path(skb);
231*4882a593Smuzhiyun 	struct nsim_ipsec *ipsec = &ns->ipsec;
232*4882a593Smuzhiyun 	struct xfrm_state *xs;
233*4882a593Smuzhiyun 	struct nsim_sa *tsa;
234*4882a593Smuzhiyun 	u32 sa_idx;
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	/* do we even need to check this packet? */
237*4882a593Smuzhiyun 	if (!sp)
238*4882a593Smuzhiyun 		return true;
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun 	if (unlikely(!sp->len)) {
241*4882a593Smuzhiyun 		netdev_err(ns->netdev, "no xfrm state len = %d\n",
242*4882a593Smuzhiyun 			   sp->len);
243*4882a593Smuzhiyun 		return false;
244*4882a593Smuzhiyun 	}
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	xs = xfrm_input_state(skb);
247*4882a593Smuzhiyun 	if (unlikely(!xs)) {
248*4882a593Smuzhiyun 		netdev_err(ns->netdev, "no xfrm_input_state() xs = %p\n", xs);
249*4882a593Smuzhiyun 		return false;
250*4882a593Smuzhiyun 	}
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	sa_idx = xs->xso.offload_handle & ~NSIM_IPSEC_VALID;
253*4882a593Smuzhiyun 	if (unlikely(sa_idx >= NSIM_IPSEC_MAX_SA_COUNT)) {
254*4882a593Smuzhiyun 		netdev_err(ns->netdev, "bad sa_idx=%d max=%d\n",
255*4882a593Smuzhiyun 			   sa_idx, NSIM_IPSEC_MAX_SA_COUNT);
256*4882a593Smuzhiyun 		return false;
257*4882a593Smuzhiyun 	}
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	tsa = &ipsec->sa[sa_idx];
260*4882a593Smuzhiyun 	if (unlikely(!tsa->used)) {
261*4882a593Smuzhiyun 		netdev_err(ns->netdev, "unused sa_idx=%d\n", sa_idx);
262*4882a593Smuzhiyun 		return false;
263*4882a593Smuzhiyun 	}
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	if (xs->id.proto != IPPROTO_ESP && xs->id.proto != IPPROTO_AH) {
266*4882a593Smuzhiyun 		netdev_err(ns->netdev, "unexpected proto=%d\n", xs->id.proto);
267*4882a593Smuzhiyun 		return false;
268*4882a593Smuzhiyun 	}
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	ipsec->tx++;
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 	return true;
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun 
nsim_ipsec_init(struct netdevsim * ns)275*4882a593Smuzhiyun void nsim_ipsec_init(struct netdevsim *ns)
276*4882a593Smuzhiyun {
277*4882a593Smuzhiyun 	ns->netdev->xfrmdev_ops = &nsim_xfrmdev_ops;
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun #define NSIM_ESP_FEATURES	(NETIF_F_HW_ESP | \
280*4882a593Smuzhiyun 				 NETIF_F_HW_ESP_TX_CSUM | \
281*4882a593Smuzhiyun 				 NETIF_F_GSO_ESP)
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	ns->netdev->features |= NSIM_ESP_FEATURES;
284*4882a593Smuzhiyun 	ns->netdev->hw_enc_features |= NSIM_ESP_FEATURES;
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	ns->ipsec.pfile = debugfs_create_file("ipsec", 0400,
287*4882a593Smuzhiyun 					      ns->nsim_dev_port->ddir, ns,
288*4882a593Smuzhiyun 					      &ipsec_dbg_fops);
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun 
nsim_ipsec_teardown(struct netdevsim * ns)291*4882a593Smuzhiyun void nsim_ipsec_teardown(struct netdevsim *ns)
292*4882a593Smuzhiyun {
293*4882a593Smuzhiyun 	struct nsim_ipsec *ipsec = &ns->ipsec;
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	if (ipsec->count)
296*4882a593Smuzhiyun 		netdev_err(ns->netdev, "tearing down IPsec offload with %d SAs left\n",
297*4882a593Smuzhiyun 			   ipsec->count);
298*4882a593Smuzhiyun 	debugfs_remove_recursive(ipsec->pfile);
299*4882a593Smuzhiyun }
300