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

Commit d88174e4 authored by David S. Miller's avatar David S. Miller Committed by David S. Miller
Browse files

wext: Extract private call iw_point handling into seperate functions.

parent 84149b0f
Loading
Loading
Loading
Loading
+74 −67
Original line number Diff line number Diff line
@@ -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,72 +930,82 @@ static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr,
				extra_size = 0;
		}
	}
	*descrp = descr;
	return extra_size;
}

	/* 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 {
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)) {
			/* Check NULL pointer */
			if ((iwr->u.data.pointer == NULL) &&
			   (iwr->u.data.length != 0))
		if (!iwp->pointer && iwp->length != 0)
			return -EFAULT;

			/* Does it fits within bounds ? */
			if (iwr->u.data.length > (descr->set_args &
						 IW_PRIV_SIZE_MASK))
		if (iwp->length > (descr->set_args & IW_PRIV_SIZE_MASK))
			return -E2BIG;
		} else if (iwr->u.data.pointer == NULL)
	} else if (!iwp->pointer)
		return -EFAULT;

		/* Always allocate for max space. Easier, and won't last
		 * long... */
	extra = kmalloc(extra_size, GFP_KERNEL);
		if (extra == NULL)
	if (!extra)
		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;
	if (IW_IS_SET(cmd) && (iwp->length != 0)) {
		if (copy_from_user(extra, iwp->pointer, extra_size)) {
			err = -EFAULT;
			goto out;
		}
	}

	/* Call the handler */
		ret = handler(dev, &info, &(iwr->u), extra);
	err = handler(dev, info, (union iwreq_data *) iwp, extra);

	/* If we have something to return to the user */
		if (!ret && IW_IS_GET(cmd)) {

	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,
							      &(iwr->u.data));
			}
		 * avoid leaking kernel bits outside.
		 */
		if (!(descr->get_args & IW_PRIV_SIZE_FIXED))
			extra_size = adjust_priv_size(descr->get_args, iwp);

			err = copy_to_user(iwr->u.data.pointer, extra,
					   extra_size);
			if (err)
				ret =  -EFAULT;
		if (copy_to_user(iwp->pointer, extra, extra_size))
			err =  -EFAULT;
	}

		/* Cleanup - I told you it wasn't that long ;-) */
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;
	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 {
		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)