1 // SPDX-License-Identifier: GPL-2.0-only 2 3 #include <linux/list.h> 4 #include <linux/netdevice.h> 5 #include <linux/xarray.h> 6 #include <net/net_namespace.h> 7 #include <net/psp.h> 8 9 #include "psp.h" 10 #include "psp-nl-gen.h" 11 12 DEFINE_XARRAY_ALLOC1(psp_devs); 13 struct mutex psp_devs_lock; 14 15 /** 16 * DOC: PSP locking 17 * 18 * psp_devs_lock protects the psp_devs xarray. 19 * Ordering is take the psp_devs_lock and then the instance lock. 20 * Each instance is protected by RCU, and has a refcount. 21 * When driver unregisters the instance gets flushed, but struct sticks around. 22 */ 23 24 /** 25 * psp_dev_check_access() - check if user in a given net ns can access PSP dev 26 * @psd: PSP device structure user is trying to access 27 * @net: net namespace user is in 28 * 29 * Return: 0 if PSP device should be visible in @net, errno otherwise. 30 */ 31 int psp_dev_check_access(struct psp_dev *psd, struct net *net) 32 { 33 if (dev_net(psd->main_netdev) == net) 34 return 0; 35 return -ENOENT; 36 } 37 38 /** 39 * psp_dev_create() - create and register PSP device 40 * @netdev: main netdevice 41 * @psd_ops: driver callbacks 42 * @psd_caps: device capabilities 43 * @priv_ptr: back-pointer to driver private data 44 * 45 * Return: pointer to allocated PSP device, or ERR_PTR. 46 */ 47 struct psp_dev * 48 psp_dev_create(struct net_device *netdev, 49 struct psp_dev_ops *psd_ops, struct psp_dev_caps *psd_caps, 50 void *priv_ptr) 51 { 52 struct psp_dev *psd; 53 static u32 last_id; 54 int err; 55 56 if (WARN_ON(!psd_caps->versions || 57 !psd_ops->set_config || 58 !psd_ops->key_rotate || 59 !psd_ops->rx_spi_alloc || 60 !psd_ops->tx_key_add || 61 !psd_ops->tx_key_del)) 62 return ERR_PTR(-EINVAL); 63 64 psd = kzalloc(sizeof(*psd), GFP_KERNEL); 65 if (!psd) 66 return ERR_PTR(-ENOMEM); 67 68 psd->main_netdev = netdev; 69 psd->ops = psd_ops; 70 psd->caps = psd_caps; 71 psd->drv_priv = priv_ptr; 72 73 mutex_init(&psd->lock); 74 INIT_LIST_HEAD(&psd->active_assocs); 75 refcount_set(&psd->refcnt, 1); 76 77 mutex_lock(&psp_devs_lock); 78 err = xa_alloc_cyclic(&psp_devs, &psd->id, psd, xa_limit_16b, 79 &last_id, GFP_KERNEL); 80 if (err) { 81 mutex_unlock(&psp_devs_lock); 82 kfree(psd); 83 return ERR_PTR(err); 84 } 85 mutex_lock(&psd->lock); 86 mutex_unlock(&psp_devs_lock); 87 88 psp_nl_notify_dev(psd, PSP_CMD_DEV_ADD_NTF); 89 90 rcu_assign_pointer(netdev->psp_dev, psd); 91 92 mutex_unlock(&psd->lock); 93 94 return psd; 95 } 96 EXPORT_SYMBOL(psp_dev_create); 97 98 void psp_dev_destroy(struct psp_dev *psd) 99 { 100 mutex_lock(&psp_devs_lock); 101 xa_erase(&psp_devs, psd->id); 102 mutex_unlock(&psp_devs_lock); 103 104 mutex_destroy(&psd->lock); 105 kfree_rcu(psd, rcu); 106 } 107 108 /** 109 * psp_dev_unregister() - unregister PSP device 110 * @psd: PSP device structure 111 */ 112 void psp_dev_unregister(struct psp_dev *psd) 113 { 114 struct psp_assoc *pas, *next; 115 116 mutex_lock(&psp_devs_lock); 117 mutex_lock(&psd->lock); 118 119 psp_nl_notify_dev(psd, PSP_CMD_DEV_DEL_NTF); 120 121 /* Wait until psp_dev_destroy() to call xa_erase() to prevent a 122 * different psd from being added to the xarray with this id, while 123 * there are still references to this psd being held. 124 */ 125 xa_store(&psp_devs, psd->id, NULL, GFP_KERNEL); 126 mutex_unlock(&psp_devs_lock); 127 128 list_for_each_entry_safe(pas, next, &psd->active_assocs, assocs_list) 129 psp_dev_tx_key_del(psd, pas); 130 131 rcu_assign_pointer(psd->main_netdev->psp_dev, NULL); 132 133 psd->ops = NULL; 134 psd->drv_priv = NULL; 135 136 mutex_unlock(&psd->lock); 137 138 psp_dev_put(psd); 139 } 140 EXPORT_SYMBOL(psp_dev_unregister); 141 142 unsigned int psp_key_size(u32 version) 143 { 144 switch (version) { 145 case PSP_VERSION_HDR0_AES_GCM_128: 146 case PSP_VERSION_HDR0_AES_GMAC_128: 147 return 16; 148 case PSP_VERSION_HDR0_AES_GCM_256: 149 case PSP_VERSION_HDR0_AES_GMAC_256: 150 return 32; 151 default: 152 return 0; 153 } 154 } 155 EXPORT_SYMBOL(psp_key_size); 156 157 static int __init psp_init(void) 158 { 159 mutex_init(&psp_devs_lock); 160 161 return genl_register_family(&psp_nl_family); 162 } 163 164 subsys_initcall(psp_init); 165