Skip to content

Commit

Permalink
wext: Dispatch and handle compat ioctls entirely in net/wireless/wext.c
Browse files Browse the repository at this point in the history
Next we can kill the hacks in fs/compat_ioctl.c and also
dispatch compat ioctls down into the driver and 80211 protocol
helper layers in order to handle iw_point objects embedded in
stream replies which need to be translated.

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Jun 17, 2008
1 parent a67fa76 commit 87de87d
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 6 deletions.
6 changes: 0 additions & 6 deletions fs/compat_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -1757,12 +1757,6 @@ static int do_i2c_smbus_ioctl(unsigned int fd, unsigned int cmd, unsigned long a
return sys_ioctl(fd, cmd, (unsigned long)tdata);
}

struct compat_iw_point {
compat_caddr_t pointer;
__u16 length;
__u16 flags;
};

static int do_wireless_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
{
struct iwreq __user *iwr;
Expand Down
13 changes: 13 additions & 0 deletions include/linux/wireless.h
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,19 @@ struct iw_point
__u16 flags; /* Optional params */
};

#ifdef __KERNEL__
#ifdef CONFIG_COMPAT

#include <linux/compat.h>

struct compat_iw_point {
compat_caddr_t pointer;
__u16 length;
__u16 flags;
};
#endif
#endif

/*
* A frequency
* For numbers lower than 10^9, we encode the number in 'm' and
Expand Down
7 changes: 7 additions & 0 deletions include/net/wext.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ extern int wext_proc_init(struct net *net);
extern void wext_proc_exit(struct net *net);
extern int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
void __user *arg);
extern int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
unsigned long arg);
#else
static inline int wext_proc_init(struct net *net)
{
Expand All @@ -26,6 +28,11 @@ static inline int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned
{
return -EINVAL;
}
static inline int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
unsigned long arg)
{
return -EINVAL;
}
#endif

#endif /* __NET_WEXT_H */
10 changes: 10 additions & 0 deletions net/socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
#include <asm/unistd.h>

#include <net/compat.h>
#include <net/wext.h>

#include <net/sock.h>
#include <linux/netfilter.h>
Expand Down Expand Up @@ -2210,10 +2211,19 @@ static long compat_sock_ioctl(struct file *file, unsigned cmd,
{
struct socket *sock = file->private_data;
int ret = -ENOIOCTLCMD;
struct sock *sk;
struct net *net;

sk = sock->sk;
net = sock_net(sk);

if (sock->ops->compat_ioctl)
ret = sock->ops->compat_ioctl(sock, cmd, arg);

if (ret == -ENOIOCTLCMD &&
(cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST))
ret = compat_wext_handle_ioctl(net, cmd, arg);

return ret;
}
#endif
Expand Down
104 changes: 104 additions & 0 deletions net/wireless/wext.c
Original file line number Diff line number Diff line change
Expand Up @@ -1112,6 +1112,110 @@ int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
return ret;
}

#ifdef CONFIG_COMPAT
static int compat_standard_call(struct net_device *dev,
struct iwreq *iwr,
unsigned int cmd,
iw_handler handler)
{
const struct iw_ioctl_description *descr;
struct compat_iw_point *iwp_compat;
struct iw_request_info info;
struct iw_point iwp;
int err;

descr = standard_ioctl + (cmd - SIOCIWFIRST);

if (descr->header_type != IW_HEADER_TYPE_POINT)
return ioctl_standard_call(dev, iwr, cmd, handler);

iwp_compat = (struct compat_iw_point *) &iwr->u.data;
iwp.pointer = compat_ptr(iwp_compat->pointer);
iwp.length = iwp_compat->length;
iwp.flags = iwp_compat->flags;

info.cmd = cmd;
info.flags = 0;

err = ioctl_standard_iw_point(&iwp, cmd, descr, handler, dev, &info);

iwp_compat->pointer = ptr_to_compat(iwp.pointer);
iwp_compat->length = iwp.length;
iwp_compat->flags = iwp.flags;

return err;
}

static int compat_private_call(struct net_device *dev, struct iwreq *iwr,
unsigned int cmd, iw_handler handler)
{
const struct iw_priv_args *descr;
struct iw_request_info info;
int ret, extra_size;

extra_size = get_priv_descr_and_size(dev, cmd, &descr);

/* Prepare the call */
info.cmd = cmd;
info.flags = 0;

/* Check if we have a pointer to user space data or not. */
if (extra_size == 0) {
/* No extra arguments. Trivial to handle */
ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u));
} else {
struct compat_iw_point *iwp_compat;
struct iw_point iwp;

iwp_compat = (struct compat_iw_point *) &iwr->u.data;
iwp.pointer = compat_ptr(iwp_compat->pointer);
iwp.length = iwp_compat->length;
iwp.flags = iwp_compat->flags;

ret = ioctl_private_iw_point(&iwp, cmd, descr,
handler, dev, &info, extra_size);

iwp_compat->pointer = ptr_to_compat(iwp.pointer);
iwp_compat->length = iwp.length;
iwp_compat->flags = iwp.flags;
}

/* Call commit handler if needed and defined */
if (ret == -EIWCOMMIT)
ret = call_commit_handler(dev);

return ret;
}

int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
unsigned long arg)
{
void __user *argp = (void __user *)arg;
struct iwreq iwr;
char *colon;
int ret;

if (copy_from_user(&iwr, argp, sizeof(struct iwreq)))
return -EFAULT;

iwr.ifr_name[IFNAMSIZ-1] = 0;
colon = strchr(iwr.ifr_name, ':');
if (colon)
*colon = 0;

ret = wext_ioctl_dispatch(net, (struct ifreq *) &iwr, cmd,
compat_standard_call,
compat_private_call);

if (ret >= 0 &&
IW_IS_GET(cmd) &&
copy_to_user(argp, &iwr, sizeof(struct iwreq)))
return -EFAULT;

return ret;
}
#endif

/************************* EVENT PROCESSING *************************/
/*
* Process events generated by the wireless layer or the driver.
Expand Down

0 comments on commit 87de87d

Please sign in to comment.