1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause OR GPL-2.0 3 * 4 * Copyright (c) 2004 Topspin Communications. All rights reserved. 5 * 6 * This software is available to you under a choice of one of two 7 * licenses. You may choose to be licensed under the terms of the GNU 8 * General Public License (GPL) Version 2, available from the file 9 * COPYING in the main directory of this source tree, or the 10 * OpenIB.org BSD license below: 11 * 12 * Redistribution and use in source and binary forms, with or 13 * without modification, are permitted provided that the following 14 * conditions are met: 15 * 16 * - Redistributions of source code must retain the above 17 * copyright notice, this list of conditions and the following 18 * disclaimer. 19 * 20 * - Redistributions in binary form must reproduce the above 21 * copyright notice, this list of conditions and the following 22 * disclaimer in the documentation and/or other materials 23 * provided with the distribution. 24 * 25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 * SOFTWARE. 33 */ 34 35 #include <linux/module.h> 36 37 #include <linux/init.h> 38 #include <linux/slab.h> 39 #include <linux/seq_file.h> 40 41 #include <asm/uaccess.h> 42 43 #include "ipoib.h" 44 45 static ssize_t show_parent(struct device *d, struct device_attribute *attr, 46 char *buf) 47 { 48 struct ifnet *dev = to_net_dev(d); 49 struct ipoib_dev_priv *priv = dev->if_softc; 50 51 return sprintf(buf, "%s\n", priv->parent->name); 52 } 53 static DEVICE_ATTR(parent, S_IRUGO, show_parent, NULL); 54 55 int ipoib_vlan_add(struct ifnet *pdev, unsigned short pkey) 56 { 57 struct ipoib_dev_priv *ppriv, *priv; 58 char intf_name[IFNAMSIZ]; 59 int result; 60 61 if (!capable(CAP_NET_ADMIN)) 62 return -EPERM; 63 64 ppriv = pdev->if_softc; 65 66 rtnl_lock(); 67 mutex_lock(&ppriv->vlan_mutex); 68 69 /* 70 * First ensure this isn't a duplicate. We check the parent device and 71 * then all of the child interfaces to make sure the Pkey doesn't match. 72 */ 73 if (ppriv->pkey == pkey) { 74 result = -ENOTUNIQ; 75 priv = NULL; 76 goto err; 77 } 78 79 list_for_each_entry(priv, &ppriv->child_intfs, list) { 80 if (priv->pkey == pkey) { 81 result = -ENOTUNIQ; 82 priv = NULL; 83 goto err; 84 } 85 } 86 87 snprintf(intf_name, sizeof intf_name, "%s.%04x", 88 ppriv->dev->name, pkey); 89 priv = ipoib_intf_alloc(intf_name); 90 if (!priv) { 91 result = -ENOMEM; 92 goto err; 93 } 94 95 priv->max_ib_mtu = ppriv->max_ib_mtu; 96 /* MTU will be reset when mcast join happens */ 97 priv->dev->mtu = IPOIB_UD_MTU(priv->max_ib_mtu); 98 priv->mcast_mtu = priv->admin_mtu = priv->dev->mtu; 99 set_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags); 100 101 result = ipoib_set_dev_features(priv, ppriv->ca); 102 if (result) 103 goto err; 104 105 priv->pkey = pkey; 106 107 memcpy(IF_LLADDR(priv->dev), ppriv->dev->dev_addr, INFINIBAND_ALEN); 108 priv->broadcastaddr[8] = pkey >> 8; 109 priv->broadcastaddr[9] = pkey & 0xff; 110 111 result = ipoib_dev_init(priv->dev, ppriv->ca, ppriv->port); 112 if (result < 0) { 113 ipoib_warn(ppriv, "failed to initialize subinterface: " 114 "device %s, port %d", 115 ppriv->ca->name, ppriv->port); 116 goto err; 117 } 118 119 result = register_netdevice(priv->dev); 120 if (result) { 121 ipoib_warn(priv, "failed to initialize; error %i", result); 122 goto register_failed; 123 } 124 125 priv->parent = ppriv->dev; 126 127 ipoib_create_debug_files(priv->dev); 128 129 if (ipoib_cm_add_mode_attr(priv->dev)) 130 goto sysfs_failed; 131 if (ipoib_add_pkey_attr(priv->dev)) 132 goto sysfs_failed; 133 if (ipoib_add_umcast_attr(priv->dev)) 134 goto sysfs_failed; 135 136 if (device_create_file(&priv->dev->dev, &dev_attr_parent)) 137 goto sysfs_failed; 138 139 list_add_tail(&priv->list, &ppriv->child_intfs); 140 141 mutex_unlock(&ppriv->vlan_mutex); 142 rtnl_unlock(); 143 144 return 0; 145 146 sysfs_failed: 147 ipoib_delete_debug_files(priv->dev); 148 unregister_netdevice(priv->dev); 149 150 register_failed: 151 ipoib_dev_cleanup(priv->dev); 152 153 err: 154 mutex_unlock(&ppriv->vlan_mutex); 155 rtnl_unlock(); 156 if (priv) 157 free_netdev(priv->dev); 158 159 return result; 160 } 161 162 int ipoib_vlan_delete(struct ifnet *pdev, unsigned short pkey) 163 { 164 struct ipoib_dev_priv *ppriv, *priv, *tpriv; 165 struct ifnet *dev = NULL; 166 167 if (!capable(CAP_NET_ADMIN)) 168 return -EPERM; 169 170 ppriv = pdev->if_softc; 171 172 rtnl_lock(); 173 mutex_lock(&ppriv->vlan_mutex); 174 list_for_each_entry_safe(priv, tpriv, &ppriv->child_intfs, list) { 175 if (priv->pkey == pkey) { 176 unregister_netdevice(priv->dev); 177 ipoib_dev_cleanup(priv->dev); 178 list_del(&priv->list); 179 dev = priv->dev; 180 break; 181 } 182 } 183 mutex_unlock(&ppriv->vlan_mutex); 184 rtnl_unlock(); 185 186 if (dev) { 187 free_netdev(dev); 188 return 0; 189 } 190 191 return -ENODEV; 192 } 193