100c94ca2SJakub Kicinski // SPDX-License-Identifier: GPL-2.0-only 200c94ca2SJakub Kicinski 300c94ca2SJakub Kicinski #include <linux/list.h> 400c94ca2SJakub Kicinski #include <linux/netdevice.h> 500c94ca2SJakub Kicinski #include <linux/xarray.h> 600c94ca2SJakub Kicinski #include <net/net_namespace.h> 700c94ca2SJakub Kicinski #include <net/psp.h> 800c94ca2SJakub Kicinski 900c94ca2SJakub Kicinski #include "psp.h" 1000c94ca2SJakub Kicinski #include "psp-nl-gen.h" 1100c94ca2SJakub Kicinski 1200c94ca2SJakub Kicinski DEFINE_XARRAY_ALLOC1(psp_devs); 1300c94ca2SJakub Kicinski struct mutex psp_devs_lock; 1400c94ca2SJakub Kicinski 1500c94ca2SJakub Kicinski /** 1600c94ca2SJakub Kicinski * DOC: PSP locking 1700c94ca2SJakub Kicinski * 1800c94ca2SJakub Kicinski * psp_devs_lock protects the psp_devs xarray. 1900c94ca2SJakub Kicinski * Ordering is take the psp_devs_lock and then the instance lock. 2000c94ca2SJakub Kicinski * Each instance is protected by RCU, and has a refcount. 2100c94ca2SJakub Kicinski * When driver unregisters the instance gets flushed, but struct sticks around. 2200c94ca2SJakub Kicinski */ 2300c94ca2SJakub Kicinski 2400c94ca2SJakub Kicinski /** 2500c94ca2SJakub Kicinski * psp_dev_check_access() - check if user in a given net ns can access PSP dev 2600c94ca2SJakub Kicinski * @psd: PSP device structure user is trying to access 2700c94ca2SJakub Kicinski * @net: net namespace user is in 2800c94ca2SJakub Kicinski * 2900c94ca2SJakub Kicinski * Return: 0 if PSP device should be visible in @net, errno otherwise. 3000c94ca2SJakub Kicinski */ 3100c94ca2SJakub Kicinski int psp_dev_check_access(struct psp_dev *psd, struct net *net) 3200c94ca2SJakub Kicinski { 3300c94ca2SJakub Kicinski if (dev_net(psd->main_netdev) == net) 3400c94ca2SJakub Kicinski return 0; 3500c94ca2SJakub Kicinski return -ENOENT; 3600c94ca2SJakub Kicinski } 3700c94ca2SJakub Kicinski 3800c94ca2SJakub Kicinski /** 3900c94ca2SJakub Kicinski * psp_dev_create() - create and register PSP device 4000c94ca2SJakub Kicinski * @netdev: main netdevice 4100c94ca2SJakub Kicinski * @psd_ops: driver callbacks 4200c94ca2SJakub Kicinski * @psd_caps: device capabilities 4300c94ca2SJakub Kicinski * @priv_ptr: back-pointer to driver private data 4400c94ca2SJakub Kicinski * 4500c94ca2SJakub Kicinski * Return: pointer to allocated PSP device, or ERR_PTR. 4600c94ca2SJakub Kicinski */ 4700c94ca2SJakub Kicinski struct psp_dev * 4800c94ca2SJakub Kicinski psp_dev_create(struct net_device *netdev, 4900c94ca2SJakub Kicinski struct psp_dev_ops *psd_ops, struct psp_dev_caps *psd_caps, 5000c94ca2SJakub Kicinski void *priv_ptr) 5100c94ca2SJakub Kicinski { 5200c94ca2SJakub Kicinski struct psp_dev *psd; 5300c94ca2SJakub Kicinski static u32 last_id; 5400c94ca2SJakub Kicinski int err; 5500c94ca2SJakub Kicinski 5600c94ca2SJakub Kicinski if (WARN_ON(!psd_caps->versions || 57117f02a4SJakub Kicinski !psd_ops->set_config || 58*6b46ca26SJakub Kicinski !psd_ops->key_rotate || 59*6b46ca26SJakub Kicinski !psd_ops->rx_spi_alloc || 60*6b46ca26SJakub Kicinski !psd_ops->tx_key_add || 61*6b46ca26SJakub Kicinski !psd_ops->tx_key_del)) 6200c94ca2SJakub Kicinski return ERR_PTR(-EINVAL); 6300c94ca2SJakub Kicinski 6400c94ca2SJakub Kicinski psd = kzalloc(sizeof(*psd), GFP_KERNEL); 6500c94ca2SJakub Kicinski if (!psd) 6600c94ca2SJakub Kicinski return ERR_PTR(-ENOMEM); 6700c94ca2SJakub Kicinski 6800c94ca2SJakub Kicinski psd->main_netdev = netdev; 6900c94ca2SJakub Kicinski psd->ops = psd_ops; 7000c94ca2SJakub Kicinski psd->caps = psd_caps; 7100c94ca2SJakub Kicinski psd->drv_priv = priv_ptr; 7200c94ca2SJakub Kicinski 7300c94ca2SJakub Kicinski mutex_init(&psd->lock); 74*6b46ca26SJakub Kicinski INIT_LIST_HEAD(&psd->active_assocs); 7500c94ca2SJakub Kicinski refcount_set(&psd->refcnt, 1); 7600c94ca2SJakub Kicinski 7700c94ca2SJakub Kicinski mutex_lock(&psp_devs_lock); 7800c94ca2SJakub Kicinski err = xa_alloc_cyclic(&psp_devs, &psd->id, psd, xa_limit_16b, 7900c94ca2SJakub Kicinski &last_id, GFP_KERNEL); 8000c94ca2SJakub Kicinski if (err) { 8100c94ca2SJakub Kicinski mutex_unlock(&psp_devs_lock); 8200c94ca2SJakub Kicinski kfree(psd); 8300c94ca2SJakub Kicinski return ERR_PTR(err); 8400c94ca2SJakub Kicinski } 8500c94ca2SJakub Kicinski mutex_lock(&psd->lock); 8600c94ca2SJakub Kicinski mutex_unlock(&psp_devs_lock); 8700c94ca2SJakub Kicinski 8800c94ca2SJakub Kicinski psp_nl_notify_dev(psd, PSP_CMD_DEV_ADD_NTF); 8900c94ca2SJakub Kicinski 9000c94ca2SJakub Kicinski rcu_assign_pointer(netdev->psp_dev, psd); 9100c94ca2SJakub Kicinski 9200c94ca2SJakub Kicinski mutex_unlock(&psd->lock); 9300c94ca2SJakub Kicinski 9400c94ca2SJakub Kicinski return psd; 9500c94ca2SJakub Kicinski } 9600c94ca2SJakub Kicinski EXPORT_SYMBOL(psp_dev_create); 9700c94ca2SJakub Kicinski 9800c94ca2SJakub Kicinski void psp_dev_destroy(struct psp_dev *psd) 9900c94ca2SJakub Kicinski { 10000c94ca2SJakub Kicinski mutex_lock(&psp_devs_lock); 10100c94ca2SJakub Kicinski xa_erase(&psp_devs, psd->id); 10200c94ca2SJakub Kicinski mutex_unlock(&psp_devs_lock); 10300c94ca2SJakub Kicinski 10400c94ca2SJakub Kicinski mutex_destroy(&psd->lock); 10500c94ca2SJakub Kicinski kfree_rcu(psd, rcu); 10600c94ca2SJakub Kicinski } 10700c94ca2SJakub Kicinski 10800c94ca2SJakub Kicinski /** 10900c94ca2SJakub Kicinski * psp_dev_unregister() - unregister PSP device 11000c94ca2SJakub Kicinski * @psd: PSP device structure 11100c94ca2SJakub Kicinski */ 11200c94ca2SJakub Kicinski void psp_dev_unregister(struct psp_dev *psd) 11300c94ca2SJakub Kicinski { 114*6b46ca26SJakub Kicinski struct psp_assoc *pas, *next; 115*6b46ca26SJakub Kicinski 11600c94ca2SJakub Kicinski mutex_lock(&psp_devs_lock); 11700c94ca2SJakub Kicinski mutex_lock(&psd->lock); 11800c94ca2SJakub Kicinski 11900c94ca2SJakub Kicinski psp_nl_notify_dev(psd, PSP_CMD_DEV_DEL_NTF); 12000c94ca2SJakub Kicinski 12100c94ca2SJakub Kicinski /* Wait until psp_dev_destroy() to call xa_erase() to prevent a 12200c94ca2SJakub Kicinski * different psd from being added to the xarray with this id, while 12300c94ca2SJakub Kicinski * there are still references to this psd being held. 12400c94ca2SJakub Kicinski */ 12500c94ca2SJakub Kicinski xa_store(&psp_devs, psd->id, NULL, GFP_KERNEL); 12600c94ca2SJakub Kicinski mutex_unlock(&psp_devs_lock); 12700c94ca2SJakub Kicinski 128*6b46ca26SJakub Kicinski list_for_each_entry_safe(pas, next, &psd->active_assocs, assocs_list) 129*6b46ca26SJakub Kicinski psp_dev_tx_key_del(psd, pas); 130*6b46ca26SJakub Kicinski 13100c94ca2SJakub Kicinski rcu_assign_pointer(psd->main_netdev->psp_dev, NULL); 13200c94ca2SJakub Kicinski 13300c94ca2SJakub Kicinski psd->ops = NULL; 13400c94ca2SJakub Kicinski psd->drv_priv = NULL; 13500c94ca2SJakub Kicinski 13600c94ca2SJakub Kicinski mutex_unlock(&psd->lock); 13700c94ca2SJakub Kicinski 13800c94ca2SJakub Kicinski psp_dev_put(psd); 13900c94ca2SJakub Kicinski } 14000c94ca2SJakub Kicinski EXPORT_SYMBOL(psp_dev_unregister); 14100c94ca2SJakub Kicinski 142*6b46ca26SJakub Kicinski unsigned int psp_key_size(u32 version) 143*6b46ca26SJakub Kicinski { 144*6b46ca26SJakub Kicinski switch (version) { 145*6b46ca26SJakub Kicinski case PSP_VERSION_HDR0_AES_GCM_128: 146*6b46ca26SJakub Kicinski case PSP_VERSION_HDR0_AES_GMAC_128: 147*6b46ca26SJakub Kicinski return 16; 148*6b46ca26SJakub Kicinski case PSP_VERSION_HDR0_AES_GCM_256: 149*6b46ca26SJakub Kicinski case PSP_VERSION_HDR0_AES_GMAC_256: 150*6b46ca26SJakub Kicinski return 32; 151*6b46ca26SJakub Kicinski default: 152*6b46ca26SJakub Kicinski return 0; 153*6b46ca26SJakub Kicinski } 154*6b46ca26SJakub Kicinski } 155*6b46ca26SJakub Kicinski EXPORT_SYMBOL(psp_key_size); 156*6b46ca26SJakub Kicinski 15700c94ca2SJakub Kicinski static int __init psp_init(void) 15800c94ca2SJakub Kicinski { 15900c94ca2SJakub Kicinski mutex_init(&psp_devs_lock); 16000c94ca2SJakub Kicinski 16100c94ca2SJakub Kicinski return genl_register_family(&psp_nl_family); 16200c94ca2SJakub Kicinski } 16300c94ca2SJakub Kicinski 16400c94ca2SJakub Kicinski subsys_initcall(psp_init); 165