Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 87de87d5 authored by David S. Miller's avatar David S. Miller
Browse files

wext: Dispatch and handle compat ioctls entirely in net/wireless/wext.c



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: default avatarDavid S. Miller <davem@davemloft.net>
parent a67fa76d
Loading
Loading
Loading
Loading
+0 −6
Original line number Diff line number Diff line
@@ -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;
+13 −0
Original line number Diff line number Diff line
@@ -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
+7 −0
Original line number Diff line number Diff line
@@ -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)
{
@@ -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 −0
Original line number Diff line number Diff line
@@ -90,6 +90,7 @@
#include <asm/unistd.h>

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

#include <net/sock.h>
#include <linux/netfilter.h>
@@ -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
+104 −0
Original line number Diff line number Diff line
@@ -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.