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 25d77e38e6SSteffen Klassert int xfrm_dev_state_add(struct net *net, struct xfrm_state *x, 26d77e38e6SSteffen Klassert struct xfrm_user_offload *xuo) 27d77e38e6SSteffen Klassert { 28d77e38e6SSteffen Klassert int err; 29d77e38e6SSteffen Klassert struct dst_entry *dst; 30d77e38e6SSteffen Klassert struct net_device *dev; 31d77e38e6SSteffen Klassert struct xfrm_state_offload *xso = &x->xso; 32d77e38e6SSteffen Klassert xfrm_address_t *saddr; 33d77e38e6SSteffen Klassert xfrm_address_t *daddr; 34d77e38e6SSteffen Klassert 35d77e38e6SSteffen Klassert if (!x->type_offload) 36d77e38e6SSteffen Klassert return 0; 37d77e38e6SSteffen Klassert 38d77e38e6SSteffen Klassert /* We don't yet support UDP encapsulation, TFC padding and ESN. */ 39d77e38e6SSteffen Klassert if (x->encap || x->tfcpad || (x->props.flags & XFRM_STATE_ESN)) 40d77e38e6SSteffen Klassert return 0; 41d77e38e6SSteffen Klassert 42d77e38e6SSteffen Klassert dev = dev_get_by_index(net, xuo->ifindex); 43d77e38e6SSteffen Klassert if (!dev) { 44d77e38e6SSteffen Klassert if (!(xuo->flags & XFRM_OFFLOAD_INBOUND)) { 45d77e38e6SSteffen Klassert saddr = &x->props.saddr; 46d77e38e6SSteffen Klassert daddr = &x->id.daddr; 47d77e38e6SSteffen Klassert } else { 48d77e38e6SSteffen Klassert saddr = &x->id.daddr; 49d77e38e6SSteffen Klassert daddr = &x->props.saddr; 50d77e38e6SSteffen Klassert } 51d77e38e6SSteffen Klassert 52d77e38e6SSteffen Klassert dst = __xfrm_dst_lookup(net, 0, 0, saddr, daddr, x->props.family); 53d77e38e6SSteffen Klassert if (IS_ERR(dst)) 54d77e38e6SSteffen Klassert return 0; 55d77e38e6SSteffen Klassert 56d77e38e6SSteffen Klassert dev = dst->dev; 57d77e38e6SSteffen Klassert 58d77e38e6SSteffen Klassert dev_hold(dev); 59d77e38e6SSteffen Klassert dst_release(dst); 60d77e38e6SSteffen Klassert } 61d77e38e6SSteffen Klassert 62d77e38e6SSteffen Klassert if (!dev->xfrmdev_ops || !dev->xfrmdev_ops->xdo_dev_state_add) { 63d77e38e6SSteffen Klassert dev_put(dev); 64d77e38e6SSteffen Klassert return 0; 65d77e38e6SSteffen Klassert } 66d77e38e6SSteffen Klassert 67d77e38e6SSteffen Klassert xso->dev = dev; 68d77e38e6SSteffen Klassert xso->num_exthdrs = 1; 69d77e38e6SSteffen Klassert xso->flags = xuo->flags; 70d77e38e6SSteffen Klassert 71d77e38e6SSteffen Klassert err = dev->xfrmdev_ops->xdo_dev_state_add(x); 72d77e38e6SSteffen Klassert if (err) { 73d77e38e6SSteffen Klassert dev_put(dev); 74d77e38e6SSteffen Klassert return err; 75d77e38e6SSteffen Klassert } 76d77e38e6SSteffen Klassert 77d77e38e6SSteffen Klassert return 0; 78d77e38e6SSteffen Klassert } 79d77e38e6SSteffen Klassert EXPORT_SYMBOL_GPL(xfrm_dev_state_add); 80d77e38e6SSteffen Klassert 81d77e38e6SSteffen Klassert bool xfrm_dev_offload_ok(struct sk_buff *skb, struct xfrm_state *x) 82d77e38e6SSteffen Klassert { 83d77e38e6SSteffen Klassert int mtu; 84d77e38e6SSteffen Klassert struct dst_entry *dst = skb_dst(skb); 85d77e38e6SSteffen Klassert struct xfrm_dst *xdst = (struct xfrm_dst *)dst; 86d77e38e6SSteffen Klassert struct net_device *dev = x->xso.dev; 87d77e38e6SSteffen Klassert 88d77e38e6SSteffen Klassert if (!x->type_offload || x->encap) 89d77e38e6SSteffen Klassert return false; 90d77e38e6SSteffen Klassert 91d77e38e6SSteffen Klassert if ((x->xso.offload_handle && (dev == dst->path->dev)) && 92d77e38e6SSteffen Klassert !dst->child->xfrm && x->type->get_mtu) { 93d77e38e6SSteffen Klassert mtu = x->type->get_mtu(x, xdst->child_mtu_cached); 94d77e38e6SSteffen Klassert 95d77e38e6SSteffen Klassert if (skb->len <= mtu) 96d77e38e6SSteffen Klassert goto ok; 97d77e38e6SSteffen Klassert 98d77e38e6SSteffen Klassert if (skb_is_gso(skb) && skb_gso_validate_mtu(skb, mtu)) 99d77e38e6SSteffen Klassert goto ok; 100d77e38e6SSteffen Klassert } 101d77e38e6SSteffen Klassert 102d77e38e6SSteffen Klassert return false; 103d77e38e6SSteffen Klassert 104d77e38e6SSteffen Klassert ok: 105d77e38e6SSteffen Klassert if (dev && dev->xfrmdev_ops && dev->xfrmdev_ops->xdo_dev_offload_ok) 106d77e38e6SSteffen Klassert return x->xso.dev->xfrmdev_ops->xdo_dev_offload_ok(skb, x); 107d77e38e6SSteffen Klassert 108d77e38e6SSteffen Klassert return true; 109d77e38e6SSteffen Klassert } 110d77e38e6SSteffen Klassert EXPORT_SYMBOL_GPL(xfrm_dev_offload_ok); 111d77e38e6SSteffen Klassert 112d77e38e6SSteffen Klassert int xfrm_dev_register(struct net_device *dev) 113d77e38e6SSteffen Klassert { 114d77e38e6SSteffen Klassert if ((dev->features & NETIF_F_HW_ESP) && !dev->xfrmdev_ops) 115d77e38e6SSteffen Klassert return NOTIFY_BAD; 116d77e38e6SSteffen Klassert if ((dev->features & NETIF_F_HW_ESP_TX_CSUM) && 117d77e38e6SSteffen Klassert !(dev->features & NETIF_F_HW_ESP)) 118d77e38e6SSteffen Klassert return NOTIFY_BAD; 119d77e38e6SSteffen Klassert 120d77e38e6SSteffen Klassert return NOTIFY_DONE; 121d77e38e6SSteffen Klassert } 122d77e38e6SSteffen Klassert 123d77e38e6SSteffen Klassert static int xfrm_dev_unregister(struct net_device *dev) 124d77e38e6SSteffen Klassert { 125d77e38e6SSteffen Klassert return NOTIFY_DONE; 126d77e38e6SSteffen Klassert } 127d77e38e6SSteffen Klassert 128d77e38e6SSteffen Klassert static int xfrm_dev_feat_change(struct net_device *dev) 129d77e38e6SSteffen Klassert { 130d77e38e6SSteffen Klassert if ((dev->features & NETIF_F_HW_ESP) && !dev->xfrmdev_ops) 131d77e38e6SSteffen Klassert return NOTIFY_BAD; 132d77e38e6SSteffen Klassert else if (!(dev->features & NETIF_F_HW_ESP)) 133d77e38e6SSteffen Klassert dev->xfrmdev_ops = NULL; 134d77e38e6SSteffen Klassert 135d77e38e6SSteffen Klassert if ((dev->features & NETIF_F_HW_ESP_TX_CSUM) && 136d77e38e6SSteffen Klassert !(dev->features & NETIF_F_HW_ESP)) 137d77e38e6SSteffen Klassert return NOTIFY_BAD; 138d77e38e6SSteffen Klassert 139d77e38e6SSteffen Klassert return NOTIFY_DONE; 140d77e38e6SSteffen Klassert } 141d77e38e6SSteffen Klassert 142d77e38e6SSteffen Klassert static int xfrm_dev_down(struct net_device *dev) 143d77e38e6SSteffen Klassert { 144d77e38e6SSteffen Klassert if (dev->hw_features & NETIF_F_HW_ESP) 145d77e38e6SSteffen Klassert xfrm_dev_state_flush(dev_net(dev), dev, true); 146d77e38e6SSteffen Klassert 147d77e38e6SSteffen Klassert xfrm_garbage_collect(dev_net(dev)); 148d77e38e6SSteffen Klassert 149d77e38e6SSteffen Klassert return NOTIFY_DONE; 150d77e38e6SSteffen Klassert } 151d77e38e6SSteffen Klassert 15221f42cc9SSteffen Klassert static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void *ptr) 15321f42cc9SSteffen Klassert { 15421f42cc9SSteffen Klassert struct net_device *dev = netdev_notifier_info_to_dev(ptr); 15521f42cc9SSteffen Klassert 15621f42cc9SSteffen Klassert switch (event) { 157d77e38e6SSteffen Klassert case NETDEV_REGISTER: 158d77e38e6SSteffen Klassert return xfrm_dev_register(dev); 159d77e38e6SSteffen Klassert 160d77e38e6SSteffen Klassert case NETDEV_UNREGISTER: 161d77e38e6SSteffen Klassert return xfrm_dev_unregister(dev); 162d77e38e6SSteffen Klassert 163d77e38e6SSteffen Klassert case NETDEV_FEAT_CHANGE: 164d77e38e6SSteffen Klassert return xfrm_dev_feat_change(dev); 165d77e38e6SSteffen Klassert 16621f42cc9SSteffen Klassert case NETDEV_DOWN: 167d77e38e6SSteffen Klassert return xfrm_dev_down(dev); 16821f42cc9SSteffen Klassert } 16921f42cc9SSteffen Klassert return NOTIFY_DONE; 17021f42cc9SSteffen Klassert } 17121f42cc9SSteffen Klassert 17221f42cc9SSteffen Klassert static struct notifier_block xfrm_dev_notifier = { 17321f42cc9SSteffen Klassert .notifier_call = xfrm_dev_event, 17421f42cc9SSteffen Klassert }; 17521f42cc9SSteffen Klassert 17621f42cc9SSteffen Klassert void __net_init xfrm_dev_init(void) 17721f42cc9SSteffen Klassert { 17821f42cc9SSteffen Klassert register_netdevice_notifier(&xfrm_dev_notifier); 17921f42cc9SSteffen Klassert } 180