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 ...@@ -104,7 +104,7 @@ struct __fdb_entry
#include <linux/netdevice.h> #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_handle_frame_hook)(struct sk_buff *skb);
extern int (*br_should_route_hook)(struct sk_buff **pskb); extern int (*br_should_route_hook)(struct sk_buff **pskb);
......
...@@ -116,6 +116,12 @@ ...@@ -116,6 +116,12 @@
#define SIOCBONDINFOQUERY 0x8994 /* rtn info about bond state */ #define SIOCBONDINFOQUERY 0x8994 /* rtn info about bond state */
#define SIOCBONDCHANGEACTIVE 0x8995 /* update to a new active slave */ #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 */ /* Device private ioctl calls */
/* /*
......
...@@ -78,13 +78,36 @@ static int get_fdb_entries(struct net_bridge *br, void __user *userbuf, ...@@ -78,13 +78,36 @@ static int get_fdb_entries(struct net_bridge *br, void __user *userbuf,
return num; 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); struct net_bridge *br = netdev_priv(dev);
unsigned long args[4]; unsigned long args[4];
if (cmd != SIOCDEVPRIVATE)
return -EOPNOTSUPP;
if (copy_from_user(args, rq->ifr_data, sizeof(args))) if (copy_from_user(args, rq->ifr_data, sizeof(args)))
return -EFAULT; return -EFAULT;
...@@ -92,25 +115,7 @@ int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ...@@ -92,25 +115,7 @@ int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
switch (args[0]) { switch (args[0]) {
case BRCTL_ADD_IF: case BRCTL_ADD_IF:
case BRCTL_DEL_IF: case BRCTL_DEL_IF:
{ return add_del_if(br, args[1], args[0] == BRCTL_ADD_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;
}
case BRCTL_GET_BRIDGE_INFO: case BRCTL_GET_BRIDGE_INFO:
{ {
...@@ -303,8 +308,7 @@ int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ...@@ -303,8 +308,7 @@ int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
static int old_deviceless(unsigned long uarg)
int br_ioctl_deviceless_stub(unsigned long uarg)
{ {
unsigned long args[3]; unsigned long args[3];
...@@ -356,3 +360,49 @@ int br_ioctl_deviceless_stub(unsigned long uarg) ...@@ -356,3 +360,49 @@ int br_ioctl_deviceless_stub(unsigned long uarg)
return -EOPNOTSUPP; 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); ...@@ -174,8 +174,8 @@ extern int br_handle_frame_finish(struct sk_buff *skb);
extern int br_handle_frame(struct sk_buff *skb); extern int br_handle_frame(struct sk_buff *skb);
/* br_ioctl.c */ /* 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_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 */ /* br_netfilter.c */
extern int br_netfilter_init(void); extern int br_netfilter_init(void);
......
...@@ -2519,6 +2519,8 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd) ...@@ -2519,6 +2519,8 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd)
cmd == SIOCGMIIPHY || cmd == SIOCGMIIPHY ||
cmd == SIOCGMIIREG || cmd == SIOCGMIIREG ||
cmd == SIOCSMIIREG || cmd == SIOCSMIIREG ||
cmd == SIOCBRADDIF ||
cmd == SIOCBRDELIF ||
cmd == SIOCWANDEV) { cmd == SIOCWANDEV) {
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
if (dev->do_ioctl) { if (dev->do_ioctl) {
...@@ -2673,6 +2675,8 @@ int dev_ioctl(unsigned int cmd, void __user *arg) ...@@ -2673,6 +2675,8 @@ int dev_ioctl(unsigned int cmd, void __user *arg)
case SIOCBONDSLAVEINFOQUERY: case SIOCBONDSLAVEINFOQUERY:
case SIOCBONDINFOQUERY: case SIOCBONDINFOQUERY:
case SIOCBONDCHANGEACTIVE: case SIOCBONDCHANGEACTIVE:
case SIOCBRADDIF:
case SIOCBRDELIF:
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN))
return -EPERM; return -EPERM;
dev_load(ifr.ifr_name); dev_load(ifr.ifr_name);
......
...@@ -729,9 +729,9 @@ static ssize_t sock_writev(struct file *file, const struct iovec *vector, ...@@ -729,9 +729,9 @@ static ssize_t sock_writev(struct file *file, const struct iovec *vector,
*/ */
static DECLARE_MUTEX(br_ioctl_mutex); 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); down(&br_ioctl_mutex);
br_ioctl_hook = hook; br_ioctl_hook = hook;
...@@ -796,13 +796,15 @@ static int sock_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -796,13 +796,15 @@ static int sock_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
break; break;
case SIOCGIFBR: case SIOCGIFBR:
case SIOCSIFBR: case SIOCSIFBR:
case SIOCBRADDBR:
case SIOCBRDELBR:
err = -ENOPKG; err = -ENOPKG;
if (!br_ioctl_hook) if (!br_ioctl_hook)
request_module("bridge"); request_module("bridge");
down(&br_ioctl_mutex); down(&br_ioctl_mutex);
if (br_ioctl_hook) if (br_ioctl_hook)
err = br_ioctl_hook(arg); err = br_ioctl_hook(cmd, arg);
up(&br_ioctl_mutex); up(&br_ioctl_mutex);
break; break;
case SIOCGIFVLAN: 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