Commit 5075405c authored by Stephen Hemminger's avatar Stephen Hemminger

[BRIDGE]: New ioctl interface for 32/64 compatability.

Add four new ioctl's for the operations that can't be done through sysfs.
The existing bridge ioctl's are multiplexed, and most go through SIOCDEVPRIVATE
so they won't work in a mixed 32/64bit environment.

The new release of bridge-utils will use these if possible, and fall
back to the old interface.
parent 3d702922
......@@ -104,7 +104,7 @@ struct __fdb_entry
#include <linux/netdevice.h>
extern void brioctl_set(int (*ioctl_hook)(unsigned long));
extern void brioctl_set(int (*ioctl_hook)(unsigned int, unsigned long));
extern int (*br_handle_frame_hook)(struct sk_buff *skb);
extern int (*br_should_route_hook)(struct sk_buff **pskb);
......
......@@ -116,6 +116,12 @@
#define SIOCBONDINFOQUERY 0x8994 /* rtn info about bond state */
#define SIOCBONDCHANGEACTIVE 0x8995 /* update to a new active slave */
/* bridge calls */
#define SIOCBRADDBR 0x89a0 /* create new bridge device */
#define SIOCBRDELBR 0x89a1 /* remove bridge device */
#define SIOCBRADDIF 0x89a2 /* add interface to bridge */
#define SIOCBRDELIF 0x89a3 /* remove interface from bridge */
/* Device private ioctl calls */
/*
......
......@@ -78,13 +78,36 @@ static int get_fdb_entries(struct net_bridge *br, void __user *userbuf,
return num;
}
int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
static int add_del_if(struct net_bridge *br, int ifindex, int isadd)
{
struct net_device *dev;
int ret;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
dev = dev_get_by_index(ifindex);
if (dev == NULL)
return -EINVAL;
if (isadd)
ret = br_add_if(br, dev);
else
ret = br_del_if(br, dev);
dev_put(dev);
return ret;
}
/*
* Legacy ioctl's through SIOCDEVPRIVATE
* This interface is deprecated because it was too difficult to
* to do the translation for 32/64bit ioctl compatability.
*/
static int old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
struct net_bridge *br = netdev_priv(dev);
unsigned long args[4];
if (cmd != SIOCDEVPRIVATE)
return -EOPNOTSUPP;
if (copy_from_user(args, rq->ifr_data, sizeof(args)))
return -EFAULT;
......@@ -92,25 +115,7 @@ int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
switch (args[0]) {
case BRCTL_ADD_IF:
case BRCTL_DEL_IF:
{
struct net_device *dev;
int ret;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
dev = dev_get_by_index(args[1]);
if (dev == NULL)
return -EINVAL;
if (args[0] == BRCTL_ADD_IF)
ret = br_add_if(br, dev);
else
ret = br_del_if(br, dev);
dev_put(dev);
return ret;
}
return add_del_if(br, args[1], args[0] == BRCTL_ADD_IF);
case BRCTL_GET_BRIDGE_INFO:
{
......@@ -303,8 +308,7 @@ int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
return -EOPNOTSUPP;
}
int br_ioctl_deviceless_stub(unsigned long uarg)
static int old_deviceless(unsigned long uarg)
{
unsigned long args[3];
......@@ -356,3 +360,49 @@ int br_ioctl_deviceless_stub(unsigned long uarg)
return -EOPNOTSUPP;
}
int br_ioctl_deviceless_stub(unsigned int cmd, unsigned long uarg)
{
switch (cmd) {
case SIOCGIFBR:
case SIOCSIFBR:
return old_deviceless(uarg);
case SIOCBRADDBR:
case SIOCBRDELBR:
{
char buf[IFNAMSIZ];
if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (copy_from_user(buf, (void __user *) uarg, IFNAMSIZ))
return -EFAULT;
buf[IFNAMSIZ-1] = 0;
if (cmd == SIOCBRADDBR)
return br_add_bridge(buf);
return br_del_bridge(buf);
}
}
return -EOPNOTSUPP;
}
int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
struct net_bridge *br = netdev_priv(dev);
switch(cmd) {
case SIOCDEVPRIVATE:
return old_dev_ioctl(dev, rq, cmd);
case SIOCBRADDIF:
case SIOCBRDELIF:
return add_del_if(br, rq->ifr_ifindex, cmd == SIOCBRADDIF);
}
printk(KERN_DEBUG "Bridge does not support ioctl 0x%x\n", cmd);
return -EOPNOTSUPP;
}
......@@ -174,8 +174,8 @@ extern int br_handle_frame_finish(struct sk_buff *skb);
extern int br_handle_frame(struct sk_buff *skb);
/* br_ioctl.c */
extern int br_ioctl_deviceless_stub(unsigned long arg);
extern int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
extern int br_ioctl_deviceless_stub(unsigned int cmd, unsigned long arg);
/* br_netfilter.c */
extern int br_netfilter_init(void);
......
......@@ -2519,6 +2519,8 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd)
cmd == SIOCGMIIPHY ||
cmd == SIOCGMIIREG ||
cmd == SIOCSMIIREG ||
cmd == SIOCBRADDIF ||
cmd == SIOCBRDELIF ||
cmd == SIOCWANDEV) {
err = -EOPNOTSUPP;
if (dev->do_ioctl) {
......@@ -2673,6 +2675,8 @@ int dev_ioctl(unsigned int cmd, void __user *arg)
case SIOCBONDSLAVEINFOQUERY:
case SIOCBONDINFOQUERY:
case SIOCBONDCHANGEACTIVE:
case SIOCBRADDIF:
case SIOCBRDELIF:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
dev_load(ifr.ifr_name);
......
......@@ -729,9 +729,9 @@ static ssize_t sock_writev(struct file *file, const struct iovec *vector,
*/
static DECLARE_MUTEX(br_ioctl_mutex);
static int (*br_ioctl_hook)(unsigned long arg) = NULL;
static int (*br_ioctl_hook)(unsigned int cmd, unsigned long arg) = NULL;
void brioctl_set(int (*hook)(unsigned long))
void brioctl_set(int (*hook)(unsigned int, unsigned long))
{
down(&br_ioctl_mutex);
br_ioctl_hook = hook;
......@@ -796,13 +796,15 @@ static int sock_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
break;
case SIOCGIFBR:
case SIOCSIFBR:
case SIOCBRADDBR:
case SIOCBRDELBR:
err = -ENOPKG;
if (!br_ioctl_hook)
request_module("bridge");
down(&br_ioctl_mutex);
if (br_ioctl_hook)
err = br_ioctl_hook(arg);
err = br_ioctl_hook(cmd, arg);
up(&br_ioctl_mutex);
break;
case SIOCGIFVLAN:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment