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;
- struct iw_request_info info;
int ret = -EINVAL;
/* Get the description of the IOCTL */
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);
+ ret = handler(dev, info, &(iwr->u), NULL);
/* Generate an event to notify listeners of the change */
if ((descr->flags & IW_DESCR_FLAG_EVENT) &&
wireless_send_event(dev, cmd, &(iwr->u), NULL);
} else {
ret = ioctl_standard_iw_point(&iwr->u.data, cmd, descr,
- handler, dev, &info);
+ handler, dev, info);
}
/* Call commit handler if needed and defined */
}
static int ioctl_private_call(struct net_device *dev, struct iwreq *iwr,
- unsigned int cmd, iw_handler handler)
+ unsigned int cmd, struct iw_request_info *info,
+ iw_handler handler)
{
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));
+ 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);
+ handler, dev, info, extra_size);
}
/* Call commit handler if needed and defined */
/* ---------------------------------------------------------------- */
typedef int (*wext_ioctl_func)(struct net_device *, struct iwreq *,
- unsigned int, iw_handler);
+ unsigned int, struct iw_request_info *,
+ iw_handler);
/*
* Main IOCTl dispatcher.
*/
static int wireless_process_ioctl(struct net *net, struct ifreq *ifr,
unsigned int cmd,
+ struct iw_request_info *info,
wext_ioctl_func standard,
wext_ioctl_func private)
{
* Note that 'cmd' is already filtered in dev_ioctl() with
* (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */
if (cmd == SIOCGIWSTATS)
- return standard(dev, iwr, cmd,
+ return standard(dev, iwr, cmd, info,
&iw_handler_get_iwstats);
if (cmd == SIOCGIWPRIV && dev->wireless_handlers)
- return standard(dev, iwr, cmd,
+ return standard(dev, iwr, cmd, info,
&iw_handler_get_private);
/* Basic check */
if (handler) {
/* Standard and private are not the same */
if (cmd < SIOCIWFIRSTPRIV)
- return standard(dev, iwr, cmd, handler);
+ return standard(dev, iwr, cmd, info, handler);
else
- return private(dev, iwr, cmd, handler);
+ return private(dev, iwr, cmd, info, handler);
}
/* Old driver API : call driver ioctl handler */
if (dev->do_ioctl)
}
/* entry point from dev ioctl */
-int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
- void __user *arg)
+static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr,
+ unsigned int cmd, struct iw_request_info *info,
+ wext_ioctl_func standard,
+ wext_ioctl_func private)
{
int ret = wext_permission_check(cmd);
dev_load(net, ifr->ifr_name);
rtnl_lock();
- ret = wireless_process_ioctl(net, ifr, cmd,
- ioctl_standard_call,
- ioctl_private_call);
+ ret = wireless_process_ioctl(net, ifr, cmd, info, standard, private);
rtnl_unlock();
- if (IW_IS_GET(cmd) && copy_to_user(arg, ifr, sizeof(struct iwreq)))
+
+ return ret;
+}
+
+int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
+ void __user *arg)
+{
+ struct iw_request_info info = { .cmd = cmd, .flags = 0 };
+ int ret;
+
+ ret = wext_ioctl_dispatch(net, ifr, cmd, &info,
+ ioctl_standard_call,
+ ioctl_private_call);
+ if (ret >= 0 &&
+ IW_IS_GET(cmd) &&
+ copy_to_user(arg, ifr, sizeof(struct iwreq)))
return -EFAULT;
+
+ return ret;
+}
+
+#ifdef CONFIG_COMPAT
+static int compat_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;
+ struct compat_iw_point *iwp_compat;
+ struct iw_point iwp;
+ int err;
+
+ descr = standard_ioctl + (cmd - SIOCIWFIRST);
+
+ if (descr->header_type != IW_HEADER_TYPE_POINT)
+ return ioctl_standard_call(dev, iwr, cmd, info, handler);
+
+ 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;
+
+ err = ioctl_standard_iw_point(&iwp, cmd, descr, handler, dev, info);
+
+ iwp_compat->pointer = ptr_to_compat(iwp.pointer);
+ iwp_compat->length = iwp.length;
+ iwp_compat->flags = iwp.flags;
+
+ return err;
+}
+
+static 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;
+}
+
+int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
+ unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ struct iw_request_info info;
+ struct iwreq iwr;
+ char *colon;
+ int ret;
+
+ if (copy_from_user(&iwr, argp, sizeof(struct iwreq)))
+ return -EFAULT;
+
+ iwr.ifr_name[IFNAMSIZ-1] = 0;
+ colon = strchr(iwr.ifr_name, ':');
+ if (colon)
+ *colon = 0;
+
+ info.cmd = cmd;
+ info.flags = IW_REQUEST_FLAG_COMPAT;
+
+ ret = wext_ioctl_dispatch(net, (struct ifreq *) &iwr, cmd, &info,
+ compat_standard_call,
+ compat_private_call);
+
+ if (ret >= 0 &&
+ IW_IS_GET(cmd) &&
+ copy_to_user(argp, &iwr, sizeof(struct iwreq)))
+ return -EFAULT;
+
return ret;
}
+#endif
/************************* EVENT PROCESSING *************************/
/*
struct sk_buff *skb;
int err;
- if (dev_net(dev) != &init_net)
+ if (!net_eq(dev_net(dev), &init_net))
return;
skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);