root/drivers/net/netdevsim/ipsec.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nsim_dbg_netdev_ops_read
  2. nsim_ipsec_find_empty_idx
  3. nsim_ipsec_parse_proto_keys
  4. nsim_ipsec_add_sa
  5. nsim_ipsec_del_sa
  6. nsim_ipsec_offload_ok
  7. nsim_ipsec_tx
  8. nsim_ipsec_init
  9. nsim_ipsec_teardown

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

/* [<][>][^][v][top][bottom][index][help] */