wext: Extract private call iw_point handling into seperate functions.
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
84149b0fca
commit
d88174e4d2
1 changed files with 75 additions and 68 deletions
|
@ -890,25 +890,22 @@ static int ioctl_standard_call(struct net_device * dev,
|
|||
* a iw_handler but process it in your ioctl handler (i.e. use the
|
||||
* old driver API).
|
||||
*/
|
||||
static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr,
|
||||
unsigned int cmd, iw_handler handler)
|
||||
static int get_priv_descr_and_size(struct net_device *dev, unsigned int cmd,
|
||||
const struct iw_priv_args **descrp)
|
||||
{
|
||||
struct iwreq * iwr = (struct iwreq *) ifr;
|
||||
const struct iw_priv_args * descr = NULL;
|
||||
struct iw_request_info info;
|
||||
int extra_size = 0;
|
||||
int i;
|
||||
int ret = -EINVAL;
|
||||
const struct iw_priv_args *descr;
|
||||
int i, extra_size;
|
||||
|
||||
/* Get the description of the IOCTL */
|
||||
for (i = 0; i < dev->wireless_handlers->num_private_args; i++)
|
||||
descr = NULL;
|
||||
for (i = 0; i < dev->wireless_handlers->num_private_args; i++) {
|
||||
if (cmd == dev->wireless_handlers->private_args[i].cmd) {
|
||||
descr = &(dev->wireless_handlers->private_args[i]);
|
||||
descr = &dev->wireless_handlers->private_args[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Compute the size of the set/get arguments */
|
||||
if (descr != NULL) {
|
||||
extra_size = 0;
|
||||
if (descr) {
|
||||
if (IW_IS_SET(cmd)) {
|
||||
int offset = 0; /* For sub-ioctls */
|
||||
/* Check for sub-ioctl handler */
|
||||
|
@ -933,6 +930,69 @@ static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr,
|
|||
extra_size = 0;
|
||||
}
|
||||
}
|
||||
*descrp = descr;
|
||||
return extra_size;
|
||||
}
|
||||
|
||||
static int ioctl_private_iw_point(struct iw_point *iwp, unsigned int cmd,
|
||||
const struct iw_priv_args *descr,
|
||||
iw_handler handler, struct net_device *dev,
|
||||
struct iw_request_info *info, int extra_size)
|
||||
{
|
||||
char *extra;
|
||||
int err;
|
||||
|
||||
/* Check what user space is giving us */
|
||||
if (IW_IS_SET(cmd)) {
|
||||
if (!iwp->pointer && iwp->length != 0)
|
||||
return -EFAULT;
|
||||
|
||||
if (iwp->length > (descr->set_args & IW_PRIV_SIZE_MASK))
|
||||
return -E2BIG;
|
||||
} else if (!iwp->pointer)
|
||||
return -EFAULT;
|
||||
|
||||
extra = kmalloc(extra_size, GFP_KERNEL);
|
||||
if (!extra)
|
||||
return -ENOMEM;
|
||||
|
||||
/* If it is a SET, get all the extra data in here */
|
||||
if (IW_IS_SET(cmd) && (iwp->length != 0)) {
|
||||
if (copy_from_user(extra, iwp->pointer, extra_size)) {
|
||||
err = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Call the handler */
|
||||
err = handler(dev, info, (union iwreq_data *) iwp, extra);
|
||||
|
||||
/* If we have something to return to the user */
|
||||
if (!err && IW_IS_GET(cmd)) {
|
||||
/* Adjust for the actual length if it's variable,
|
||||
* avoid leaking kernel bits outside.
|
||||
*/
|
||||
if (!(descr->get_args & IW_PRIV_SIZE_FIXED))
|
||||
extra_size = adjust_priv_size(descr->get_args, iwp);
|
||||
|
||||
if (copy_to_user(iwp->pointer, extra, extra_size))
|
||||
err = -EFAULT;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(extra);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr,
|
||||
unsigned int cmd, iw_handler handler)
|
||||
{
|
||||
struct iwreq *iwr = (struct iwreq *) ifr;
|
||||
int extra_size = 0, ret = -EINVAL;
|
||||
const struct iw_priv_args *descr;
|
||||
struct iw_request_info info;
|
||||
|
||||
extra_size = get_priv_descr_and_size(dev, cmd, &descr);
|
||||
|
||||
/* Prepare the call */
|
||||
info.cmd = cmd;
|
||||
|
@ -943,63 +1003,10 @@ static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr,
|
|||
/* No extra arguments. Trivial to handle */
|
||||
ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u));
|
||||
} else {
|
||||
char * extra;
|
||||
int err;
|
||||
|
||||
/* Check what user space is giving us */
|
||||
if (IW_IS_SET(cmd)) {
|
||||
/* Check NULL pointer */
|
||||
if ((iwr->u.data.pointer == NULL) &&
|
||||
(iwr->u.data.length != 0))
|
||||
return -EFAULT;
|
||||
|
||||
/* Does it fits within bounds ? */
|
||||
if (iwr->u.data.length > (descr->set_args &
|
||||
IW_PRIV_SIZE_MASK))
|
||||
return -E2BIG;
|
||||
} else if (iwr->u.data.pointer == NULL)
|
||||
return -EFAULT;
|
||||
|
||||
/* Always allocate for max space. Easier, and won't last
|
||||
* long... */
|
||||
extra = kmalloc(extra_size, GFP_KERNEL);
|
||||
if (extra == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
/* If it is a SET, get all the extra data in here */
|
||||
if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
|
||||
err = copy_from_user(extra, iwr->u.data.pointer,
|
||||
extra_size);
|
||||
if (err) {
|
||||
kfree(extra);
|
||||
return -EFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
/* Call the handler */
|
||||
ret = handler(dev, &info, &(iwr->u), extra);
|
||||
|
||||
/* If we have something to return to the user */
|
||||
if (!ret && IW_IS_GET(cmd)) {
|
||||
|
||||
/* Adjust for the actual length if it's variable,
|
||||
* avoid leaking kernel bits outside. */
|
||||
if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) {
|
||||
extra_size = adjust_priv_size(descr->get_args,
|
||||
&(iwr->u.data));
|
||||
}
|
||||
|
||||
err = copy_to_user(iwr->u.data.pointer, extra,
|
||||
extra_size);
|
||||
if (err)
|
||||
ret = -EFAULT;
|
||||
}
|
||||
|
||||
/* Cleanup - I told you it wasn't that long ;-) */
|
||||
kfree(extra);
|
||||
ret = ioctl_private_iw_point(&iwr->u.data, cmd, descr,
|
||||
handler, dev, &info, extra_size);
|
||||
}
|
||||
|
||||
|
||||
/* Call commit handler if needed and defined */
|
||||
if (ret == -EIWCOMMIT)
|
||||
ret = call_commit_handler(dev);
|
||||
|
|
Loading…
Reference in a new issue