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