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