Beispiel #1
0
/*********************************************************************************************************
** 函数名称: ioctl_private_iw_point
** 功能描述: ioctl priv
** 输 入  : 
** 输 出  : OK or ERROR
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static int ioctl_private_iw_point (struct iw_point *iwp, unsigned int cmd,
                                   const struct iw_priv_args *descr,
                                   iw_handler handler, struct netif *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 = kzalloc(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);
}
Beispiel #2
0
/*********************************************************************************************************
** 函数名称: get_priv_descr_and_size
** 功能描述: Wrapper to call a private Wireless Extension handler.
** 输 入  : 
** 输 出  : OK or ERROR
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static int get_priv_descr_and_size (struct netif *dev, unsigned int cmd,
                                    const struct iw_priv_args **descrp)
{
    const struct iw_priv_args *descr;
    int i, extra_size;
    struct iw_handler_def *handlers = (struct iw_handler_def *)dev->wireless_handlers;
    
    if (!handlers) {
        return  (-EOPNOTSUPP);
    }

    descr = NULL;
    for (i = 0; i < handlers->num_private_args; i++) {
        if (cmd == handlers->private_args[i].cmd) {
            descr = &handlers->private_args[i];
            break;
        }
    }

    extra_size = 0;
    if (descr) {
        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 get 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;
            }
        }
    }
    
    *descrp = descr;
    return  (extra_size);
}
Beispiel #3
0
Datei: net.c Projekt: ctos/bpi
static io_return_t
device_set_status(void *d, dev_flavor_t flavor, dev_status_t status,
		  mach_msg_type_number_t count)
{
  if (flavor == NET_FLAGS)
    {
      if (count != 1)
        return D_INVALID_SIZE;

      short flags = status[0];
      struct net_data *net = (struct net_data *) d;

      dev_change_flags (net->dev, flags);

      /* Change the flags of the Mach device, too. */
      net->ifnet.if_flags = net->dev->flags;
      return D_SUCCESS;
    }

  if(flavor < SIOCIWFIRST || flavor > SIOCIWLAST)
    return D_INVALID_OPERATION;

  if(! IW_IS_SET(flavor))
    return D_INVALID_OPERATION;
  
  if(count * sizeof(int) < sizeof(struct ifreq))
    return D_INVALID_OPERATION;

  struct net_data *nd = d;
  struct linux_device *dev = nd->dev;

  if(! dev->do_ioctl)
    return D_INVALID_OPERATION;

  if((flavor == SIOCSIWENCODE || flavor == SIOCSIWESSID
      || flavor == SIOCSIWNICKN || flavor == SIOCSIWSPY)
     && ((struct iwreq *) status)->u.data.pointer)
    {
      struct iw_point *iwp = &((struct iwreq *) status)->u.data;

      /* safety check whether the status array is long enough ... */
      if(count * sizeof(int) < sizeof(struct ifreq) + iwp->length)
	return D_INVALID_OPERATION;

      /* make sure, iwp->pointer points to the correct address */
      if(iwp->pointer) iwp->pointer = (void *) status + sizeof(struct ifreq);
    }
  
  int result = dev->do_ioctl(dev, (struct ifreq *) status, flavor);
  return result ? D_IO_ERROR : D_SUCCESS;
}
Beispiel #4
0
/* entry point from dev ioctl */
int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
		      void __user *arg)
{
	int ret;

	/* If command is `set a parameter', or
	 * `get the encoding parameters', check if
	 * the user has the right to do it */
	if ((IW_IS_SET(cmd) || cmd == SIOCGIWENCODE || cmd == SIOCGIWENCODEEXT)
	    && !capable(CAP_NET_ADMIN))
		return -EPERM;

	dev_load(net, ifr->ifr_name);
	rtnl_lock();
	ret = wireless_process_ioctl(net, ifr, cmd);
	rtnl_unlock();
	if (IW_IS_GET(cmd) && copy_to_user(arg, ifr, sizeof(struct iwreq)))
		return -EFAULT;
	return ret;
}
static int ioctl_standard_iw_point(struct iw_point *iwp, unsigned int cmd,
				   const struct iw_ioctl_description *descr,
				   iw_handler handler, struct net_device *dev,
				   struct iw_request_info *info)
{
	int err, extra_size, user_length = 0, essid_compat = 0;
	char *extra;

	/* Calculate space needed by arguments. Always allocate
	 * for max space.
	 */
	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 (iwp->length == descr->max_tokens + 1)
			essid_compat = 1;
		else if (IW_IS_SET(cmd) && (iwp->length != 0)) {
			char essid[IW_ESSID_MAX_SIZE + 1];
			unsigned int len;
			len = iwp->length * descr->token_size;

			if (len > IW_ESSID_MAX_SIZE)
				return -EFAULT;

			err = copy_from_user(essid, iwp->pointer, len);
			if (err)
				return -EFAULT;

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

	iwp->length -= essid_compat;

	/* Check what user space is giving us */
	if (IW_IS_SET(cmd)) {
		/* Check NULL pointer */
		if (!iwp->pointer && iwp->length != 0)
			return -EFAULT;
		/* Check if number of token fits within bounds */
		if (iwp->length > descr->max_tokens)
			return -E2BIG;
		if (iwp->length < descr->min_tokens)
			return -EINVAL;
	} else {
		/* Check NULL pointer */
		if (!iwp->pointer)
			return -EFAULT;
		/* Save user space buffer size for checking */
		user_length = iwp->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...
			 */
		}
	}

	/* kzalloc() ensures NULL-termination for essid_compat. */
	extra = kzalloc(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,
				   iwp->length *
				   descr->token_size)) {
			err = -EFAULT;
			goto out;
		}

		if (cmd == SIOCSIWENCODEEXT) {
			struct iw_encode_ext *ee = (void *) extra;

			if (iwp->length < sizeof(*ee) + ee->key_len)
				return -EFAULT;
		}
	}

	if (IW_IS_GET(cmd) && !(descr->flags & IW_DESCR_FLAG_NOMAX)) {
		/*
		 * If this is a GET, but not NOMAX, it means that the extra
		 * data is not bounded by userspace, but by max_tokens. Thus
		 * set the length to max_tokens. This matches the extra data
		 * allocation.
		 * The driver should fill it with the number of tokens it
		 * provided, and it may check iwp->length rather than having
		 * knowledge of max_tokens. If the driver doesn't change the
		 * iwp->length, this ioctl just copies back max_token tokens
		 * filled with zeroes. Hopefully the driver isn't claiming
		 * them to be valid data.
		 */
		iwp->length = descr->max_tokens;
	}

	err = handler(dev, info, (union iwreq_data *) iwp, extra);

	iwp->length += essid_compat;

	/* If we have something to return to the user */
	if (!err && IW_IS_GET(cmd)) {
		/* Check if there is enough buffer up there */
		if (user_length < iwp->length) {
			err = -E2BIG;
			goto out;
		}

		if (copy_to_user(iwp->pointer, extra,
				 iwp->length *
				 descr->token_size)) {
			err = -EFAULT;
			goto out;
		}
	}

	/* Generate an event to notify listeners of the change */
	if ((descr->flags & IW_DESCR_FLAG_EVENT) &&
	    ((err == 0) || (err == -EIWCOMMIT))) {
		union iwreq_data *data = (union iwreq_data *) iwp;

		if (descr->flags & IW_DESCR_FLAG_RESTRICT)
			/* If the event is restricted, don't
			 * export the payload.
			 */
			wireless_send_event(dev, cmd, data, NULL);
		else
			wireless_send_event(dev, cmd, data, extra);
	}

out:
	kfree(extra);
	return err;
}
Beispiel #6
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;
}
Beispiel #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;
	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;
}
Beispiel #8
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;
}
Beispiel #9
0
/* ---------------------------------------------------------------- */
static int ioctl_standard_iw_point(struct iw_point *iwp, unsigned int cmd,
				   const struct iw_ioctl_description *descr,
				   iw_handler handler, struct net_device *dev,
				   struct iw_request_info *info)
{
	int err, extra_size, user_length = 0;
	char *extra;

	/* Calculate space needed by arguments. Always allocate
	 * for max space.
	 */
	extra_size = descr->max_tokens * descr->token_size;

	/* Check what user space is giving us */
	if (IW_IS_SET(cmd)) {
		/* Check NULL pointer */
		if (!iwp->pointer && iwp->length != 0)
			return -EFAULT;
		/* Check if number of token fits within bounds */
		if (iwp->length > descr->max_tokens)
			return -E2BIG;
		if (iwp->length < descr->min_tokens)
			return -EINVAL;
	} else {
		/* Check NULL pointer */
		if (!iwp->pointer)
			return -EFAULT;
		/* Save user space buffer size for checking */
		user_length = iwp->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...
			 */
		}
	}

	extra = kzalloc(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,
				   iwp->length *
				   descr->token_size)) {
			err = -EFAULT;
			goto out;
		}

		if (cmd == SIOCSIWENCODEEXT) {
			struct iw_encode_ext *ee = (void *) extra;

			if (iwp->length < sizeof(*ee) + ee->key_len)
				return -EFAULT;
		}
	}

	err = handler(dev, info, (union iwreq_data *) iwp, extra);

	/* If we have something to return to the user */
	if (!err && IW_IS_GET(cmd)) {
		/* Check if there is enough buffer up there */
		if (user_length < iwp->length) {
			err = -E2BIG;
			goto out;
		}

		if (copy_to_user(iwp->pointer, extra,
				 iwp->length *
				 descr->token_size)) {
			err = -EFAULT;
			goto out;
		}
	}

	/* Generate an event to notify listeners of the change */
	if ((descr->flags & IW_DESCR_FLAG_EVENT) && err == -EIWCOMMIT) {
		union iwreq_data *data = (union iwreq_data *) iwp;

		if (descr->flags & IW_DESCR_FLAG_RESTRICT)
			/* If the event is restricted, don't
			 * export the payload.
			 */
			wireless_send_event(dev, cmd, data, NULL);
		else
			wireless_send_event(dev, cmd, data, extra);
	}

out:
	kfree(extra);
	return err;
}
Beispiel #10
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;
}
Beispiel #11
0
int dev_ioctl(unsigned int cmd, void *arg)
{
	switch(cmd) 
	{
		case SIOCGIFCONF:
			(void) dev_ifconf((char *) arg);
			return 0;

		/*
		 *	Ioctl calls that can be done by all.
		 */
		 
		case SIOCGIFFLAGS:
		case SIOCGIFADDR:
		case SIOCGIFDSTADDR:
		case SIOCGIFBRDADDR:
		case SIOCGIFNETMASK:
		case SIOCGIFMETRIC:
		case SIOCGIFMTU:
		case SIOCGIFMEM:
		case SIOCGIFHWADDR:
		case SIOCGIFSLAVE:
		case SIOCGIFMAP:
			return dev_ifsioc(arg, cmd);

		/*
		 *	Ioctl calls requiring the power of a superuser
		 */
		 
		case SIOCSIFFLAGS:
		case SIOCSIFADDR:
		case SIOCSIFDSTADDR:
		case SIOCSIFBRDADDR:
		case SIOCSIFNETMASK:
		case SIOCSIFMETRIC:
		case SIOCSIFMTU:
		case SIOCSIFMEM:
		case SIOCSIFHWADDR:
		case SIOCSIFMAP:
		case SIOCSIFSLAVE:
		case SIOCADDMULTI:
		case SIOCDELMULTI:
			if (!suser())
				return -EPERM;
			return dev_ifsioc(arg, cmd);
	
		case SIOCSIFLINK:
			return -EINVAL;

		/*
		 *	Unknown or private ioctl.
		 */	
		 
		default:
			if((cmd >= SIOCDEVPRIVATE) &&
			   (cmd <= (SIOCDEVPRIVATE + 15))) {
				return dev_ifsioc(arg, cmd);
			}
#ifdef CONFIG_NET_RADIO
			if((cmd >= SIOCIWFIRST) &&
			   (cmd <= SIOCIWLAST))
			{
				if((IW_IS_SET(cmd)) && (!suser()))
					return -EPERM;
				return dev_ifsioc(arg, cmd);
			}
#endif	/* CONFIG_NET_RADIO */
			return -EINVAL;
	}
}