18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2004 Topspin Communications. All rights reserved. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 58c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 68c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 78c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 88c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 118c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 128c2ecf20Sopenharmony_ci * conditions are met: 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 158c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 168c2ecf20Sopenharmony_ci * disclaimer. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 198c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 208c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 218c2ecf20Sopenharmony_ci * provided with the distribution. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 248c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 258c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 268c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 278c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 288c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 298c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 308c2ecf20Sopenharmony_ci * SOFTWARE. 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include <linux/module.h> 348c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#include <linux/init.h> 378c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#include "ipoib.h" 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic ssize_t show_parent(struct device *d, struct device_attribute *attr, 448c2ecf20Sopenharmony_ci char *buf) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci struct net_device *dev = to_net_dev(d); 478c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci return sprintf(buf, "%s\n", priv->parent->name); 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_cistatic DEVICE_ATTR(parent, S_IRUGO, show_parent, NULL); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic bool is_child_unique(struct ipoib_dev_priv *ppriv, 548c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci struct ipoib_dev_priv *tpriv; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci ASSERT_RTNL(); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci /* 618c2ecf20Sopenharmony_ci * Since the legacy sysfs interface uses pkey for deletion it cannot 628c2ecf20Sopenharmony_ci * support more than one interface with the same pkey, it creates 638c2ecf20Sopenharmony_ci * ambiguity. The RTNL interface deletes using the netdev so it does 648c2ecf20Sopenharmony_ci * not have a problem to support duplicated pkeys. 658c2ecf20Sopenharmony_ci */ 668c2ecf20Sopenharmony_ci if (priv->child_type != IPOIB_LEGACY_CHILD) 678c2ecf20Sopenharmony_ci return true; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci /* 708c2ecf20Sopenharmony_ci * First ensure this isn't a duplicate. We check the parent device and 718c2ecf20Sopenharmony_ci * then all of the legacy child interfaces to make sure the Pkey 728c2ecf20Sopenharmony_ci * doesn't match. 738c2ecf20Sopenharmony_ci */ 748c2ecf20Sopenharmony_ci if (ppriv->pkey == priv->pkey) 758c2ecf20Sopenharmony_ci return false; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci list_for_each_entry(tpriv, &ppriv->child_intfs, list) { 788c2ecf20Sopenharmony_ci if (tpriv->pkey == priv->pkey && 798c2ecf20Sopenharmony_ci tpriv->child_type == IPOIB_LEGACY_CHILD) 808c2ecf20Sopenharmony_ci return false; 818c2ecf20Sopenharmony_ci } 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci return true; 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci/* 878c2ecf20Sopenharmony_ci * NOTE: If this function fails then the priv->dev will remain valid, however 888c2ecf20Sopenharmony_ci * priv will have been freed and must not be touched by caller in the error 898c2ecf20Sopenharmony_ci * case. 908c2ecf20Sopenharmony_ci * 918c2ecf20Sopenharmony_ci * If (ndev->reg_state == NETREG_UNINITIALIZED) then it is up to the caller to 928c2ecf20Sopenharmony_ci * free the net_device (just as rtnl_newlink does) otherwise the net_device 938c2ecf20Sopenharmony_ci * will be freed when the rtnl is unlocked. 948c2ecf20Sopenharmony_ci */ 958c2ecf20Sopenharmony_ciint __ipoib_vlan_add(struct ipoib_dev_priv *ppriv, struct ipoib_dev_priv *priv, 968c2ecf20Sopenharmony_ci u16 pkey, int type) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci struct net_device *ndev = priv->dev; 998c2ecf20Sopenharmony_ci int result; 1008c2ecf20Sopenharmony_ci struct rdma_netdev *rn = netdev_priv(ndev); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci ASSERT_RTNL(); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci /* 1058c2ecf20Sopenharmony_ci * We do not need to touch priv if register_netdevice fails, so just 1068c2ecf20Sopenharmony_ci * always use this flow. 1078c2ecf20Sopenharmony_ci */ 1088c2ecf20Sopenharmony_ci ndev->priv_destructor = ipoib_intf_free; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci /* 1118c2ecf20Sopenharmony_ci * Racing with unregister of the parent must be prevented by the 1128c2ecf20Sopenharmony_ci * caller. 1138c2ecf20Sopenharmony_ci */ 1148c2ecf20Sopenharmony_ci WARN_ON(ppriv->dev->reg_state != NETREG_REGISTERED); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci if (pkey == 0 || pkey == 0x8000) { 1178c2ecf20Sopenharmony_ci result = -EINVAL; 1188c2ecf20Sopenharmony_ci goto out_early; 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci rn->mtu = priv->mcast_mtu; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci priv->parent = ppriv->dev; 1248c2ecf20Sopenharmony_ci priv->pkey = pkey; 1258c2ecf20Sopenharmony_ci priv->child_type = type; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci if (!is_child_unique(ppriv, priv)) { 1288c2ecf20Sopenharmony_ci result = -ENOTUNIQ; 1298c2ecf20Sopenharmony_ci goto out_early; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci result = register_netdevice(ndev); 1338c2ecf20Sopenharmony_ci if (result) { 1348c2ecf20Sopenharmony_ci ipoib_warn(priv, "failed to initialize; error %i", result); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci /* 1378c2ecf20Sopenharmony_ci * register_netdevice sometimes calls priv_destructor, 1388c2ecf20Sopenharmony_ci * sometimes not. Make sure it was done. 1398c2ecf20Sopenharmony_ci */ 1408c2ecf20Sopenharmony_ci goto out_early; 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci /* RTNL childs don't need proprietary sysfs entries */ 1448c2ecf20Sopenharmony_ci if (type == IPOIB_LEGACY_CHILD) { 1458c2ecf20Sopenharmony_ci if (ipoib_cm_add_mode_attr(ndev)) 1468c2ecf20Sopenharmony_ci goto sysfs_failed; 1478c2ecf20Sopenharmony_ci if (ipoib_add_pkey_attr(ndev)) 1488c2ecf20Sopenharmony_ci goto sysfs_failed; 1498c2ecf20Sopenharmony_ci if (ipoib_add_umcast_attr(ndev)) 1508c2ecf20Sopenharmony_ci goto sysfs_failed; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci if (device_create_file(&ndev->dev, &dev_attr_parent)) 1538c2ecf20Sopenharmony_ci goto sysfs_failed; 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci return 0; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cisysfs_failed: 1598c2ecf20Sopenharmony_ci unregister_netdevice(priv->dev); 1608c2ecf20Sopenharmony_ci return -ENOMEM; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ciout_early: 1638c2ecf20Sopenharmony_ci if (ndev->priv_destructor) 1648c2ecf20Sopenharmony_ci ndev->priv_destructor(ndev); 1658c2ecf20Sopenharmony_ci return result; 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ciint ipoib_vlan_add(struct net_device *pdev, unsigned short pkey) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci struct ipoib_dev_priv *ppriv, *priv; 1718c2ecf20Sopenharmony_ci char intf_name[IFNAMSIZ]; 1728c2ecf20Sopenharmony_ci struct net_device *ndev; 1738c2ecf20Sopenharmony_ci int result; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (!capable(CAP_NET_ADMIN)) 1768c2ecf20Sopenharmony_ci return -EPERM; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci if (!rtnl_trylock()) 1798c2ecf20Sopenharmony_ci return restart_syscall(); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci if (pdev->reg_state != NETREG_REGISTERED) { 1828c2ecf20Sopenharmony_ci rtnl_unlock(); 1838c2ecf20Sopenharmony_ci return -EPERM; 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci ppriv = ipoib_priv(pdev); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci snprintf(intf_name, sizeof(intf_name), "%s.%04x", 1898c2ecf20Sopenharmony_ci ppriv->dev->name, pkey); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci ndev = ipoib_intf_alloc(ppriv->ca, ppriv->port, intf_name); 1928c2ecf20Sopenharmony_ci if (IS_ERR(ndev)) { 1938c2ecf20Sopenharmony_ci result = PTR_ERR(ndev); 1948c2ecf20Sopenharmony_ci goto out; 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci priv = ipoib_priv(ndev); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci ndev->rtnl_link_ops = ipoib_get_link_ops(); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci result = __ipoib_vlan_add(ppriv, priv, pkey, IPOIB_LEGACY_CHILD); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci if (result && ndev->reg_state == NETREG_UNINITIALIZED) 2038c2ecf20Sopenharmony_ci free_netdev(ndev); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ciout: 2068c2ecf20Sopenharmony_ci rtnl_unlock(); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci return result; 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistruct ipoib_vlan_delete_work { 2128c2ecf20Sopenharmony_ci struct work_struct work; 2138c2ecf20Sopenharmony_ci struct net_device *dev; 2148c2ecf20Sopenharmony_ci}; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci/* 2178c2ecf20Sopenharmony_ci * sysfs callbacks of a netdevice cannot obtain the rtnl lock as 2188c2ecf20Sopenharmony_ci * unregister_netdev ultimately deletes the sysfs files while holding the rtnl 2198c2ecf20Sopenharmony_ci * lock. This deadlocks the system. 2208c2ecf20Sopenharmony_ci * 2218c2ecf20Sopenharmony_ci * A callback can use rtnl_trylock to avoid the deadlock but it cannot call 2228c2ecf20Sopenharmony_ci * unregister_netdev as that internally takes and releases the rtnl_lock. So 2238c2ecf20Sopenharmony_ci * instead we find the netdev to unregister and then do the actual unregister 2248c2ecf20Sopenharmony_ci * from the global work queue where we can obtain the rtnl_lock safely. 2258c2ecf20Sopenharmony_ci */ 2268c2ecf20Sopenharmony_cistatic void ipoib_vlan_delete_task(struct work_struct *work) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci struct ipoib_vlan_delete_work *pwork = 2298c2ecf20Sopenharmony_ci container_of(work, struct ipoib_vlan_delete_work, work); 2308c2ecf20Sopenharmony_ci struct net_device *dev = pwork->dev; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci rtnl_lock(); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci /* Unregistering tasks can race with another task or parent removal */ 2358c2ecf20Sopenharmony_ci if (dev->reg_state == NETREG_REGISTERED) { 2368c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 2378c2ecf20Sopenharmony_ci struct ipoib_dev_priv *ppriv = ipoib_priv(priv->parent); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci ipoib_dbg(ppriv, "delete child vlan %s\n", dev->name); 2408c2ecf20Sopenharmony_ci unregister_netdevice(dev); 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci rtnl_unlock(); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci kfree(pwork); 2468c2ecf20Sopenharmony_ci} 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ciint ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci struct ipoib_dev_priv *ppriv, *priv, *tpriv; 2518c2ecf20Sopenharmony_ci int rc; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci if (!capable(CAP_NET_ADMIN)) 2548c2ecf20Sopenharmony_ci return -EPERM; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (!rtnl_trylock()) 2578c2ecf20Sopenharmony_ci return restart_syscall(); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci if (pdev->reg_state != NETREG_REGISTERED) { 2608c2ecf20Sopenharmony_ci rtnl_unlock(); 2618c2ecf20Sopenharmony_ci return -EPERM; 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci ppriv = ipoib_priv(pdev); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci rc = -ENODEV; 2678c2ecf20Sopenharmony_ci list_for_each_entry_safe(priv, tpriv, &ppriv->child_intfs, list) { 2688c2ecf20Sopenharmony_ci if (priv->pkey == pkey && 2698c2ecf20Sopenharmony_ci priv->child_type == IPOIB_LEGACY_CHILD) { 2708c2ecf20Sopenharmony_ci struct ipoib_vlan_delete_work *work; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci work = kmalloc(sizeof(*work), GFP_KERNEL); 2738c2ecf20Sopenharmony_ci if (!work) { 2748c2ecf20Sopenharmony_ci rc = -ENOMEM; 2758c2ecf20Sopenharmony_ci goto out; 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci down_write(&ppriv->vlan_rwsem); 2798c2ecf20Sopenharmony_ci list_del_init(&priv->list); 2808c2ecf20Sopenharmony_ci up_write(&ppriv->vlan_rwsem); 2818c2ecf20Sopenharmony_ci work->dev = priv->dev; 2828c2ecf20Sopenharmony_ci INIT_WORK(&work->work, ipoib_vlan_delete_task); 2838c2ecf20Sopenharmony_ci queue_work(ipoib_workqueue, &work->work); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci rc = 0; 2868c2ecf20Sopenharmony_ci break; 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ciout: 2918c2ecf20Sopenharmony_ci rtnl_unlock(); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci return rc; 2948c2ecf20Sopenharmony_ci} 295