linux/net/xfrm/xfrm_device.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * xfrm_device.c - IPsec device offloading code.
   4 *
   5 * Copyright (c) 2015 secunet Security Networks AG
   6 *
   7 * Author:
   8 * Steffen Klassert <steffen.klassert@secunet.com>
   9 */
  10
  11#include <linux/errno.h>
  12#include <linux/module.h>
  13#include <linux/netdevice.h>
  14#include <linux/skbuff.h>
  15#include <linux/slab.h>
  16#include <linux/spinlock.h>
  17#include <net/dst.h>
  18#include <net/xfrm.h>
  19#include <linux/notifier.h>
  20
  21#ifdef CONFIG_XFRM_OFFLOAD
  22static void __xfrm_transport_prep(struct xfrm_state *x, struct sk_buff *skb,
  23                                  unsigned int hsize)
  24{
  25        struct xfrm_offload *xo = xfrm_offload(skb);
  26
  27        skb_reset_mac_len(skb);
  28        pskb_pull(skb, skb->mac_len + hsize + x->props.header_len);
  29
  30        if (xo->flags & XFRM_GSO_SEGMENT) {
  31                skb_reset_transport_header(skb);
  32                skb->transport_header -= x->props.header_len;
  33        }
  34}
  35
  36static void __xfrm_mode_tunnel_prep(struct xfrm_state *x, struct sk_buff *skb,
  37                                    unsigned int hsize)
  38
  39{
  40        struct xfrm_offload *xo = xfrm_offload(skb);
  41
  42        if (xo->flags & XFRM_GSO_SEGMENT)
  43                skb->transport_header = skb->network_header + hsize;
  44
  45        skb_reset_mac_len(skb);
  46        pskb_pull(skb, skb->mac_len + x->props.header_len);
  47}
  48
  49/* Adjust pointers into the packet when IPsec is done at layer2 */
  50static void xfrm_outer_mode_prep(struct xfrm_state *x, struct sk_buff *skb)
  51{
  52        switch (x->outer_mode.encap) {
  53        case XFRM_MODE_TUNNEL:
  54                if (x->outer_mode.family == AF_INET)
  55                        return __xfrm_mode_tunnel_prep(x, skb,
  56                                                       sizeof(struct iphdr));
  57                if (x->outer_mode.family == AF_INET6)
  58                        return __xfrm_mode_tunnel_prep(x, skb,
  59                                                       sizeof(struct ipv6hdr));
  60                break;
  61        case XFRM_MODE_TRANSPORT:
  62                if (x->outer_mode.family == AF_INET)
  63                        return __xfrm_transport_prep(x, skb,
  64                                                     sizeof(struct iphdr));
  65                if (x->outer_mode.family == AF_INET6)
  66                        return __xfrm_transport_prep(x, skb,
  67                                                     sizeof(struct ipv6hdr));
  68                break;
  69        case XFRM_MODE_ROUTEOPTIMIZATION:
  70        case XFRM_MODE_IN_TRIGGER:
  71        case XFRM_MODE_BEET:
  72                break;
  73        }
  74}
  75
  76struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t features, bool *again)
  77{
  78        int err;
  79        unsigned long flags;
  80        struct xfrm_state *x;
  81        struct softnet_data *sd;
  82        struct sk_buff *skb2, *nskb, *pskb = NULL;
  83        netdev_features_t esp_features = features;
  84        struct xfrm_offload *xo = xfrm_offload(skb);
  85        struct sec_path *sp;
  86
  87        if (!xo)
  88                return skb;
  89
  90        if (!(features & NETIF_F_HW_ESP))
  91                esp_features = features & ~(NETIF_F_SG | NETIF_F_CSUM_MASK);
  92
  93        sp = skb_sec_path(skb);
  94        x = sp->xvec[sp->len - 1];
  95        if (xo->flags & XFRM_GRO || x->xso.flags & XFRM_OFFLOAD_INBOUND)
  96                return skb;
  97
  98        local_irq_save(flags);
  99        sd = this_cpu_ptr(&softnet_data);
 100        err = !skb_queue_empty(&sd->xfrm_backlog);
 101        local_irq_restore(flags);
 102
 103        if (err) {
 104                *again = true;
 105                return skb;
 106        }
 107
 108        if (skb_is_gso(skb)) {
 109                struct net_device *dev = skb->dev;
 110
 111                if (unlikely(x->xso.dev != dev)) {
 112                        struct sk_buff *segs;
 113
 114                        /* Packet got rerouted, fixup features and segment it. */
 115                        esp_features = esp_features & ~(NETIF_F_HW_ESP
 116                                                        | NETIF_F_GSO_ESP);
 117
 118                        segs = skb_gso_segment(skb, esp_features);
 119                        if (IS_ERR(segs)) {
 120                                kfree_skb(skb);
 121                                atomic_long_inc(&dev->tx_dropped);
 122                                return NULL;
 123                        } else {
 124                                consume_skb(skb);
 125                                skb = segs;
 126                        }
 127                }
 128        }
 129
 130        if (!skb->next) {
 131                esp_features |= skb->dev->gso_partial_features;
 132                xfrm_outer_mode_prep(x, skb);
 133
 134                xo->flags |= XFRM_DEV_RESUME;
 135
 136                err = x->type_offload->xmit(x, skb, esp_features);
 137                if (err) {
 138                        if (err == -EINPROGRESS)
 139                                return NULL;
 140
 141                        XFRM_INC_STATS(xs_net(x), LINUX_MIB_XFRMOUTSTATEPROTOERROR);
 142                        kfree_skb(skb);
 143                        return NULL;
 144                }
 145
 146                skb_push(skb, skb->data - skb_mac_header(skb));
 147
 148                return skb;
 149        }
 150
 151        skb_list_walk_safe(skb, skb2, nskb) {
 152                esp_features |= skb->dev->gso_partial_features;
 153                skb_mark_not_on_list(skb2);
 154
 155                xo = xfrm_offload(skb2);
 156                xo->flags |= XFRM_DEV_RESUME;
 157
 158                xfrm_outer_mode_prep(x, skb2);
 159
 160                err = x->type_offload->xmit(x, skb2, esp_features);
 161                if (!err) {
 162                        skb2->next = nskb;
 163                } else if (err != -EINPROGRESS) {
 164                        XFRM_INC_STATS(xs_net(x), LINUX_MIB_XFRMOUTSTATEPROTOERROR);
 165                        skb2->next = nskb;
 166                        kfree_skb_list(skb2);
 167                        return NULL;
 168                } else {
 169                        if (skb == skb2)
 170                                skb = nskb;
 171                        else
 172                                pskb->next = nskb;
 173
 174                        continue;
 175                }
 176
 177                skb_push(skb2, skb2->data - skb_mac_header(skb2));
 178                pskb = skb2;
 179        }
 180
 181        return skb;
 182}
 183EXPORT_SYMBOL_GPL(validate_xmit_xfrm);
 184
 185int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
 186                       struct xfrm_user_offload *xuo)
 187{
 188        int err;
 189        struct dst_entry *dst;
 190        struct net_device *dev;
 191        struct xfrm_state_offload *xso = &x->xso;
 192        xfrm_address_t *saddr;
 193        xfrm_address_t *daddr;
 194
 195        if (!x->type_offload)
 196                return -EINVAL;
 197
 198        /* We don't yet support UDP encapsulation and TFC padding. */
 199        if (x->encap || x->tfcpad)
 200                return -EINVAL;
 201
 202        dev = dev_get_by_index(net, xuo->ifindex);
 203        if (!dev) {
 204                if (!(xuo->flags & XFRM_OFFLOAD_INBOUND)) {
 205                        saddr = &x->props.saddr;
 206                        daddr = &x->id.daddr;
 207                } else {
 208                        saddr = &x->id.daddr;
 209                        daddr = &x->props.saddr;
 210                }
 211
 212                dst = __xfrm_dst_lookup(net, 0, 0, saddr, daddr,
 213                                        x->props.family,
 214                                        xfrm_smark_get(0, x));
 215                if (IS_ERR(dst))
 216                        return 0;
 217
 218                dev = dst->dev;
 219
 220                dev_hold(dev);
 221                dst_release(dst);
 222        }
 223
 224        if (!dev->xfrmdev_ops || !dev->xfrmdev_ops->xdo_dev_state_add) {
 225                xso->dev = NULL;
 226                dev_put(dev);
 227                return 0;
 228        }
 229
 230        if (x->props.flags & XFRM_STATE_ESN &&
 231            !dev->xfrmdev_ops->xdo_dev_state_advance_esn) {
 232                xso->dev = NULL;
 233                dev_put(dev);
 234                return -EINVAL;
 235        }
 236
 237        xso->dev = dev;
 238        xso->num_exthdrs = 1;
 239        xso->flags = xuo->flags;
 240
 241        err = dev->xfrmdev_ops->xdo_dev_state_add(x);
 242        if (err) {
 243                xso->num_exthdrs = 0;
 244                xso->flags = 0;
 245                xso->dev = NULL;
 246                dev_put(dev);
 247
 248                if (err != -EOPNOTSUPP)
 249                        return err;
 250        }
 251
 252        return 0;
 253}
 254EXPORT_SYMBOL_GPL(xfrm_dev_state_add);
 255
 256bool xfrm_dev_offload_ok(struct sk_buff *skb, struct xfrm_state *x)
 257{
 258        int mtu;
 259        struct dst_entry *dst = skb_dst(skb);
 260        struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
 261        struct net_device *dev = x->xso.dev;
 262
 263        if (!x->type_offload || x->encap)
 264                return false;
 265
 266        if ((!dev || (dev == xfrm_dst_path(dst)->dev)) &&
 267            (!xdst->child->xfrm)) {
 268                mtu = xfrm_state_mtu(x, xdst->child_mtu_cached);
 269                if (skb->len <= mtu)
 270                        goto ok;
 271
 272                if (skb_is_gso(skb) && skb_gso_validate_network_len(skb, mtu))
 273                        goto ok;
 274        }
 275
 276        return false;
 277
 278ok:
 279        if (dev && dev->xfrmdev_ops && dev->xfrmdev_ops->xdo_dev_offload_ok)
 280                return x->xso.dev->xfrmdev_ops->xdo_dev_offload_ok(skb, x);
 281
 282        return true;
 283}
 284EXPORT_SYMBOL_GPL(xfrm_dev_offload_ok);
 285
 286void xfrm_dev_resume(struct sk_buff *skb)
 287{
 288        struct net_device *dev = skb->dev;
 289        int ret = NETDEV_TX_BUSY;
 290        struct netdev_queue *txq;
 291        struct softnet_data *sd;
 292        unsigned long flags;
 293
 294        rcu_read_lock();
 295        txq = netdev_core_pick_tx(dev, skb, NULL);
 296
 297        HARD_TX_LOCK(dev, txq, smp_processor_id());
 298        if (!netif_xmit_frozen_or_stopped(txq))
 299                skb = dev_hard_start_xmit(skb, dev, txq, &ret);
 300        HARD_TX_UNLOCK(dev, txq);
 301
 302        if (!dev_xmit_complete(ret)) {
 303                local_irq_save(flags);
 304                sd = this_cpu_ptr(&softnet_data);
 305                skb_queue_tail(&sd->xfrm_backlog, skb);
 306                raise_softirq_irqoff(NET_TX_SOFTIRQ);
 307                local_irq_restore(flags);
 308        }
 309        rcu_read_unlock();
 310}
 311EXPORT_SYMBOL_GPL(xfrm_dev_resume);
 312
 313void xfrm_dev_backlog(struct softnet_data *sd)
 314{
 315        struct sk_buff_head *xfrm_backlog = &sd->xfrm_backlog;
 316        struct sk_buff_head list;
 317        struct sk_buff *skb;
 318
 319        if (skb_queue_empty(xfrm_backlog))
 320                return;
 321
 322        __skb_queue_head_init(&list);
 323
 324        spin_lock(&xfrm_backlog->lock);
 325        skb_queue_splice_init(xfrm_backlog, &list);
 326        spin_unlock(&xfrm_backlog->lock);
 327
 328        while (!skb_queue_empty(&list)) {
 329                skb = __skb_dequeue(&list);
 330                xfrm_dev_resume(skb);
 331        }
 332
 333}
 334#endif
 335
 336static int xfrm_api_check(struct net_device *dev)
 337{
 338#ifdef CONFIG_XFRM_OFFLOAD
 339        if ((dev->features & NETIF_F_HW_ESP_TX_CSUM) &&
 340            !(dev->features & NETIF_F_HW_ESP))
 341                return NOTIFY_BAD;
 342
 343        if ((dev->features & NETIF_F_HW_ESP) &&
 344            (!(dev->xfrmdev_ops &&
 345               dev->xfrmdev_ops->xdo_dev_state_add &&
 346               dev->xfrmdev_ops->xdo_dev_state_delete)))
 347                return NOTIFY_BAD;
 348#else
 349        if (dev->features & (NETIF_F_HW_ESP | NETIF_F_HW_ESP_TX_CSUM))
 350                return NOTIFY_BAD;
 351#endif
 352
 353        return NOTIFY_DONE;
 354}
 355
 356static int xfrm_dev_register(struct net_device *dev)
 357{
 358        return xfrm_api_check(dev);
 359}
 360
 361static int xfrm_dev_feat_change(struct net_device *dev)
 362{
 363        return xfrm_api_check(dev);
 364}
 365
 366static int xfrm_dev_down(struct net_device *dev)
 367{
 368        if (dev->features & NETIF_F_HW_ESP)
 369                xfrm_dev_state_flush(dev_net(dev), dev, true);
 370
 371        return NOTIFY_DONE;
 372}
 373
 374static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
 375{
 376        struct net_device *dev = netdev_notifier_info_to_dev(ptr);
 377
 378        switch (event) {
 379        case NETDEV_REGISTER:
 380                return xfrm_dev_register(dev);
 381
 382        case NETDEV_FEAT_CHANGE:
 383                return xfrm_dev_feat_change(dev);
 384
 385        case NETDEV_DOWN:
 386        case NETDEV_UNREGISTER:
 387                return xfrm_dev_down(dev);
 388        }
 389        return NOTIFY_DONE;
 390}
 391
 392static struct notifier_block xfrm_dev_notifier = {
 393        .notifier_call  = xfrm_dev_event,
 394};
 395
 396void __init xfrm_dev_init(void)
 397{
 398        register_netdevice_notifier(&xfrm_dev_notifier);
 399}
 400