Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* Copyright(c) 2018 Oracle and/or its affiliates. All rights reserved. */
0003 
0004 #include <crypto/aead.h>
0005 #include <linux/debugfs.h>
0006 #include <net/xfrm.h>
0007 
0008 #include "netdevsim.h"
0009 
0010 #define NSIM_IPSEC_AUTH_BITS    128
0011 
0012 static ssize_t nsim_dbg_netdev_ops_read(struct file *filp,
0013                     char __user *buffer,
0014                     size_t count, loff_t *ppos)
0015 {
0016     struct netdevsim *ns = filp->private_data;
0017     struct nsim_ipsec *ipsec = &ns->ipsec;
0018     size_t bufsize;
0019     char *buf, *p;
0020     int len;
0021     int i;
0022 
0023     /* the buffer needed is
0024      * (num SAs * 3 lines each * ~60 bytes per line) + one more line
0025      */
0026     bufsize = (ipsec->count * 4 * 60) + 60;
0027     buf = kzalloc(bufsize, GFP_KERNEL);
0028     if (!buf)
0029         return -ENOMEM;
0030 
0031     p = buf;
0032     p += scnprintf(p, bufsize - (p - buf),
0033                "SA count=%u tx=%u\n",
0034                ipsec->count, ipsec->tx);
0035 
0036     for (i = 0; i < NSIM_IPSEC_MAX_SA_COUNT; i++) {
0037         struct nsim_sa *sap = &ipsec->sa[i];
0038 
0039         if (!sap->used)
0040             continue;
0041 
0042         p += scnprintf(p, bufsize - (p - buf),
0043                    "sa[%i] %cx ipaddr=0x%08x %08x %08x %08x\n",
0044                    i, (sap->rx ? 'r' : 't'), sap->ipaddr[0],
0045                    sap->ipaddr[1], sap->ipaddr[2], sap->ipaddr[3]);
0046         p += scnprintf(p, bufsize - (p - buf),
0047                    "sa[%i]    spi=0x%08x proto=0x%x salt=0x%08x crypt=%d\n",
0048                    i, be32_to_cpu(sap->xs->id.spi),
0049                    sap->xs->id.proto, sap->salt, sap->crypt);
0050         p += scnprintf(p, bufsize - (p - buf),
0051                    "sa[%i]    key=0x%08x %08x %08x %08x\n",
0052                    i, sap->key[0], sap->key[1],
0053                    sap->key[2], sap->key[3]);
0054     }
0055 
0056     len = simple_read_from_buffer(buffer, count, ppos, buf, p - buf);
0057 
0058     kfree(buf);
0059     return len;
0060 }
0061 
0062 static const struct file_operations ipsec_dbg_fops = {
0063     .owner = THIS_MODULE,
0064     .open = simple_open,
0065     .read = nsim_dbg_netdev_ops_read,
0066 };
0067 
0068 static int nsim_ipsec_find_empty_idx(struct nsim_ipsec *ipsec)
0069 {
0070     u32 i;
0071 
0072     if (ipsec->count == NSIM_IPSEC_MAX_SA_COUNT)
0073         return -ENOSPC;
0074 
0075     /* search sa table */
0076     for (i = 0; i < NSIM_IPSEC_MAX_SA_COUNT; i++) {
0077         if (!ipsec->sa[i].used)
0078             return i;
0079     }
0080 
0081     return -ENOSPC;
0082 }
0083 
0084 static int nsim_ipsec_parse_proto_keys(struct xfrm_state *xs,
0085                        u32 *mykey, u32 *mysalt)
0086 {
0087     const char aes_gcm_name[] = "rfc4106(gcm(aes))";
0088     struct net_device *dev = xs->xso.real_dev;
0089     unsigned char *key_data;
0090     char *alg_name = NULL;
0091     int key_len;
0092 
0093     if (!xs->aead) {
0094         netdev_err(dev, "Unsupported IPsec algorithm\n");
0095         return -EINVAL;
0096     }
0097 
0098     if (xs->aead->alg_icv_len != NSIM_IPSEC_AUTH_BITS) {
0099         netdev_err(dev, "IPsec offload requires %d bit authentication\n",
0100                NSIM_IPSEC_AUTH_BITS);
0101         return -EINVAL;
0102     }
0103 
0104     key_data = &xs->aead->alg_key[0];
0105     key_len = xs->aead->alg_key_len;
0106     alg_name = xs->aead->alg_name;
0107 
0108     if (strcmp(alg_name, aes_gcm_name)) {
0109         netdev_err(dev, "Unsupported IPsec algorithm - please use %s\n",
0110                aes_gcm_name);
0111         return -EINVAL;
0112     }
0113 
0114     /* 160 accounts for 16 byte key and 4 byte salt */
0115     if (key_len > NSIM_IPSEC_AUTH_BITS) {
0116         *mysalt = ((u32 *)key_data)[4];
0117     } else if (key_len == NSIM_IPSEC_AUTH_BITS) {
0118         *mysalt = 0;
0119     } else {
0120         netdev_err(dev, "IPsec hw offload only supports 128 bit keys with optional 32 bit salt\n");
0121         return -EINVAL;
0122     }
0123     memcpy(mykey, key_data, 16);
0124 
0125     return 0;
0126 }
0127 
0128 static int nsim_ipsec_add_sa(struct xfrm_state *xs)
0129 {
0130     struct nsim_ipsec *ipsec;
0131     struct net_device *dev;
0132     struct netdevsim *ns;
0133     struct nsim_sa sa;
0134     u16 sa_idx;
0135     int ret;
0136 
0137     dev = xs->xso.real_dev;
0138     ns = netdev_priv(dev);
0139     ipsec = &ns->ipsec;
0140 
0141     if (xs->id.proto != IPPROTO_ESP && xs->id.proto != IPPROTO_AH) {
0142         netdev_err(dev, "Unsupported protocol 0x%04x for ipsec offload\n",
0143                xs->id.proto);
0144         return -EINVAL;
0145     }
0146 
0147     if (xs->calg) {
0148         netdev_err(dev, "Compression offload not supported\n");
0149         return -EINVAL;
0150     }
0151 
0152     /* find the first unused index */
0153     ret = nsim_ipsec_find_empty_idx(ipsec);
0154     if (ret < 0) {
0155         netdev_err(dev, "No space for SA in Rx table!\n");
0156         return ret;
0157     }
0158     sa_idx = (u16)ret;
0159 
0160     memset(&sa, 0, sizeof(sa));
0161     sa.used = true;
0162     sa.xs = xs;
0163 
0164     if (sa.xs->id.proto & IPPROTO_ESP)
0165         sa.crypt = xs->ealg || xs->aead;
0166 
0167     /* get the key and salt */
0168     ret = nsim_ipsec_parse_proto_keys(xs, sa.key, &sa.salt);
0169     if (ret) {
0170         netdev_err(dev, "Failed to get key data for SA table\n");
0171         return ret;
0172     }
0173 
0174     if (xs->xso.dir == XFRM_DEV_OFFLOAD_IN) {
0175         sa.rx = true;
0176 
0177         if (xs->props.family == AF_INET6)
0178             memcpy(sa.ipaddr, &xs->id.daddr.a6, 16);
0179         else
0180             memcpy(&sa.ipaddr[3], &xs->id.daddr.a4, 4);
0181     }
0182 
0183     /* the preparations worked, so save the info */
0184     memcpy(&ipsec->sa[sa_idx], &sa, sizeof(sa));
0185 
0186     /* the XFRM stack doesn't like offload_handle == 0,
0187      * so add a bitflag in case our array index is 0
0188      */
0189     xs->xso.offload_handle = sa_idx | NSIM_IPSEC_VALID;
0190     ipsec->count++;
0191 
0192     return 0;
0193 }
0194 
0195 static void nsim_ipsec_del_sa(struct xfrm_state *xs)
0196 {
0197     struct netdevsim *ns = netdev_priv(xs->xso.real_dev);
0198     struct nsim_ipsec *ipsec = &ns->ipsec;
0199     u16 sa_idx;
0200 
0201     sa_idx = xs->xso.offload_handle & ~NSIM_IPSEC_VALID;
0202     if (!ipsec->sa[sa_idx].used) {
0203         netdev_err(ns->netdev, "Invalid SA for delete sa_idx=%d\n",
0204                sa_idx);
0205         return;
0206     }
0207 
0208     memset(&ipsec->sa[sa_idx], 0, sizeof(struct nsim_sa));
0209     ipsec->count--;
0210 }
0211 
0212 static bool nsim_ipsec_offload_ok(struct sk_buff *skb, struct xfrm_state *xs)
0213 {
0214     struct netdevsim *ns = netdev_priv(xs->xso.real_dev);
0215     struct nsim_ipsec *ipsec = &ns->ipsec;
0216 
0217     ipsec->ok++;
0218 
0219     return true;
0220 }
0221 
0222 static const struct xfrmdev_ops nsim_xfrmdev_ops = {
0223     .xdo_dev_state_add  = nsim_ipsec_add_sa,
0224     .xdo_dev_state_delete   = nsim_ipsec_del_sa,
0225     .xdo_dev_offload_ok = nsim_ipsec_offload_ok,
0226 };
0227 
0228 bool nsim_ipsec_tx(struct netdevsim *ns, struct sk_buff *skb)
0229 {
0230     struct sec_path *sp = skb_sec_path(skb);
0231     struct nsim_ipsec *ipsec = &ns->ipsec;
0232     struct xfrm_state *xs;
0233     struct nsim_sa *tsa;
0234     u32 sa_idx;
0235 
0236     /* do we even need to check this packet? */
0237     if (!sp)
0238         return true;
0239 
0240     if (unlikely(!sp->len)) {
0241         netdev_err(ns->netdev, "no xfrm state len = %d\n",
0242                sp->len);
0243         return false;
0244     }
0245 
0246     xs = xfrm_input_state(skb);
0247     if (unlikely(!xs)) {
0248         netdev_err(ns->netdev, "no xfrm_input_state() xs = %p\n", xs);
0249         return false;
0250     }
0251 
0252     sa_idx = xs->xso.offload_handle & ~NSIM_IPSEC_VALID;
0253     if (unlikely(sa_idx >= NSIM_IPSEC_MAX_SA_COUNT)) {
0254         netdev_err(ns->netdev, "bad sa_idx=%d max=%d\n",
0255                sa_idx, NSIM_IPSEC_MAX_SA_COUNT);
0256         return false;
0257     }
0258 
0259     tsa = &ipsec->sa[sa_idx];
0260     if (unlikely(!tsa->used)) {
0261         netdev_err(ns->netdev, "unused sa_idx=%d\n", sa_idx);
0262         return false;
0263     }
0264 
0265     if (xs->id.proto != IPPROTO_ESP && xs->id.proto != IPPROTO_AH) {
0266         netdev_err(ns->netdev, "unexpected proto=%d\n", xs->id.proto);
0267         return false;
0268     }
0269 
0270     ipsec->tx++;
0271 
0272     return true;
0273 }
0274 
0275 void nsim_ipsec_init(struct netdevsim *ns)
0276 {
0277     ns->netdev->xfrmdev_ops = &nsim_xfrmdev_ops;
0278 
0279 #define NSIM_ESP_FEATURES   (NETIF_F_HW_ESP | \
0280                  NETIF_F_HW_ESP_TX_CSUM | \
0281                  NETIF_F_GSO_ESP)
0282 
0283     ns->netdev->features |= NSIM_ESP_FEATURES;
0284     ns->netdev->hw_enc_features |= NSIM_ESP_FEATURES;
0285 
0286     ns->ipsec.pfile = debugfs_create_file("ipsec", 0400,
0287                           ns->nsim_dev_port->ddir, ns,
0288                           &ipsec_dbg_fops);
0289 }
0290 
0291 void nsim_ipsec_teardown(struct netdevsim *ns)
0292 {
0293     struct nsim_ipsec *ipsec = &ns->ipsec;
0294 
0295     if (ipsec->count)
0296         netdev_err(ns->netdev, "tearing down IPsec offload with %d SAs left\n",
0297                ipsec->count);
0298     debugfs_remove_recursive(ipsec->pfile);
0299 }