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 <sys/cdefs.h> 36 __FBSDID("$FreeBSD$"); 37 38 #include <linux/module.h> 39 40 #include <linux/init.h> 41 #include <linux/slab.h> 42 #include <linux/seq_file.h> 43 44 #include <asm/uaccess.h> 45 46 #include "ipoib.h" 47 48 static ssize_t show_parent(struct device *d, struct device_attribute *attr, 49 char *buf) 50 { 51 struct ifnet *dev = to_net_dev(d); 52 struct ipoib_dev_priv *priv = dev->if_softc; 53 54 return sprintf(buf, "%s\n", priv->parent->name); 55 } 56 static DEVICE_ATTR(parent, S_IRUGO, show_parent, NULL); 57 58 int ipoib_vlan_add(struct ifnet *pdev, unsigned short pkey) 59 { 60 struct ipoib_dev_priv *ppriv, *priv; 61 char intf_name[IFNAMSIZ]; 62 int result; 63 64 if (!capable(CAP_NET_ADMIN)) 65 return -EPERM; 66 67 ppriv = pdev->if_softc; 68 69 rtnl_lock(); 70 mutex_lock(&ppriv->vlan_mutex); 71 72 /* 73 * First ensure this isn't a duplicate. We check the parent device and 74 * then all of the child interfaces to make sure the Pkey doesn't match. 75 */ 76 if (ppriv->pkey == pkey) { 77 result = -ENOTUNIQ; 78 priv = NULL; 79 goto err; 80 } 81 82 list_for_each_entry(priv, &ppriv->child_intfs, list) { 83 if (priv->pkey == pkey) { 84 result = -ENOTUNIQ; 85 priv = NULL; 86 goto err; 87 } 88 } 89 90 snprintf(intf_name, sizeof intf_name, "%s.%04x", 91 ppriv->dev->name, pkey); 92 priv = ipoib_intf_alloc(intf_name); 93 if (!priv) { 94 result = -ENOMEM; 95 goto err; 96 } 97 98 priv->max_ib_mtu = ppriv->max_ib_mtu; 99 /* MTU will be reset when mcast join happens */ 100 priv->dev->mtu = IPOIB_UD_MTU(priv->max_ib_mtu); 101 priv->mcast_mtu = priv->admin_mtu = priv->dev->mtu; 102 set_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags); 103 104 result = ipoib_set_dev_features(priv, ppriv->ca); 105 if (result) 106 goto err; 107 108 priv->pkey = pkey; 109 110 memcpy(IF_LLADDR(priv->dev), ppriv->dev->dev_addr, INFINIBAND_ALEN); 111 priv->broadcastaddr[8] = pkey >> 8; 112 priv->broadcastaddr[9] = pkey & 0xff; 113 114 result = ipoib_dev_init(priv->dev, ppriv->ca, ppriv->port); 115 if (result < 0) { 116 ipoib_warn(ppriv, "failed to initialize subinterface: " 117 "device %s, port %d", 118 ppriv->ca->name, ppriv->port); 119 goto err; 120 } 121 122 result = register_netdevice(priv->dev); 123 if (result) { 124 ipoib_warn(priv, "failed to initialize; error %i", result); 125 goto register_failed; 126 } 127 128 priv->parent = ppriv->dev; 129 130 ipoib_create_debug_files(priv->dev); 131 132 if (ipoib_cm_add_mode_attr(priv->dev)) 133 goto sysfs_failed; 134 if (ipoib_add_pkey_attr(priv->dev)) 135 goto sysfs_failed; 136 if (ipoib_add_umcast_attr(priv->dev)) 137 goto sysfs_failed; 138 139 if (device_create_file(&priv->dev->dev, &dev_attr_parent)) 140 goto sysfs_failed; 141 142 list_add_tail(&priv->list, &ppriv->child_intfs); 143 144 mutex_unlock(&ppriv->vlan_mutex); 145 rtnl_unlock(); 146 147 return 0; 148 149 sysfs_failed: 150 ipoib_delete_debug_files(priv->dev); 151 unregister_netdevice(priv->dev); 152 153 register_failed: 154 ipoib_dev_cleanup(priv->dev); 155 156 err: 157 mutex_unlock(&ppriv->vlan_mutex); 158 rtnl_unlock(); 159 if (priv) 160 free_netdev(priv->dev); 161 162 return result; 163 } 164 165 int ipoib_vlan_delete(struct ifnet *pdev, unsigned short pkey) 166 { 167 struct ipoib_dev_priv *ppriv, *priv, *tpriv; 168 struct ifnet *dev = NULL; 169 170 if (!capable(CAP_NET_ADMIN)) 171 return -EPERM; 172 173 ppriv = pdev->if_softc; 174 175 rtnl_lock(); 176 mutex_lock(&ppriv->vlan_mutex); 177 list_for_each_entry_safe(priv, tpriv, &ppriv->child_intfs, list) { 178 if (priv->pkey == pkey) { 179 unregister_netdevice(priv->dev); 180 ipoib_dev_cleanup(priv->dev); 181 list_del(&priv->list); 182 dev = priv->dev; 183 break; 184 } 185 } 186 mutex_unlock(&ppriv->vlan_mutex); 187 rtnl_unlock(); 188 189 if (dev) { 190 free_netdev(dev); 191 return 0; 192 } 193 194 return -ENODEV; 195 } 196