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
|
* a iw_handler but process it in your ioctl handler (i.e. use the
|
||||||
* old driver API).
|
* old driver API).
|
||||||
*/
|
*/
|
||||||
static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr,
|
static int get_priv_descr_and_size(struct net_device *dev, unsigned int cmd,
|
||||||
unsigned int cmd, iw_handler handler)
|
const struct iw_priv_args **descrp)
|
||||||
{
|
{
|
||||||
struct iwreq * iwr = (struct iwreq *) ifr;
|
const struct iw_priv_args *descr;
|
||||||
const struct iw_priv_args * descr = NULL;
|
int i, extra_size;
|
||||||
struct iw_request_info info;
|
|
||||||
int extra_size = 0;
|
|
||||||
int i;
|
|
||||||
int ret = -EINVAL;
|
|
||||||
|
|
||||||
/* Get the description of the IOCTL */
|
descr = NULL;
|
||||||
for (i = 0; i < dev->wireless_handlers->num_private_args; i++)
|
for (i = 0; i < dev->wireless_handlers->num_private_args; i++) {
|
||||||
if (cmd == dev->wireless_handlers->private_args[i].cmd) {
|
if (cmd == dev->wireless_handlers->private_args[i].cmd) {
|
||||||
descr = &(dev->wireless_handlers->private_args[i]);
|
descr = &dev->wireless_handlers->private_args[i];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Compute the size of the set/get arguments */
|
extra_size = 0;
|
||||||
if (descr != NULL) {
|
if (descr) {
|
||||||
if (IW_IS_SET(cmd)) {
|
if (IW_IS_SET(cmd)) {
|
||||||
int offset = 0; /* For sub-ioctls */
|
int offset = 0; /* For sub-ioctls */
|
||||||
/* Check for sub-ioctl handler */
|
/* Check for sub-ioctl handler */
|
||||||
|
@ -933,6 +930,69 @@ static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr,
|
||||||
extra_size = 0;
|
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 */
|
/* Prepare the call */
|
||||||
info.cmd = cmd;
|
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 */
|
/* No extra arguments. Trivial to handle */
|
||||||
ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u));
|
ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u));
|
||||||
} else {
|
} else {
|
||||||
char * extra;
|
ret = ioctl_private_iw_point(&iwr->u.data, cmd, descr,
|
||||||
int err;
|
handler, dev, &info, extra_size);
|
||||||
|
|
||||||
/* 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Call commit handler if needed and defined */
|
/* Call commit handler if needed and defined */
|
||||||
if (ret == -EIWCOMMIT)
|
if (ret == -EIWCOMMIT)
|
||||||
ret = call_commit_handler(dev);
|
ret = call_commit_handler(dev);
|
||||||
|
|
Loading…
Reference in a new issue