121f42cc9SSteffen Klassert /* 221f42cc9SSteffen Klassert * xfrm_device.c - IPsec device offloading code. 321f42cc9SSteffen Klassert * 421f42cc9SSteffen Klassert * Copyright (c) 2015 secunet Security Networks AG 521f42cc9SSteffen Klassert * 621f42cc9SSteffen Klassert * Author: 721f42cc9SSteffen Klassert * Steffen Klassert <steffen.klassert@secunet.com> 821f42cc9SSteffen Klassert * 921f42cc9SSteffen Klassert * This program is free software; you can redistribute it and/or 1021f42cc9SSteffen Klassert * modify it under the terms of the GNU General Public License 1121f42cc9SSteffen Klassert * as published by the Free Software Foundation; either version 1221f42cc9SSteffen Klassert * 2 of the License, or (at your option) any later version. 1321f42cc9SSteffen Klassert */ 1421f42cc9SSteffen Klassert 1521f42cc9SSteffen Klassert #include <linux/errno.h> 1621f42cc9SSteffen Klassert #include <linux/module.h> 1721f42cc9SSteffen Klassert #include <linux/netdevice.h> 1821f42cc9SSteffen Klassert #include <linux/skbuff.h> 1921f42cc9SSteffen Klassert #include <linux/slab.h> 2021f42cc9SSteffen Klassert #include <linux/spinlock.h> 2121f42cc9SSteffen Klassert #include <net/dst.h> 2221f42cc9SSteffen Klassert #include <net/xfrm.h> 2321f42cc9SSteffen Klassert #include <linux/notifier.h> 2421f42cc9SSteffen Klassert 25f6e27114SSteffen Klassert int validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t features) 26f6e27114SSteffen Klassert { 27f6e27114SSteffen Klassert int err; 28f6e27114SSteffen Klassert struct xfrm_state *x; 29f6e27114SSteffen Klassert struct xfrm_offload *xo = xfrm_offload(skb); 30f6e27114SSteffen Klassert 31f6e27114SSteffen Klassert if (skb_is_gso(skb)) 32f6e27114SSteffen Klassert return 0; 33f6e27114SSteffen Klassert 34f6e27114SSteffen Klassert if (xo) { 35f6e27114SSteffen Klassert x = skb->sp->xvec[skb->sp->len - 1]; 36f6e27114SSteffen Klassert if (xo->flags & XFRM_GRO || x->xso.flags & XFRM_OFFLOAD_INBOUND) 37f6e27114SSteffen Klassert return 0; 38f6e27114SSteffen Klassert 39f6e27114SSteffen Klassert x->outer_mode->xmit(x, skb); 40f6e27114SSteffen Klassert 41f6e27114SSteffen Klassert err = x->type_offload->xmit(x, skb, features); 42f6e27114SSteffen Klassert if (err) { 43f6e27114SSteffen Klassert XFRM_INC_STATS(xs_net(x), LINUX_MIB_XFRMOUTSTATEPROTOERROR); 44f6e27114SSteffen Klassert return err; 45f6e27114SSteffen Klassert } 46f6e27114SSteffen Klassert 47f6e27114SSteffen Klassert skb_push(skb, skb->data - skb_mac_header(skb)); 48f6e27114SSteffen Klassert } 49f6e27114SSteffen Klassert 50f6e27114SSteffen Klassert return 0; 51f6e27114SSteffen Klassert } 52f6e27114SSteffen Klassert EXPORT_SYMBOL_GPL(validate_xmit_xfrm); 53f6e27114SSteffen Klassert 54d77e38e6SSteffen Klassert int xfrm_dev_state_add(struct net *net, struct xfrm_state *x, 55d77e38e6SSteffen Klassert struct xfrm_user_offload *xuo) 56d77e38e6SSteffen Klassert { 57d77e38e6SSteffen Klassert int err; 58d77e38e6SSteffen Klassert struct dst_entry *dst; 59d77e38e6SSteffen Klassert struct net_device *dev; 60d77e38e6SSteffen Klassert struct xfrm_state_offload *xso = &x->xso; 61d77e38e6SSteffen Klassert xfrm_address_t *saddr; 62d77e38e6SSteffen Klassert xfrm_address_t *daddr; 63d77e38e6SSteffen Klassert 64d77e38e6SSteffen Klassert if (!x->type_offload) 65d77e38e6SSteffen Klassert return 0; 66d77e38e6SSteffen Klassert 67d77e38e6SSteffen Klassert /* We don't yet support UDP encapsulation, TFC padding and ESN. */ 68d77e38e6SSteffen Klassert if (x->encap || x->tfcpad || (x->props.flags & XFRM_STATE_ESN)) 69d77e38e6SSteffen Klassert return 0; 70d77e38e6SSteffen Klassert 71d77e38e6SSteffen Klassert dev = dev_get_by_index(net, xuo->ifindex); 72d77e38e6SSteffen Klassert if (!dev) { 73d77e38e6SSteffen Klassert if (!(xuo->flags & XFRM_OFFLOAD_INBOUND)) { 74d77e38e6SSteffen Klassert saddr = &x->props.saddr; 75d77e38e6SSteffen Klassert daddr = &x->id.daddr; 76d77e38e6SSteffen Klassert } else { 77d77e38e6SSteffen Klassert saddr = &x->id.daddr; 78d77e38e6SSteffen Klassert daddr = &x->props.saddr; 79d77e38e6SSteffen Klassert } 80d77e38e6SSteffen Klassert 81d77e38e6SSteffen Klassert dst = __xfrm_dst_lookup(net, 0, 0, saddr, daddr, x->props.family); 82d77e38e6SSteffen Klassert if (IS_ERR(dst)) 83d77e38e6SSteffen Klassert return 0; 84d77e38e6SSteffen Klassert 85d77e38e6SSteffen Klassert dev = dst->dev; 86d77e38e6SSteffen Klassert 87d77e38e6SSteffen Klassert dev_hold(dev); 88d77e38e6SSteffen Klassert dst_release(dst); 89d77e38e6SSteffen Klassert } 90d77e38e6SSteffen Klassert 91d77e38e6SSteffen Klassert if (!dev->xfrmdev_ops || !dev->xfrmdev_ops->xdo_dev_state_add) { 92d77e38e6SSteffen Klassert dev_put(dev); 93d77e38e6SSteffen Klassert return 0; 94d77e38e6SSteffen Klassert } 95d77e38e6SSteffen Klassert 96d77e38e6SSteffen Klassert xso->dev = dev; 97d77e38e6SSteffen Klassert xso->num_exthdrs = 1; 98d77e38e6SSteffen Klassert xso->flags = xuo->flags; 99d77e38e6SSteffen Klassert 100d77e38e6SSteffen Klassert err = dev->xfrmdev_ops->xdo_dev_state_add(x); 101d77e38e6SSteffen Klassert if (err) { 102d77e38e6SSteffen Klassert dev_put(dev); 103d77e38e6SSteffen Klassert return err; 104d77e38e6SSteffen Klassert } 105d77e38e6SSteffen Klassert 106d77e38e6SSteffen Klassert return 0; 107d77e38e6SSteffen Klassert } 108d77e38e6SSteffen Klassert EXPORT_SYMBOL_GPL(xfrm_dev_state_add); 109d77e38e6SSteffen Klassert 110d77e38e6SSteffen Klassert bool xfrm_dev_offload_ok(struct sk_buff *skb, struct xfrm_state *x) 111d77e38e6SSteffen Klassert { 112d77e38e6SSteffen Klassert int mtu; 113d77e38e6SSteffen Klassert struct dst_entry *dst = skb_dst(skb); 114d77e38e6SSteffen Klassert struct xfrm_dst *xdst = (struct xfrm_dst *)dst; 115d77e38e6SSteffen Klassert struct net_device *dev = x->xso.dev; 116d77e38e6SSteffen Klassert 117d77e38e6SSteffen Klassert if (!x->type_offload || x->encap) 118d77e38e6SSteffen Klassert return false; 119d77e38e6SSteffen Klassert 120d77e38e6SSteffen Klassert if ((x->xso.offload_handle && (dev == dst->path->dev)) && 121d77e38e6SSteffen Klassert !dst->child->xfrm && x->type->get_mtu) { 122d77e38e6SSteffen Klassert mtu = x->type->get_mtu(x, xdst->child_mtu_cached); 123d77e38e6SSteffen Klassert 124d77e38e6SSteffen Klassert if (skb->len <= mtu) 125d77e38e6SSteffen Klassert goto ok; 126d77e38e6SSteffen Klassert 127d77e38e6SSteffen Klassert if (skb_is_gso(skb) && skb_gso_validate_mtu(skb, mtu)) 128d77e38e6SSteffen Klassert goto ok; 129d77e38e6SSteffen Klassert } 130d77e38e6SSteffen Klassert 131d77e38e6SSteffen Klassert return false; 132d77e38e6SSteffen Klassert 133d77e38e6SSteffen Klassert ok: 134d77e38e6SSteffen Klassert if (dev && dev->xfrmdev_ops && dev->xfrmdev_ops->xdo_dev_offload_ok) 135d77e38e6SSteffen Klassert return x->xso.dev->xfrmdev_ops->xdo_dev_offload_ok(skb, x); 136d77e38e6SSteffen Klassert 137d77e38e6SSteffen Klassert return true; 138d77e38e6SSteffen Klassert } 139d77e38e6SSteffen Klassert EXPORT_SYMBOL_GPL(xfrm_dev_offload_ok); 140d77e38e6SSteffen Klassert 141d77e38e6SSteffen Klassert int xfrm_dev_register(struct net_device *dev) 142d77e38e6SSteffen Klassert { 143d77e38e6SSteffen Klassert if ((dev->features & NETIF_F_HW_ESP) && !dev->xfrmdev_ops) 144d77e38e6SSteffen Klassert return NOTIFY_BAD; 145d77e38e6SSteffen Klassert if ((dev->features & NETIF_F_HW_ESP_TX_CSUM) && 146d77e38e6SSteffen Klassert !(dev->features & NETIF_F_HW_ESP)) 147d77e38e6SSteffen Klassert return NOTIFY_BAD; 148d77e38e6SSteffen Klassert 149d77e38e6SSteffen Klassert return NOTIFY_DONE; 150d77e38e6SSteffen Klassert } 151d77e38e6SSteffen Klassert 152d77e38e6SSteffen Klassert static int xfrm_dev_unregister(struct net_device *dev) 153d77e38e6SSteffen Klassert { 154d77e38e6SSteffen Klassert return NOTIFY_DONE; 155d77e38e6SSteffen Klassert } 156d77e38e6SSteffen Klassert 157d77e38e6SSteffen Klassert static int xfrm_dev_feat_change(struct net_device *dev) 158d77e38e6SSteffen Klassert { 159d77e38e6SSteffen Klassert if ((dev->features & NETIF_F_HW_ESP) && !dev->xfrmdev_ops) 160d77e38e6SSteffen Klassert return NOTIFY_BAD; 161d77e38e6SSteffen Klassert else if (!(dev->features & NETIF_F_HW_ESP)) 162d77e38e6SSteffen Klassert dev->xfrmdev_ops = NULL; 163d77e38e6SSteffen Klassert 164d77e38e6SSteffen Klassert if ((dev->features & NETIF_F_HW_ESP_TX_CSUM) && 165d77e38e6SSteffen Klassert !(dev->features & NETIF_F_HW_ESP)) 166d77e38e6SSteffen Klassert return NOTIFY_BAD; 167d77e38e6SSteffen Klassert 168d77e38e6SSteffen Klassert return NOTIFY_DONE; 169d77e38e6SSteffen Klassert } 170d77e38e6SSteffen Klassert 171d77e38e6SSteffen Klassert static int xfrm_dev_down(struct net_device *dev) 172d77e38e6SSteffen Klassert { 173d77e38e6SSteffen Klassert if (dev->hw_features & NETIF_F_HW_ESP) 174d77e38e6SSteffen Klassert xfrm_dev_state_flush(dev_net(dev), dev, true); 175d77e38e6SSteffen Klassert 176d77e38e6SSteffen Klassert xfrm_garbage_collect(dev_net(dev)); 177d77e38e6SSteffen Klassert 178d77e38e6SSteffen Klassert return NOTIFY_DONE; 179d77e38e6SSteffen Klassert } 180d77e38e6SSteffen Klassert 18121f42cc9SSteffen Klassert static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void *ptr) 18221f42cc9SSteffen Klassert { 18321f42cc9SSteffen Klassert struct net_device *dev = netdev_notifier_info_to_dev(ptr); 18421f42cc9SSteffen Klassert 18521f42cc9SSteffen Klassert switch (event) { 186d77e38e6SSteffen Klassert case NETDEV_REGISTER: 187d77e38e6SSteffen Klassert return xfrm_dev_register(dev); 188d77e38e6SSteffen Klassert 189d77e38e6SSteffen Klassert case NETDEV_UNREGISTER: 190d77e38e6SSteffen Klassert return xfrm_dev_unregister(dev); 191d77e38e6SSteffen Klassert 192d77e38e6SSteffen Klassert case NETDEV_FEAT_CHANGE: 193d77e38e6SSteffen Klassert return xfrm_dev_feat_change(dev); 194d77e38e6SSteffen Klassert 19521f42cc9SSteffen Klassert case NETDEV_DOWN: 196d77e38e6SSteffen Klassert return xfrm_dev_down(dev); 19721f42cc9SSteffen Klassert } 19821f42cc9SSteffen Klassert return NOTIFY_DONE; 19921f42cc9SSteffen Klassert } 20021f42cc9SSteffen Klassert 20121f42cc9SSteffen Klassert static struct notifier_block xfrm_dev_notifier = { 20221f42cc9SSteffen Klassert .notifier_call = xfrm_dev_event, 20321f42cc9SSteffen Klassert }; 20421f42cc9SSteffen Klassert 20521f42cc9SSteffen Klassert void __net_init xfrm_dev_init(void) 20621f42cc9SSteffen Klassert { 20721f42cc9SSteffen Klassert register_netdevice_notifier(&xfrm_dev_notifier); 20821f42cc9SSteffen Klassert } 209