Skip to content

Commit

Permalink
[VLAN]: Convert name-based configuration functions to struct netdevice *
Browse files Browse the repository at this point in the history
Move the device lookup and checks to the ioctl handler under the RTNL and
change all name-based interfaces to take a struct net_device * instead.

This allows to use them from a netlink interface, which identifies devices
based on ifindex not name. It also avoids races between the ioctl interface
and the (upcoming) netlink interface since now all changes happen under the
RTNL.

As a nice side effect this greatly simplifies error handling in the helper
functions and fixes a number of incorrect error codes like -EINVAL for
device not found.

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Patrick McHardy authored and David S. Miller committed Jul 11, 2007
1 parent 9ba2cd6 commit c17d887
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 199 deletions.
153 changes: 64 additions & 89 deletions net/8021q/vlan.c
Original file line number Diff line number Diff line change
Expand Up @@ -278,43 +278,16 @@ static int unregister_vlan_dev(struct net_device *real_dev,
return ret;
}

static int unregister_vlan_device(const char *vlan_IF_name)
static int unregister_vlan_device(struct net_device *dev)
{
struct net_device *dev = NULL;
int ret;

ret = unregister_vlan_dev(VLAN_DEV_INFO(dev)->real_dev,
VLAN_DEV_INFO(dev)->vlan_id);
unregister_netdevice(dev);

dev = dev_get_by_name(vlan_IF_name);
ret = -EINVAL;
if (dev) {
if (dev->priv_flags & IFF_802_1Q_VLAN) {
rtnl_lock();

ret = unregister_vlan_dev(VLAN_DEV_INFO(dev)->real_dev,
VLAN_DEV_INFO(dev)->vlan_id);

dev_put(dev);
unregister_netdevice(dev);

rtnl_unlock();

if (ret == 1)
ret = 0;
} else {
printk(VLAN_ERR
"%s: ERROR: Tried to remove a non-vlan device "
"with VLAN code, name: %s priv_flags: %hX\n",
__FUNCTION__, dev->name, dev->priv_flags);
dev_put(dev);
ret = -EPERM;
}
} else {
#ifdef VLAN_DEBUG
printk(VLAN_DBG "%s: WARNING: Could not find dev.\n", __FUNCTION__);
#endif
ret = -EINVAL;
}

if (ret == 1)
ret = 0;
return ret;
}

Expand Down Expand Up @@ -378,12 +351,11 @@ static struct lock_class_key vlan_netdev_xmit_lock_key;
* Returns the device that was created, or NULL if there was
* an error of some kind.
*/
static struct net_device *register_vlan_device(const char *eth_IF_name,
static struct net_device *register_vlan_device(struct net_device *real_dev,
unsigned short VLAN_ID)
{
struct vlan_group *grp;
struct net_device *new_dev;
struct net_device *real_dev; /* the ethernet device */
char name[IFNAMSIZ];
int i;

Expand All @@ -395,46 +367,36 @@ static struct net_device *register_vlan_device(const char *eth_IF_name,
if (VLAN_ID >= VLAN_VID_MASK)
goto out_ret_null;

/* find the device relating to eth_IF_name. */
real_dev = dev_get_by_name(eth_IF_name);
if (!real_dev)
goto out_ret_null;

if (real_dev->features & NETIF_F_VLAN_CHALLENGED) {
printk(VLAN_DBG "%s: VLANs not supported on %s.\n",
__FUNCTION__, real_dev->name);
goto out_put_dev;
goto out_ret_null;
}

if ((real_dev->features & NETIF_F_HW_VLAN_RX) &&
!real_dev->vlan_rx_register) {
printk(VLAN_DBG "%s: Device %s has buggy VLAN hw accel.\n",
__FUNCTION__, real_dev->name);
goto out_put_dev;
goto out_ret_null;
}

if ((real_dev->features & NETIF_F_HW_VLAN_FILTER) &&
(!real_dev->vlan_rx_add_vid || !real_dev->vlan_rx_kill_vid)) {
printk(VLAN_DBG "%s: Device %s has buggy VLAN hw accel.\n",
__FUNCTION__, real_dev->name);
goto out_put_dev;
goto out_ret_null;
}

/* From this point on, all the data structures must remain
* consistent.
*/
rtnl_lock();

/* The real device must be up and operating in order to
* assosciate a VLAN device with it.
*/
if (!(real_dev->flags & IFF_UP))
goto out_unlock;
goto out_ret_null;

if (__find_vlan_dev(real_dev, VLAN_ID) != NULL) {
/* was already registered. */
printk(VLAN_DBG "%s: ALREADY had VLAN registered\n", __FUNCTION__);
goto out_unlock;
goto out_ret_null;
}

/* Gotta set up the fields for the device. */
Expand Down Expand Up @@ -471,7 +433,7 @@ static struct net_device *register_vlan_device(const char *eth_IF_name,
vlan_setup);

if (new_dev == NULL)
goto out_unlock;
goto out_ret_null;

#ifdef VLAN_DEBUG
printk(VLAN_DBG "Allocated new name -:%s:-\n", new_dev->name);
Expand Down Expand Up @@ -577,9 +539,8 @@ static struct net_device *register_vlan_device(const char *eth_IF_name,
if (real_dev->features & NETIF_F_HW_VLAN_FILTER)
real_dev->vlan_rx_add_vid(real_dev, VLAN_ID);

rtnl_unlock();


/* Account for reference in struct vlan_dev_info */
dev_hold(real_dev);
#ifdef VLAN_DEBUG
printk(VLAN_DBG "Allocated new device successfully, returning.\n");
#endif
Expand All @@ -590,17 +551,11 @@ static struct net_device *register_vlan_device(const char *eth_IF_name,

out_free_unregister:
unregister_netdev(new_dev);
goto out_unlock;
goto out_ret_null;

out_free_newdev:
free_netdev(new_dev);

out_unlock:
rtnl_unlock();

out_put_dev:
dev_put(real_dev);

out_ret_null:
return NULL;
}
Expand Down Expand Up @@ -693,9 +648,10 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
*/
static int vlan_ioctl_handler(void __user *arg)
{
int err = 0;
int err;
unsigned short vid = 0;
struct vlan_ioctl_args args;
struct net_device *dev = NULL;

if (copy_from_user(&args, arg, sizeof(struct vlan_ioctl_args)))
return -EFAULT;
Expand All @@ -708,35 +664,61 @@ static int vlan_ioctl_handler(void __user *arg)
printk(VLAN_DBG "%s: args.cmd: %x\n", __FUNCTION__, args.cmd);
#endif

rtnl_lock();

switch (args.cmd) {
case SET_VLAN_INGRESS_PRIORITY_CMD:
case SET_VLAN_EGRESS_PRIORITY_CMD:
case SET_VLAN_FLAG_CMD:
case ADD_VLAN_CMD:
case DEL_VLAN_CMD:
case GET_VLAN_REALDEV_NAME_CMD:
case GET_VLAN_VID_CMD:
err = -ENODEV;
dev = __dev_get_by_name(args.device1);
if (!dev)
goto out;

err = -EINVAL;
if (args.cmd != ADD_VLAN_CMD &&
!(dev->priv_flags & IFF_802_1Q_VLAN))
goto out;
}

switch (args.cmd) {
case SET_VLAN_INGRESS_PRIORITY_CMD:
err = -EPERM;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
err = vlan_dev_set_ingress_priority(args.device1,
args.u.skb_priority,
args.vlan_qos);
break;
vlan_dev_set_ingress_priority(dev,
args.u.skb_priority,
args.vlan_qos);
break;

case SET_VLAN_EGRESS_PRIORITY_CMD:
err = -EPERM;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
err = vlan_dev_set_egress_priority(args.device1,
break;
err = vlan_dev_set_egress_priority(dev,
args.u.skb_priority,
args.vlan_qos);
break;

case SET_VLAN_FLAG_CMD:
err = -EPERM;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
err = vlan_dev_set_vlan_flag(args.device1,
break;
err = vlan_dev_set_vlan_flag(dev,
args.u.flag,
args.vlan_qos);
break;

case SET_VLAN_NAME_TYPE_CMD:
err = -EPERM;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (args.u.name_type < VLAN_NAME_TYPE_HIGHEST) {
if ((args.u.name_type >= 0) &&
(args.u.name_type < VLAN_NAME_TYPE_HIGHEST)) {
vlan_name_type = args.u.name_type;
err = 0;
} else {
Expand All @@ -745,26 +727,21 @@ static int vlan_ioctl_handler(void __user *arg)
break;

case ADD_VLAN_CMD:
err = -EPERM;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
/* we have been given the name of the Ethernet Device we want to
* talk to: args.dev1 We also have the
* VLAN ID: args.u.VID
*/
if (register_vlan_device(args.device1, args.u.VID)) {
break;
if (register_vlan_device(dev, args.u.VID)) {
err = 0;
} else {
err = -EINVAL;
}
break;

case DEL_VLAN_CMD:
err = -EPERM;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
/* Here, the args.dev1 is the actual VLAN we want
* to get rid of.
*/
err = unregister_vlan_device(args.device1);
break;
err = unregister_vlan_device(dev);
break;

case GET_VLAN_INGRESS_PRIORITY_CMD:
Expand All @@ -788,19 +765,15 @@ static int vlan_ioctl_handler(void __user *arg)
err = -EINVAL;
break;
case GET_VLAN_REALDEV_NAME_CMD:
err = vlan_dev_get_realdev_name(args.device1, args.u.device2);
if (err)
goto out;
vlan_dev_get_realdev_name(dev, args.u.device2);
if (copy_to_user(arg, &args,
sizeof(struct vlan_ioctl_args))) {
err = -EFAULT;
}
break;

case GET_VLAN_VID_CMD:
err = vlan_dev_get_vid(args.device1, &vid);
if (err)
goto out;
vlan_dev_get_vid(dev, &vid);
args.u.VID = vid;
if (copy_to_user(arg, &args,
sizeof(struct vlan_ioctl_args))) {
Expand All @@ -812,9 +785,11 @@ static int vlan_ioctl_handler(void __user *arg)
/* pass on to underlying device instead?? */
printk(VLAN_DBG "%s: Unknown VLAN CMD: %x \n",
__FUNCTION__, args.cmd);
return -EINVAL;
err = -EINVAL;
break;
}
out:
rtnl_unlock();
return err;
}

Expand Down
13 changes: 8 additions & 5 deletions net/8021q/vlan.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,14 @@ int vlan_dev_set_mac_address(struct net_device *dev, void* addr);
int vlan_dev_open(struct net_device* dev);
int vlan_dev_stop(struct net_device* dev);
int vlan_dev_ioctl(struct net_device* dev, struct ifreq *ifr, int cmd);
int vlan_dev_set_ingress_priority(char* dev_name, __u32 skb_prio, short vlan_prio);
int vlan_dev_set_egress_priority(char* dev_name, __u32 skb_prio, short vlan_prio);
int vlan_dev_set_vlan_flag(char* dev_name, __u32 flag, short flag_val);
int vlan_dev_get_realdev_name(const char* dev_name, char* result);
int vlan_dev_get_vid(const char* dev_name, unsigned short* result);
void vlan_dev_set_ingress_priority(const struct net_device *dev,
u32 skb_prio, short vlan_prio);
int vlan_dev_set_egress_priority(const struct net_device *dev,
u32 skb_prio, short vlan_prio);
int vlan_dev_set_vlan_flag(const struct net_device *dev,
u32 flag, short flag_val);
void vlan_dev_get_realdev_name(const struct net_device *dev, char *result);
void vlan_dev_get_vid(const struct net_device *dev, unsigned short *result);
void vlan_dev_set_multicast_list(struct net_device *vlan_dev);

#endif /* !(__BEN_VLAN_802_1Q_INC__) */
Loading

0 comments on commit c17d887

Please sign in to comment.