1219820Sjeff/* 2219820Sjeff * Copyright (c) 2004 Topspin Communications. All rights reserved. 3219820Sjeff * 4219820Sjeff * This software is available to you under a choice of one of two 5219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 6219820Sjeff * General Public License (GPL) Version 2, available from the file 7219820Sjeff * COPYING in the main directory of this source tree, or the 8219820Sjeff * OpenIB.org BSD license below: 9219820Sjeff * 10219820Sjeff * Redistribution and use in source and binary forms, with or 11219820Sjeff * without modification, are permitted provided that the following 12219820Sjeff * conditions are met: 13219820Sjeff * 14219820Sjeff * - Redistributions of source code must retain the above 15219820Sjeff * copyright notice, this list of conditions and the following 16219820Sjeff * disclaimer. 17219820Sjeff * 18219820Sjeff * - Redistributions in binary form must reproduce the above 19219820Sjeff * copyright notice, this list of conditions and the following 20219820Sjeff * disclaimer in the documentation and/or other materials 21219820Sjeff * provided with the distribution. 22219820Sjeff * 23219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30219820Sjeff * SOFTWARE. 31219820Sjeff */ 32219820Sjeff 33219820Sjeff#include <linux/module.h> 34219820Sjeff 35219820Sjeff#include <linux/init.h> 36219820Sjeff#include <linux/slab.h> 37219820Sjeff#include <linux/seq_file.h> 38219820Sjeff 39219820Sjeff#include <asm/uaccess.h> 40219820Sjeff 41219820Sjeff#include "ipoib.h" 42219820Sjeff 43219820Sjeffstatic ssize_t show_parent(struct device *d, struct device_attribute *attr, 44219820Sjeff char *buf) 45219820Sjeff{ 46219820Sjeff struct ifnet *dev = to_net_dev(d); 47219820Sjeff struct ipoib_dev_priv *priv = dev->if_softc; 48219820Sjeff 49219820Sjeff return sprintf(buf, "%s\n", priv->parent->name); 50219820Sjeff} 51219820Sjeffstatic DEVICE_ATTR(parent, S_IRUGO, show_parent, NULL); 52219820Sjeff 53219820Sjeffint ipoib_vlan_add(struct ifnet *pdev, unsigned short pkey) 54219820Sjeff{ 55219820Sjeff struct ipoib_dev_priv *ppriv, *priv; 56219820Sjeff char intf_name[IFNAMSIZ]; 57219820Sjeff int result; 58219820Sjeff 59219820Sjeff if (!capable(CAP_NET_ADMIN)) 60219820Sjeff return -EPERM; 61219820Sjeff 62219820Sjeff ppriv = pdev->if_softc; 63219820Sjeff 64219820Sjeff rtnl_lock(); 65219820Sjeff mutex_lock(&ppriv->vlan_mutex); 66219820Sjeff 67219820Sjeff /* 68219820Sjeff * First ensure this isn't a duplicate. We check the parent device and 69219820Sjeff * then all of the child interfaces to make sure the Pkey doesn't match. 70219820Sjeff */ 71219820Sjeff if (ppriv->pkey == pkey) { 72219820Sjeff result = -ENOTUNIQ; 73219820Sjeff priv = NULL; 74219820Sjeff goto err; 75219820Sjeff } 76219820Sjeff 77219820Sjeff list_for_each_entry(priv, &ppriv->child_intfs, list) { 78219820Sjeff if (priv->pkey == pkey) { 79219820Sjeff result = -ENOTUNIQ; 80219820Sjeff priv = NULL; 81219820Sjeff goto err; 82219820Sjeff } 83219820Sjeff } 84219820Sjeff 85219820Sjeff snprintf(intf_name, sizeof intf_name, "%s.%04x", 86219820Sjeff ppriv->dev->name, pkey); 87219820Sjeff priv = ipoib_intf_alloc(intf_name); 88219820Sjeff if (!priv) { 89219820Sjeff result = -ENOMEM; 90219820Sjeff goto err; 91219820Sjeff } 92219820Sjeff 93219820Sjeff priv->max_ib_mtu = ppriv->max_ib_mtu; 94219820Sjeff /* MTU will be reset when mcast join happens */ 95219820Sjeff priv->dev->mtu = IPOIB_UD_MTU(priv->max_ib_mtu); 96219820Sjeff priv->mcast_mtu = priv->admin_mtu = priv->dev->mtu; 97219820Sjeff set_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags); 98219820Sjeff 99219820Sjeff result = ipoib_set_dev_features(priv, ppriv->ca); 100219820Sjeff if (result) 101219820Sjeff goto err; 102219820Sjeff 103219820Sjeff priv->pkey = pkey; 104219820Sjeff 105219820Sjeff memcpy(IF_LLADDR(priv->dev), ppriv->dev->dev_addr, INFINIBAND_ALEN); 106219820Sjeff priv->broadcastaddr[8] = pkey >> 8; 107219820Sjeff priv->broadcastaddr[9] = pkey & 0xff; 108219820Sjeff 109219820Sjeff result = ipoib_dev_init(priv->dev, ppriv->ca, ppriv->port); 110219820Sjeff if (result < 0) { 111219820Sjeff ipoib_warn(ppriv, "failed to initialize subinterface: " 112219820Sjeff "device %s, port %d", 113219820Sjeff ppriv->ca->name, ppriv->port); 114219820Sjeff goto err; 115219820Sjeff } 116219820Sjeff 117219820Sjeff result = register_netdevice(priv->dev); 118219820Sjeff if (result) { 119219820Sjeff ipoib_warn(priv, "failed to initialize; error %i", result); 120219820Sjeff goto register_failed; 121219820Sjeff } 122219820Sjeff 123219820Sjeff priv->parent = ppriv->dev; 124219820Sjeff 125219820Sjeff ipoib_create_debug_files(priv->dev); 126219820Sjeff 127219820Sjeff if (ipoib_cm_add_mode_attr(priv->dev)) 128219820Sjeff goto sysfs_failed; 129219820Sjeff if (ipoib_add_pkey_attr(priv->dev)) 130219820Sjeff goto sysfs_failed; 131219820Sjeff if (ipoib_add_umcast_attr(priv->dev)) 132219820Sjeff goto sysfs_failed; 133219820Sjeff 134219820Sjeff if (device_create_file(&priv->dev->dev, &dev_attr_parent)) 135219820Sjeff goto sysfs_failed; 136219820Sjeff 137219820Sjeff list_add_tail(&priv->list, &ppriv->child_intfs); 138219820Sjeff 139219820Sjeff mutex_unlock(&ppriv->vlan_mutex); 140219820Sjeff rtnl_unlock(); 141219820Sjeff 142219820Sjeff return 0; 143219820Sjeff 144219820Sjeffsysfs_failed: 145219820Sjeff ipoib_delete_debug_files(priv->dev); 146219820Sjeff unregister_netdevice(priv->dev); 147219820Sjeff 148219820Sjeffregister_failed: 149219820Sjeff ipoib_dev_cleanup(priv->dev); 150219820Sjeff 151219820Sjefferr: 152219820Sjeff mutex_unlock(&ppriv->vlan_mutex); 153219820Sjeff rtnl_unlock(); 154219820Sjeff if (priv) 155219820Sjeff free_netdev(priv->dev); 156219820Sjeff 157219820Sjeff return result; 158219820Sjeff} 159219820Sjeff 160219820Sjeffint ipoib_vlan_delete(struct ifnet *pdev, unsigned short pkey) 161219820Sjeff{ 162219820Sjeff struct ipoib_dev_priv *ppriv, *priv, *tpriv; 163219820Sjeff struct ifnet *dev = NULL; 164219820Sjeff 165219820Sjeff if (!capable(CAP_NET_ADMIN)) 166219820Sjeff return -EPERM; 167219820Sjeff 168219820Sjeff ppriv = pdev->if_softc; 169219820Sjeff 170219820Sjeff rtnl_lock(); 171219820Sjeff mutex_lock(&ppriv->vlan_mutex); 172219820Sjeff list_for_each_entry_safe(priv, tpriv, &ppriv->child_intfs, list) { 173219820Sjeff if (priv->pkey == pkey) { 174219820Sjeff unregister_netdevice(priv->dev); 175219820Sjeff ipoib_dev_cleanup(priv->dev); 176219820Sjeff list_del(&priv->list); 177219820Sjeff dev = priv->dev; 178219820Sjeff break; 179219820Sjeff } 180219820Sjeff } 181219820Sjeff mutex_unlock(&ppriv->vlan_mutex); 182219820Sjeff rtnl_unlock(); 183219820Sjeff 184219820Sjeff if (dev) { 185219820Sjeff free_netdev(dev); 186219820Sjeff return 0; 187219820Sjeff } 188219820Sjeff 189219820Sjeff return -ENODEV; 190219820Sjeff} 191