13d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg/*
23d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg * This file implement the Wireless Extensions priv API.
33d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg *
43d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
53d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved.
63d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg * Copyright	2009 Johannes Berg <johannes@sipsolutions.net>
73d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg *
83d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg * (As all part of the Linux kernel, this file is GPL)
93d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg */
105a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
113d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg#include <linux/wireless.h>
123d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg#include <linux/netdevice.h>
133d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg#include <net/iw_handler.h>
143d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg#include <net/wext.h>
153d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
163d23e349d807177eaf519d444677cee86b1a04cfJohannes Bergint iw_handler_get_private(struct net_device *		dev,
173d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg			   struct iw_request_info *	info,
183d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg			   union iwreq_data *		wrqu,
193d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg			   char *			extra)
203d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg{
213d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	/* Check if the driver has something to export */
223d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	if ((dev->wireless_handlers->num_private_args == 0) ||
233d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	   (dev->wireless_handlers->private_args == NULL))
243d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		return -EOPNOTSUPP;
253d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
263d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	/* Check if there is enough buffer up there */
273d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	if (wrqu->data.length < dev->wireless_handlers->num_private_args) {
283d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		/* User space can't know in advance how large the buffer
293d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		 * needs to be. Give it a hint, so that we can support
303d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		 * any size buffer we want somewhat efficiently... */
313d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		wrqu->data.length = dev->wireless_handlers->num_private_args;
323d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		return -E2BIG;
333d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	}
343d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
353d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	/* Set the number of available ioctls. */
363d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	wrqu->data.length = dev->wireless_handlers->num_private_args;
373d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
383d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	/* Copy structure to the user buffer. */
393d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	memcpy(extra, dev->wireless_handlers->private_args,
403d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	       sizeof(struct iw_priv_args) * wrqu->data.length);
413d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
423d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	return 0;
433d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg}
443d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
453d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg/* Size (in bytes) of the various private data types */
463d23e349d807177eaf519d444677cee86b1a04cfJohannes Bergstatic const char iw_priv_type_size[] = {
473d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	0,				/* IW_PRIV_TYPE_NONE */
483d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	1,				/* IW_PRIV_TYPE_BYTE */
493d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	1,				/* IW_PRIV_TYPE_CHAR */
503d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	0,				/* Not defined */
513d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	sizeof(__u32),			/* IW_PRIV_TYPE_INT */
523d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	sizeof(struct iw_freq),		/* IW_PRIV_TYPE_FLOAT */
533d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	sizeof(struct sockaddr),	/* IW_PRIV_TYPE_ADDR */
543d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	0,				/* Not defined */
553d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg};
563d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
573d23e349d807177eaf519d444677cee86b1a04cfJohannes Bergstatic int get_priv_size(__u16 args)
583d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg{
593d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	int	num = args & IW_PRIV_SIZE_MASK;
603d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	int	type = (args & IW_PRIV_TYPE_MASK) >> 12;
613d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
623d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	return num * iw_priv_type_size[type];
633d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg}
643d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
653d23e349d807177eaf519d444677cee86b1a04cfJohannes Bergstatic int adjust_priv_size(__u16 args, struct iw_point *iwp)
663d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg{
673d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	int	num = iwp->length;
683d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	int	max = args & IW_PRIV_SIZE_MASK;
693d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	int	type = (args & IW_PRIV_TYPE_MASK) >> 12;
703d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
713d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	/* Make sure the driver doesn't goof up */
723d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	if (max < num)
733d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		num = max;
743d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
753d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	return num * iw_priv_type_size[type];
763d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg}
773d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
783d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg/*
793d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg * Wrapper to call a private Wireless Extension handler.
803d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg * We do various checks and also take care of moving data between
813d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg * user space and kernel space.
823d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg * It's not as nice and slimline as the standard wrapper. The cause
833d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg * is struct iw_priv_args, which was not really designed for the
843d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg * job we are going here.
853d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg *
863d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg * IMPORTANT : This function prevent to set and get data on the same
873d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg * IOCTL and enforce the SET/GET convention. Not doing it would be
883d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg * far too hairy...
893d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg * If you need to set and get data at the same time, please don't use
903d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg * a iw_handler but process it in your ioctl handler (i.e. use the
913d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg * old driver API).
923d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg */
933d23e349d807177eaf519d444677cee86b1a04cfJohannes Bergstatic int get_priv_descr_and_size(struct net_device *dev, unsigned int cmd,
943d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg				   const struct iw_priv_args **descrp)
953d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg{
963d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	const struct iw_priv_args *descr;
973d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	int i, extra_size;
983d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
993d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	descr = NULL;
1003d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	for (i = 0; i < dev->wireless_handlers->num_private_args; i++) {
1013d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		if (cmd == dev->wireless_handlers->private_args[i].cmd) {
1023d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg			descr = &dev->wireless_handlers->private_args[i];
1033d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg			break;
1043d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		}
1053d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	}
1063d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
1073d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	extra_size = 0;
1083d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	if (descr) {
1093d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		if (IW_IS_SET(cmd)) {
1103d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg			int	offset = 0;	/* For sub-ioctls */
1113d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg			/* Check for sub-ioctl handler */
1123d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg			if (descr->name[0] == '\0')
1133d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg				/* Reserve one int for sub-ioctl index */
1143d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg				offset = sizeof(__u32);
1153d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
1163d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg			/* Size of set arguments */
1173d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg			extra_size = get_priv_size(descr->set_args);
1183d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
1193d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg			/* Does it fits in iwr ? */
1203d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg			if ((descr->set_args & IW_PRIV_SIZE_FIXED) &&
1213d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg			   ((extra_size + offset) <= IFNAMSIZ))
1223d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg				extra_size = 0;
1233d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		} else {
1243d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg			/* Size of get arguments */
1253d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg			extra_size = get_priv_size(descr->get_args);
1263d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
1273d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg			/* Does it fits in iwr ? */
1283d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg			if ((descr->get_args & IW_PRIV_SIZE_FIXED) &&
1293d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg			   (extra_size <= IFNAMSIZ))
1303d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg				extra_size = 0;
1313d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		}
1323d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	}
1333d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	*descrp = descr;
1343d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	return extra_size;
1353d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg}
1363d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
1373d23e349d807177eaf519d444677cee86b1a04cfJohannes Bergstatic int ioctl_private_iw_point(struct iw_point *iwp, unsigned int cmd,
1383d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg				  const struct iw_priv_args *descr,
1393d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg				  iw_handler handler, struct net_device *dev,
1403d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg				  struct iw_request_info *info, int extra_size)
1413d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg{
1423d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	char *extra;
1433d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	int err;
1443d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
1453d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	/* Check what user space is giving us */
1463d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	if (IW_IS_SET(cmd)) {
1473d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		if (!iwp->pointer && iwp->length != 0)
1483d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg			return -EFAULT;
1493d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
1503d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		if (iwp->length > (descr->set_args & IW_PRIV_SIZE_MASK))
1513d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg			return -E2BIG;
1523d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	} else if (!iwp->pointer)
1533d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		return -EFAULT;
1543d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
155df6d02300f7c2fbd0fbe626d819c8e5237d72c62Johannes Berg	extra = kzalloc(extra_size, GFP_KERNEL);
1563d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	if (!extra)
1573d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		return -ENOMEM;
1583d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
1593d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	/* If it is a SET, get all the extra data in here */
1603d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	if (IW_IS_SET(cmd) && (iwp->length != 0)) {
1613d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		if (copy_from_user(extra, iwp->pointer, extra_size)) {
1623d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg			err = -EFAULT;
1633d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg			goto out;
1643d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		}
1653d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	}
1663d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
1673d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	/* Call the handler */
1683d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	err = handler(dev, info, (union iwreq_data *) iwp, extra);
1693d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
1703d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	/* If we have something to return to the user */
1713d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	if (!err && IW_IS_GET(cmd)) {
1723d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		/* Adjust for the actual length if it's variable,
1733d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		 * avoid leaking kernel bits outside.
1743d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		 */
1753d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		if (!(descr->get_args & IW_PRIV_SIZE_FIXED))
1763d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg			extra_size = adjust_priv_size(descr->get_args, iwp);
1773d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
1783d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		if (copy_to_user(iwp->pointer, extra, extra_size))
1793d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg			err =  -EFAULT;
1803d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	}
1813d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
1823d23e349d807177eaf519d444677cee86b1a04cfJohannes Bergout:
1833d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	kfree(extra);
1843d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	return err;
1853d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg}
1863d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
1873d23e349d807177eaf519d444677cee86b1a04cfJohannes Bergint ioctl_private_call(struct net_device *dev, struct iwreq *iwr,
1883d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		       unsigned int cmd, struct iw_request_info *info,
1893d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		       iw_handler handler)
1903d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg{
1913d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	int extra_size = 0, ret = -EINVAL;
1923d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	const struct iw_priv_args *descr;
1933d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
1943d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	extra_size = get_priv_descr_and_size(dev, cmd, &descr);
1953d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
1963d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	/* Check if we have a pointer to user space data or not. */
1973d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	if (extra_size == 0) {
1983d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		/* No extra arguments. Trivial to handle */
1993d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		ret = handler(dev, info, &(iwr->u), (char *) &(iwr->u));
2003d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	} else {
2013d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		ret = ioctl_private_iw_point(&iwr->u.data, cmd, descr,
2023d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg					     handler, dev, info, extra_size);
2033d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	}
2043d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
2053d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	/* Call commit handler if needed and defined */
2063d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	if (ret == -EIWCOMMIT)
2073d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		ret = call_commit_handler(dev);
2083d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
2093d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	return ret;
2103d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg}
2113d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
2123d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg#ifdef CONFIG_COMPAT
2133d23e349d807177eaf519d444677cee86b1a04cfJohannes Bergint compat_private_call(struct net_device *dev, struct iwreq *iwr,
2143d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg			unsigned int cmd, struct iw_request_info *info,
2153d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg			iw_handler handler)
2163d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg{
2173d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	const struct iw_priv_args *descr;
2183d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	int ret, extra_size;
2193d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
2203d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	extra_size = get_priv_descr_and_size(dev, cmd, &descr);
2213d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
2223d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	/* Check if we have a pointer to user space data or not. */
2233d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	if (extra_size == 0) {
2243d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		/* No extra arguments. Trivial to handle */
2253d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		ret = handler(dev, info, &(iwr->u), (char *) &(iwr->u));
2263d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	} else {
2273d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		struct compat_iw_point *iwp_compat;
2283d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		struct iw_point iwp;
2293d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
2303d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		iwp_compat = (struct compat_iw_point *) &iwr->u.data;
2313d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		iwp.pointer = compat_ptr(iwp_compat->pointer);
2323d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		iwp.length = iwp_compat->length;
2333d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		iwp.flags = iwp_compat->flags;
2343d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
2353d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		ret = ioctl_private_iw_point(&iwp, cmd, descr,
2363d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg					     handler, dev, info, extra_size);
2373d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
2383d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		iwp_compat->pointer = ptr_to_compat(iwp.pointer);
2393d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		iwp_compat->length = iwp.length;
2403d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		iwp_compat->flags = iwp.flags;
2413d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	}
2423d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
2433d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	/* Call commit handler if needed and defined */
2443d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	if (ret == -EIWCOMMIT)
2453d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg		ret = call_commit_handler(dev);
2463d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg
2473d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg	return ret;
2483d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg}
2493d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg#endif
250