Esempio n. 1
0
/*********************************************************************************************************
** 函数名称: ioctl_private_iw_point
** 功能描述: ioctl priv call
** 输 入  : 
** 输 出  : OK or ERROR
** 全局变量:
** 调用模块:
*********************************************************************************************************/
int ioctl_private_call (struct netif *dev, struct iwreq *iwr,
                        unsigned int cmd, struct iw_request_info *info,
                        iw_handler handler)
{
    int extra_size = 0, ret = -EINVAL;
    const struct iw_priv_args *descr;

    extra_size = get_priv_descr_and_size(dev, cmd, &descr);

    /* 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) {
        ret = call_commit_handler(dev);
    }

    return  (ret);
}
Esempio n. 2
0
/*
 * Wrapper to call a standard Wireless Extension handler.
 * We do various checks and also take care of moving data between
 * user space and kernel space.
 */
static int ioctl_standard_call(struct net_device *	dev,
			       struct iwreq		*iwr,
			       unsigned int		cmd,
			       struct iw_request_info	*info,
			       iw_handler		handler)
{
	const struct iw_ioctl_description *	descr;
	int					ret = -EINVAL;

	/* Get the description of the IOCTL */
	if ((cmd - SIOCIWFIRST) >= standard_ioctl_num)
		return -EOPNOTSUPP;
	descr = &(standard_ioctl[cmd - SIOCIWFIRST]);

	/* Check if we have a pointer to user space data or not */
	if (descr->header_type != IW_HEADER_TYPE_POINT) {

		/* No extra arguments. Trivial to handle */
		ret = handler(dev, info, &(iwr->u), NULL);

		/* Generate an event to notify listeners of the change */
		if ((descr->flags & IW_DESCR_FLAG_EVENT) &&
		   ((ret == 0) || (ret == -EIWCOMMIT)))
			wireless_send_event(dev, cmd, &(iwr->u), NULL);
	} else {
		ret = ioctl_standard_iw_point(&iwr->u.data, cmd, descr,
					      handler, dev, info);
	}

	/* Call commit handler if needed and defined */
	if (ret == -EIWCOMMIT)
		ret = call_commit_handler(dev);

	/* Here, we will generate the appropriate event if needed */

	return ret;
}
Esempio n. 3
0
int compat_private_call(struct net_device *dev, struct iwreq *iwr,
			unsigned int cmd, struct iw_request_info *info,
			iw_handler handler)
{
	const struct iw_priv_args *descr;
	int ret, extra_size;

	extra_size = get_priv_descr_and_size(dev, cmd, &descr);

	/* 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;
}
Esempio n. 4
0
/*
 * Wrapper to call a private Wireless Extension handler.
 * We do various checks and also take care of moving data between
 * user space and kernel space.
 * It's not as nice and slimline as the standard wrapper. The cause
 * is struct iw_priv_args, which was not really designed for the
 * job we are going here.
 *
 * IMPORTANT : This function prevent to set and get data on the same
 * IOCTL and enforce the SET/GET convention. Not doing it would be
 * far too hairy...
 * If you need to set and get data at the same time, please don't use
 * a iw_handler but process it in your ioctl handler (i.e. use the
 * old driver API).
 */
static inline int ioctl_private_call(struct net_device *	dev,
				     struct ifreq *		ifr,
				     unsigned int		cmd,
				     iw_handler		handler)
{
	struct iwreq *			iwr = (struct iwreq *) ifr;
	struct iw_priv_args *		descr = NULL;
	struct iw_request_info		info;
	int				extra_size = 0;
	int				i;
	int				ret = -EINVAL;

	/* Get the description of the IOCTL */
	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]);
			break;
		}

#ifdef WE_IOCTL_DEBUG
	printk(KERN_DEBUG "%s (WE) : Found private handler for 0x%04X\n",
	       ifr->ifr_name, cmd);
	if(descr) {
		printk(KERN_DEBUG "%s (WE) : Name %s, set %X, get %X\n",
		       dev->name, descr->name,
		       descr->set_args, descr->get_args);
	}
#endif	/* WE_IOCTL_DEBUG */

	/* Compute the size of the set/get arguments */
	if(descr != NULL) {
		if(IW_IS_SET(cmd)) {
			int	offset = 0;	/* For sub-ioctls */
			/* Check for sub-ioctl handler */
			if(descr->name[0] == '\0')
				/* Reserve one int for sub-ioctl index */
				offset = sizeof(__u32);

			/* Size of set arguments */
			extra_size = get_priv_size(descr->set_args);

			/* Does it fits in iwr ? */
			if((descr->set_args & IW_PRIV_SIZE_FIXED) &&
			   ((extra_size + offset) <= IFNAMSIZ))
				extra_size = 0;
		} else {
			/* Size of set arguments */
			extra_size = get_priv_size(descr->get_args);

			/* Does it fits in iwr ? */
			if((descr->get_args & IW_PRIV_SIZE_FIXED) &&
			   (extra_size <= IFNAMSIZ))
				extra_size = 0;
		}
	}

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

#ifdef WE_IOCTL_DEBUG
		printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n",
		       dev->name, extra_size);
#endif	/* WE_IOCTL_DEBUG */

		/* 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;
			}
#ifdef WE_IOCTL_DEBUG
			printk(KERN_DEBUG "%s (WE) : Got %d elem\n",
			       dev->name, iwr->u.data.length);
#endif	/* WE_IOCTL_DEBUG */
		}

		/* 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)) {
			err = copy_to_user(iwr->u.data.pointer, extra,
					   extra_size);
			if (err)
				ret =  -EFAULT;				   
#ifdef WE_IOCTL_DEBUG
			printk(KERN_DEBUG "%s (WE) : Wrote %d elem\n",
			       dev->name, iwr->u.data.length);
#endif	/* WE_IOCTL_DEBUG */
		}

		/* Cleanup - I told you it wasn't that long ;-) */
		kfree(extra);
	}


	/* Call commit handler if needed and defined */
	if(ret == -EIWCOMMIT)
		ret = call_commit_handler(dev);

	return ret;
}
Esempio n. 5
0
/*
 * Wrapper to call a standard Wireless Extension handler.
 * We do various checks and also take care of moving data between
 * user space and kernel space.
 */
static inline int ioctl_standard_call(struct net_device *	dev,
				      struct ifreq *		ifr,
				      unsigned int		cmd,
				      iw_handler		handler)
{
	struct iwreq *				iwr = (struct iwreq *) ifr;
	const struct iw_ioctl_description *	descr;
	struct iw_request_info			info;
	int					ret = -EINVAL;
	int					user_size = 0;

	/* Get the description of the IOCTL */
	if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
		return -EOPNOTSUPP;
	descr = &(standard_ioctl[cmd - SIOCIWFIRST]);

#ifdef WE_IOCTL_DEBUG
	printk(KERN_DEBUG "%s (WE) : Found standard handler for 0x%04X\n",
	       ifr->ifr_name, cmd);
	printk(KERN_DEBUG "%s (WE) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
#endif	/* WE_IOCTL_DEBUG */

	/* Prepare the call */
	info.cmd = cmd;
	info.flags = 0;

	/* Check if we have a pointer to user space data or not */
	if(descr->header_type != IW_HEADER_TYPE_POINT) {

		/* No extra arguments. Trivial to handle */
		ret = handler(dev, &info, &(iwr->u), NULL);

#ifdef WE_SET_EVENT
		/* Generate an event to notify listeners of the change */
		if((descr->flags & IW_DESCR_FLAG_EVENT) &&
		   ((ret == 0) || (ret == -EIWCOMMIT)))
			wireless_send_event(dev, cmd, &(iwr->u), NULL);
#endif	/* WE_SET_EVENT */
	} 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;
			/* Check if number of token fits within bounds */
			if(iwr->u.data.length > descr->max_tokens)
				return -E2BIG;
			if(iwr->u.data.length < descr->min_tokens)
				return -EINVAL;
		} else {
			/* Check NULL pointer */
			if(iwr->u.data.pointer == NULL)
				return -EFAULT;
			/* Save user space buffer size for checking */
			user_size = iwr->u.data.length;
		}

#ifdef WE_IOCTL_DEBUG
		printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n",
		       dev->name, descr->max_tokens * descr->token_size);
#endif	/* WE_IOCTL_DEBUG */

		/* Always allocate for max space. Easier, and won't last
		 * long... */
		extra = kmalloc(descr->max_tokens * descr->token_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,
					     iwr->u.data.length *
					     descr->token_size);
			if (err) {
				kfree(extra);
				return -EFAULT;
			}
#ifdef WE_IOCTL_DEBUG
			printk(KERN_DEBUG "%s (WE) : Got %d bytes\n",
			       dev->name,
			       iwr->u.data.length * descr->token_size);
#endif	/* WE_IOCTL_DEBUG */
		}

		/* 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)) {
#ifdef WE_STRICT_WRITE
			/* Check if there is enough buffer up there */
			if(user_size < iwr->u.data.length) {
				printk(KERN_ERR "%s (WE) : Buffer for request %04X too small (%d<%d)\n", dev->name, cmd, user_size, iwr->u.data.length);
				kfree(extra);
				return -E2BIG;
			}
#endif	/* WE_STRICT_WRITE */

			err = copy_to_user(iwr->u.data.pointer, extra,
					   iwr->u.data.length *
					   descr->token_size);
			if (err)
				ret =  -EFAULT;				   
#ifdef WE_IOCTL_DEBUG
			printk(KERN_DEBUG "%s (WE) : Wrote %d bytes\n",
			       dev->name,
			       iwr->u.data.length * descr->token_size);
#endif	/* WE_IOCTL_DEBUG */
		}

#ifdef WE_SET_EVENT
		/* Generate an event to notify listeners of the change */
		if((descr->flags & IW_DESCR_FLAG_EVENT) &&
		   ((ret == 0) || (ret == -EIWCOMMIT))) {
			if(descr->flags & IW_DESCR_FLAG_RESTRICT)
				/* If the event is restricted, don't
				 * export the payload */
				wireless_send_event(dev, cmd, &(iwr->u), NULL);
			else
				wireless_send_event(dev, cmd, &(iwr->u),
						    extra);
		}
#endif	/* WE_SET_EVENT */

		/* Cleanup - I told you it wasn't that long ;-) */
		kfree(extra);
	}

	/* Call commit handler if needed and defined */
	if(ret == -EIWCOMMIT)
		ret = call_commit_handler(dev);

	/* Here, we will generate the appropriate event if needed */

	return ret;
}
Esempio n. 6
0
/*
 * Wrapper to call a standard Wireless Extension handler.
 * We do various checks and also take care of moving data between
 * user space and kernel space.
 */
static int ioctl_standard_call(struct net_device *	dev,
			       struct ifreq *		ifr,
			       unsigned int		cmd,
			       iw_handler		handler)
{
	struct iwreq *				iwr = (struct iwreq *) ifr;
	const struct iw_ioctl_description *	descr;
	struct iw_request_info			info;
	int					ret = -EINVAL;

	/* Get the description of the IOCTL */
	if ((cmd - SIOCIWFIRST) >= standard_ioctl_num)
		return -EOPNOTSUPP;
	descr = &(standard_ioctl[cmd - SIOCIWFIRST]);

	/* Prepare the call */
	info.cmd = cmd;
	info.flags = 0;

	/* Check if we have a pointer to user space data or not */
	if (descr->header_type != IW_HEADER_TYPE_POINT) {

		/* No extra arguments. Trivial to handle */
		ret = handler(dev, &info, &(iwr->u), NULL);

		/* Generate an event to notify listeners of the change */
		if ((descr->flags & IW_DESCR_FLAG_EVENT) &&
		   ((ret == 0) || (ret == -EIWCOMMIT)))
			wireless_send_event(dev, cmd, &(iwr->u), NULL);
	} else {
		char *	extra;
		int	extra_size;
		int	user_length = 0;
		int	err;
		int	essid_compat = 0;

		/* Calculate space needed by arguments. Always allocate
		 * for max space. Easier, and won't last long... */
		extra_size = descr->max_tokens * descr->token_size;

		/* Check need for ESSID compatibility for WE < 21 */
		switch (cmd) {
		case SIOCSIWESSID:
		case SIOCGIWESSID:
		case SIOCSIWNICKN:
		case SIOCGIWNICKN:
			if (iwr->u.data.length == descr->max_tokens + 1)
				essid_compat = 1;
			else if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
				char essid[IW_ESSID_MAX_SIZE + 1];

				err = copy_from_user(essid, iwr->u.data.pointer,
						     iwr->u.data.length *
						     descr->token_size);
				if (err)
					return -EFAULT;

				if (essid[iwr->u.data.length - 1] == '\0')
					essid_compat = 1;
			}
			break;
		default:
			break;
		}

		iwr->u.data.length -= essid_compat;

		/* 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;
			/* Check if number of token fits within bounds */
			if (iwr->u.data.length > descr->max_tokens)
				return -E2BIG;
			if (iwr->u.data.length < descr->min_tokens)
				return -EINVAL;
		} else {
			/* Check NULL pointer */
			if (iwr->u.data.pointer == NULL)
				return -EFAULT;
			/* Save user space buffer size for checking */
			user_length = iwr->u.data.length;

			/* Don't check if user_length > max to allow forward
			 * compatibility. The test user_length < min is
			 * implied by the test at the end. */

			/* Support for very large requests */
			if ((descr->flags & IW_DESCR_FLAG_NOMAX) &&
			   (user_length > descr->max_tokens)) {
				/* Allow userspace to GET more than max so
				 * we can support any size GET requests.
				 * There is still a limit : -ENOMEM. */
				extra_size = user_length * descr->token_size;
				/* Note : user_length is originally a __u16,
				 * and token_size is controlled by us,
				 * so extra_size won't get negative and
				 * won't overflow... */
			}
		}

		/* Create the kernel buffer */
		/*    kzalloc ensures NULL-termination for essid_compat */
		extra = kzalloc(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,
					     iwr->u.data.length *
					     descr->token_size);
			if (err) {
				kfree(extra);
				return -EFAULT;
			}
		}

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

		iwr->u.data.length += essid_compat;

		/* If we have something to return to the user */
		if (!ret && IW_IS_GET(cmd)) {
			/* Check if there is enough buffer up there */
			if (user_length < iwr->u.data.length) {
				kfree(extra);
				return -E2BIG;
			}

			err = copy_to_user(iwr->u.data.pointer, extra,
					   iwr->u.data.length *
					   descr->token_size);
			if (err)
				ret =  -EFAULT;
		}

		/* Generate an event to notify listeners of the change */
		if ((descr->flags & IW_DESCR_FLAG_EVENT) &&
		   ((ret == 0) || (ret == -EIWCOMMIT))) {
			if (descr->flags & IW_DESCR_FLAG_RESTRICT)
				/* If the event is restricted, don't
				 * export the payload */
				wireless_send_event(dev, cmd, &(iwr->u), NULL);
			else
				wireless_send_event(dev, cmd, &(iwr->u),
						    extra);
		}

		/* Cleanup - I told you it wasn't that long ;-) */
		kfree(extra);
	}

	/* Call commit handler if needed and defined */
	if (ret == -EIWCOMMIT)
		ret = call_commit_handler(dev);

	/* Here, we will generate the appropriate event if needed */

	return ret;
}
Esempio n. 7
0
/*
 * Wrapper to call a standard Wireless Extension handler.
 * We do various checks and also take care of moving data between
 * user space and kernel space.
 */
static inline int ioctl_standard_call(struct net_device *	dev,
                                      struct ifreq *		ifr,
                                      unsigned int		cmd,
                                      iw_handler		handler)
{
    struct iwreq *				iwr = (struct iwreq *) ifr;
    const struct iw_ioctl_description *	descr;
    struct iw_request_info			info;
    int					ret = -EINVAL;

    /* Get the description of the IOCTL */
    descr = &(standard_ioctl[cmd - SIOCIWFIRST]);

#ifdef WE_IOCTL_DEBUG
    printk(KERN_DEBUG "%s : Found standard handler for 0x%04X\n",
           ifr->ifr_name, cmd);
    printk(KERN_DEBUG "Header type : %d, token type : %d, token_size : %d, max_token : %d\n", descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
#endif	/* WE_IOCTL_DEBUG */

    /* Prepare the call */
    info.cmd = cmd;
    info.flags = 0;

    /* Check if we have a pointer to user space data or not */
    if(descr->header_type != IW_HEADER_TYPE_POINT) {
        /* No extra arguments. Trivial to handle */
        ret = handler(dev, &info, &(iwr->u), NULL);
    } 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;
            /* Check if number of token fits within bounds */
            if(iwr->u.data.length > descr->max_tokens)
                return -E2BIG;
            if(iwr->u.data.length < descr->min_tokens)
                return -EINVAL;
        } else {
            /* Check NULL pointer */
            if(iwr->u.data.pointer == NULL)
                return -EFAULT;
#ifdef WE_STRICT_WRITE
            /* Check if there is enough buffer up there */
            if(iwr->u.data.length < descr->max_tokens)
                return -E2BIG;
#endif	/* WE_STRICT_WRITE */
        }

#ifdef WE_IOCTL_DEBUG
        printk(KERN_DEBUG "Malloc %d bytes\n",
               descr->max_tokens * descr->token_size);
#endif	/* WE_IOCTL_DEBUG */

        /* Always allocate for max space. Easier, and won't last
         * long... */
        extra = kmalloc(descr->max_tokens * descr->token_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,
                                 iwr->u.data.length *
                                 descr->token_size);
            if (err) {
                kfree(extra);
                return -EFAULT;
            }
#ifdef WE_IOCTL_DEBUG
            printk(KERN_DEBUG "Got %d bytes\n",
                   iwr->u.data.length * descr->token_size);
#endif	/* WE_IOCTL_DEBUG */
        }

        /* 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)) {
            err = copy_to_user(iwr->u.data.pointer, extra,
                               iwr->u.data.length *
                               descr->token_size);
            if (err)
                ret =  -EFAULT;
#ifdef WE_IOCTL_DEBUG
            printk(KERN_DEBUG "Wrote %d bytes\n",
                   iwr->u.data.length * descr->token_size);
#endif	/* WE_IOCTL_DEBUG */
        }

        /* Cleanup - I told you it wasn't that long ;-) */
        kfree(extra);
    }

    /* Call commit handler if needed and defined */
    if(ret == -EIWCOMMIT)
        ret = call_commit_handler(dev);

    /* Here, we will generate the appropriate event if needed */

    return ret;
}