1 /* 2 * Copyright (c) 2004 Topspin Communications. All rights reserved. 3 * 4 * This software is available to you under a choice of one of two 5 * licenses. You may choose to be licensed under the terms of the GNU 6 * General Public License (GPL) Version 2, available from the file 7 * COPYING in the main directory of this source tree, or the 8 * OpenIB.org BSD license below: 9 * 10 * Redistribution and use in source and binary forms, with or 11 * without modification, are permitted provided that the following 12 * conditions are met: 13 * 14 * - Redistributions of source code must retain the above 15 * copyright notice, this list of conditions and the following 16 * disclaimer. 17 * 18 * - Redistributions in binary form must reproduce the above 19 * copyright notice, this list of conditions and the following 20 * disclaimer in the documentation and/or other materials 21 * provided with the distribution. 22 * 23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 * SOFTWARE. 31 * 32 * $Id: ipoib_vlan.c 1349 2004-12-16 21:09:43Z roland $ 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 class_device *class_dev, char *buf) 46 { 47 struct net_device *dev = 48 container_of(class_dev, struct net_device, class_dev); 49 struct ipoib_dev_priv *priv = netdev_priv(dev); 50 51 return sprintf(buf, "%s\n", priv->parent->name); 52 } 53 static CLASS_DEVICE_ATTR(parent, S_IRUGO, show_parent, NULL); 54 55 int ipoib_vlan_add(struct net_device *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 = netdev_priv(pdev); 65 66 down(&ppriv->vlan_mutex); 67 68 /* 69 * First ensure this isn't a duplicate. We check the parent device and 70 * then all of the child interfaces to make sure the Pkey doesn't match. 71 */ 72 if (ppriv->pkey == pkey) { 73 result = -ENOTUNIQ; 74 goto err; 75 } 76 77 list_for_each_entry(priv, &ppriv->child_intfs, list) { 78 if (priv->pkey == pkey) { 79 result = -ENOTUNIQ; 80 goto err; 81 } 82 } 83 84 snprintf(intf_name, sizeof intf_name, "%s.%04x", 85 ppriv->dev->name, pkey); 86 priv = ipoib_intf_alloc(intf_name); 87 if (!priv) { 88 result = -ENOMEM; 89 goto err; 90 } 91 92 set_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags); 93 94 priv->pkey = pkey; 95 96 memcpy(priv->dev->dev_addr, ppriv->dev->dev_addr, INFINIBAND_ALEN); 97 priv->dev->broadcast[8] = pkey >> 8; 98 priv->dev->broadcast[9] = pkey & 0xff; 99 100 result = ipoib_dev_init(priv->dev, ppriv->ca, ppriv->port); 101 if (result < 0) { 102 ipoib_warn(ppriv, "failed to initialize subinterface: " 103 "device %s, port %d", 104 ppriv->ca->name, ppriv->port); 105 goto device_init_failed; 106 } 107 108 result = register_netdev(priv->dev); 109 if (result) { 110 ipoib_warn(priv, "failed to initialize; error %i", result); 111 goto register_failed; 112 } 113 114 priv->parent = ppriv->dev; 115 116 ipoib_create_debug_files(priv->dev); 117 118 if (ipoib_add_pkey_attr(priv->dev)) 119 goto sysfs_failed; 120 121 if (class_device_create_file(&priv->dev->class_dev, 122 &class_device_attr_parent)) 123 goto sysfs_failed; 124 125 list_add_tail(&priv->list, &ppriv->child_intfs); 126 127 up(&ppriv->vlan_mutex); 128 129 return 0; 130 131 sysfs_failed: 132 ipoib_delete_debug_files(priv->dev); 133 unregister_netdev(priv->dev); 134 135 register_failed: 136 ipoib_dev_cleanup(priv->dev); 137 138 device_init_failed: 139 free_netdev(priv->dev); 140 141 err: 142 up(&ppriv->vlan_mutex); 143 return result; 144 } 145 146 int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey) 147 { 148 struct ipoib_dev_priv *ppriv, *priv, *tpriv; 149 int ret = -ENOENT; 150 151 if (!capable(CAP_NET_ADMIN)) 152 return -EPERM; 153 154 ppriv = netdev_priv(pdev); 155 156 down(&ppriv->vlan_mutex); 157 list_for_each_entry_safe(priv, tpriv, &ppriv->child_intfs, list) { 158 if (priv->pkey == pkey) { 159 unregister_netdev(priv->dev); 160 ipoib_dev_cleanup(priv->dev); 161 162 list_del(&priv->list); 163 164 kfree(priv); 165 166 ret = 0; 167 break; 168 } 169 } 170 up(&ppriv->vlan_mutex); 171 172 return ret; 173 } 174