wext: Create IW_REQUEST_FLAG_COMPAT and set it as needed.

Now low-level WEXT ioctl handlers can do compat handling
when necessary.

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2008-06-03 07:39:16 -07:00
parent 169a3ec492
commit 0f5cabba49
2 changed files with 34 additions and 41 deletions

View file

@ -256,7 +256,7 @@
#define EIWCOMMIT EINPROGRESS #define EIWCOMMIT EINPROGRESS
/* Flags available in struct iw_request_info */ /* Flags available in struct iw_request_info */
#define IW_REQUEST_FLAG_NONE 0x0000 /* No flag so far */ #define IW_REQUEST_FLAG_COMPAT 0x0001 /* Compat ioctl call */
/* Type of headers we know about (basically union iwreq_data) */ /* Type of headers we know about (basically union iwreq_data) */
#define IW_HEADER_TYPE_NULL 0 /* Not available */ #define IW_HEADER_TYPE_NULL 0 /* Not available */

View file

@ -834,10 +834,10 @@ out:
static int ioctl_standard_call(struct net_device * dev, static int ioctl_standard_call(struct net_device * dev,
struct iwreq *iwr, struct iwreq *iwr,
unsigned int cmd, unsigned int cmd,
struct iw_request_info *info,
iw_handler handler) iw_handler handler)
{ {
const struct iw_ioctl_description * descr; const struct iw_ioctl_description * descr;
struct iw_request_info info;
int ret = -EINVAL; int ret = -EINVAL;
/* Get the description of the IOCTL */ /* Get the description of the IOCTL */
@ -845,15 +845,11 @@ static int ioctl_standard_call(struct net_device * dev,
return -EOPNOTSUPP; return -EOPNOTSUPP;
descr = &(standard_ioctl[cmd - SIOCIWFIRST]); 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 */ /* Check if we have a pointer to user space data or not */
if (descr->header_type != IW_HEADER_TYPE_POINT) { if (descr->header_type != IW_HEADER_TYPE_POINT) {
/* No extra arguments. Trivial to handle */ /* 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 */ /* Generate an event to notify listeners of the change */
if ((descr->flags & IW_DESCR_FLAG_EVENT) && if ((descr->flags & IW_DESCR_FLAG_EVENT) &&
@ -861,7 +857,7 @@ static int ioctl_standard_call(struct net_device * dev,
wireless_send_event(dev, cmd, &(iwr->u), NULL); wireless_send_event(dev, cmd, &(iwr->u), NULL);
} else { } else {
ret = ioctl_standard_iw_point(&iwr->u.data, cmd, descr, ret = ioctl_standard_iw_point(&iwr->u.data, cmd, descr,
handler, dev, &info); handler, dev, info);
} }
/* Call commit handler if needed and defined */ /* Call commit handler if needed and defined */
@ -984,25 +980,21 @@ out:
} }
static int ioctl_private_call(struct net_device *dev, struct iwreq *iwr, 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; int extra_size = 0, ret = -EINVAL;
const struct iw_priv_args *descr; const struct iw_priv_args *descr;
struct iw_request_info info;
extra_size = get_priv_descr_and_size(dev, cmd, &descr); 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. */ /* Check if we have a pointer to user space data or not. */
if (extra_size == 0) { if (extra_size == 0) {
/* 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 {
ret = ioctl_private_iw_point(&iwr->u.data, cmd, descr, 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 */ /* Call commit handler if needed and defined */
@ -1014,7 +1006,8 @@ static int ioctl_private_call(struct net_device *dev, struct iwreq *iwr,
/* ---------------------------------------------------------------- */ /* ---------------------------------------------------------------- */
typedef int (*wext_ioctl_func)(struct net_device *, struct iwreq *, 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. * Main IOCTl dispatcher.
@ -1022,6 +1015,7 @@ typedef int (*wext_ioctl_func)(struct net_device *, struct iwreq *,
*/ */
static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, static int wireless_process_ioctl(struct net *net, struct ifreq *ifr,
unsigned int cmd, unsigned int cmd,
struct iw_request_info *info,
wext_ioctl_func standard, wext_ioctl_func standard,
wext_ioctl_func private) wext_ioctl_func private)
{ {
@ -1040,11 +1034,11 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr,
* Note that 'cmd' is already filtered in dev_ioctl() with * Note that 'cmd' is already filtered in dev_ioctl() with
* (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */ * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */
if (cmd == SIOCGIWSTATS) if (cmd == SIOCGIWSTATS)
return standard(dev, iwr, cmd, return standard(dev, iwr, cmd, info,
&iw_handler_get_iwstats); &iw_handler_get_iwstats);
if (cmd == SIOCGIWPRIV && dev->wireless_handlers) if (cmd == SIOCGIWPRIV && dev->wireless_handlers)
return standard(dev, iwr, cmd, return standard(dev, iwr, cmd, info,
&iw_handler_get_private); &iw_handler_get_private);
/* Basic check */ /* Basic check */
@ -1056,9 +1050,9 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr,
if (handler) { if (handler) {
/* Standard and private are not the same */ /* Standard and private are not the same */
if (cmd < SIOCIWFIRSTPRIV) if (cmd < SIOCIWFIRSTPRIV)
return standard(dev, iwr, cmd, handler); return standard(dev, iwr, cmd, info, handler);
else else
return private(dev, iwr, cmd, handler); return private(dev, iwr, cmd, info, handler);
} }
/* Old driver API : call driver ioctl handler */ /* Old driver API : call driver ioctl handler */
if (dev->do_ioctl) if (dev->do_ioctl)
@ -1080,7 +1074,7 @@ static int wext_permission_check(unsigned int cmd)
/* entry point from dev ioctl */ /* entry point from dev ioctl */
static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr, static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr,
unsigned int cmd, unsigned int cmd, struct iw_request_info *info,
wext_ioctl_func standard, wext_ioctl_func standard,
wext_ioctl_func private) wext_ioctl_func private)
{ {
@ -1091,7 +1085,7 @@ static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr,
dev_load(net, ifr->ifr_name); dev_load(net, ifr->ifr_name);
rtnl_lock(); rtnl_lock();
ret = wireless_process_ioctl(net, ifr, cmd, standard, private); ret = wireless_process_ioctl(net, ifr, cmd, info, standard, private);
rtnl_unlock(); rtnl_unlock();
return ret; return ret;
@ -1100,10 +1094,12 @@ static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr,
int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
void __user *arg) void __user *arg)
{ {
int ret = wext_ioctl_dispatch(net, ifr, cmd, struct iw_request_info info = { .cmd = cmd, .flags = 0 };
ioctl_standard_call, int ret;
ioctl_private_call);
ret = wext_ioctl_dispatch(net, ifr, cmd, &info,
ioctl_standard_call,
ioctl_private_call);
if (ret >= 0 && if (ret >= 0 &&
IW_IS_GET(cmd) && IW_IS_GET(cmd) &&
copy_to_user(arg, ifr, sizeof(struct iwreq))) copy_to_user(arg, ifr, sizeof(struct iwreq)))
@ -1116,28 +1112,25 @@ int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
static int compat_standard_call(struct net_device *dev, static int compat_standard_call(struct net_device *dev,
struct iwreq *iwr, struct iwreq *iwr,
unsigned int cmd, unsigned int cmd,
struct iw_request_info *info,
iw_handler handler) iw_handler handler)
{ {
const struct iw_ioctl_description *descr; const struct iw_ioctl_description *descr;
struct compat_iw_point *iwp_compat; struct compat_iw_point *iwp_compat;
struct iw_request_info info;
struct iw_point iwp; struct iw_point iwp;
int err; int err;
descr = standard_ioctl + (cmd - SIOCIWFIRST); descr = standard_ioctl + (cmd - SIOCIWFIRST);
if (descr->header_type != IW_HEADER_TYPE_POINT) if (descr->header_type != IW_HEADER_TYPE_POINT)
return ioctl_standard_call(dev, iwr, cmd, handler); return ioctl_standard_call(dev, iwr, cmd, info, handler);
iwp_compat = (struct compat_iw_point *) &iwr->u.data; iwp_compat = (struct compat_iw_point *) &iwr->u.data;
iwp.pointer = compat_ptr(iwp_compat->pointer); iwp.pointer = compat_ptr(iwp_compat->pointer);
iwp.length = iwp_compat->length; iwp.length = iwp_compat->length;
iwp.flags = iwp_compat->flags; iwp.flags = iwp_compat->flags;
info.cmd = cmd; err = ioctl_standard_iw_point(&iwp, cmd, descr, handler, dev, info);
info.flags = 0;
err = ioctl_standard_iw_point(&iwp, cmd, descr, handler, dev, &info);
iwp_compat->pointer = ptr_to_compat(iwp.pointer); iwp_compat->pointer = ptr_to_compat(iwp.pointer);
iwp_compat->length = iwp.length; iwp_compat->length = iwp.length;
@ -1147,22 +1140,18 @@ static int compat_standard_call(struct net_device *dev,
} }
static int compat_private_call(struct net_device *dev, struct iwreq *iwr, static int compat_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)
{ {
const struct iw_priv_args *descr; const struct iw_priv_args *descr;
struct iw_request_info info;
int ret, extra_size; int ret, extra_size;
extra_size = get_priv_descr_and_size(dev, cmd, &descr); 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. */ /* Check if we have a pointer to user space data or not. */
if (extra_size == 0) { if (extra_size == 0) {
/* 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 {
struct compat_iw_point *iwp_compat; struct compat_iw_point *iwp_compat;
struct iw_point iwp; struct iw_point iwp;
@ -1173,7 +1162,7 @@ static int compat_private_call(struct net_device *dev, struct iwreq *iwr,
iwp.flags = iwp_compat->flags; iwp.flags = iwp_compat->flags;
ret = ioctl_private_iw_point(&iwp, cmd, descr, ret = ioctl_private_iw_point(&iwp, cmd, descr,
handler, dev, &info, extra_size); handler, dev, info, extra_size);
iwp_compat->pointer = ptr_to_compat(iwp.pointer); iwp_compat->pointer = ptr_to_compat(iwp.pointer);
iwp_compat->length = iwp.length; iwp_compat->length = iwp.length;
@ -1191,6 +1180,7 @@ int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
unsigned long arg) unsigned long arg)
{ {
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
struct iw_request_info info;
struct iwreq iwr; struct iwreq iwr;
char *colon; char *colon;
int ret; int ret;
@ -1203,7 +1193,10 @@ int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
if (colon) if (colon)
*colon = 0; *colon = 0;
ret = wext_ioctl_dispatch(net, (struct ifreq *) &iwr, cmd, info.cmd = cmd;
info.flags = IW_REQUEST_FLAG_COMPAT;
ret = wext_ioctl_dispatch(net, (struct ifreq *) &iwr, cmd, &info,
compat_standard_call, compat_standard_call,
compat_private_call); compat_private_call);