wext: Extract private call iw_point handling into seperate functions.
authorDavid S. Miller <davem@sunset.davemloft.net>
Fri, 21 Dec 2007 11:33:46 +0000 (03:33 -0800)
committerDavid S. Miller <davem@davemloft.net>
Tue, 17 Jun 2008 01:30:21 +0000 (18:30 -0700)
Signed-off-by: David S. Miller <davem@davemloft.net>
net/wireless/wext.c

index d17c0f45accb750910110bb5ae7a146b071120eb..a1cd19add6d8a9642eba9d5895a1ef11a8f00127 100644 (file)
@@ -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;
+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 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)) {
+               if (!iwp->pointer && iwp->length != 0)
+                       return -EFAULT;
 
-               /* 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;
+               if (iwp->length > (descr->set_args & IW_PRIV_SIZE_MASK))
+                       return -E2BIG;
+       } else if (!iwp->pointer)
+               return -EFAULT;
 
-                       /* Does it fits within bounds ? */
-                       if (iwr->u.data.length > (descr->set_args &
-                                                IW_PRIV_SIZE_MASK))
-                               return -E2BIG;
-               } else if (iwr->u.data.pointer == NULL)
-                       return -EFAULT;
+       extra = kmalloc(extra_size, GFP_KERNEL);
+       if (!extra)
+               return -ENOMEM;
 
-               /* 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;
-                       }
+       /* 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 */
-               ret = handler(dev, &info, &(iwr->u), extra);
+       /* Call the handler */
+       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 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);
 
-                       /* 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));
-                       }
+               if (copy_to_user(iwp->pointer, extra, extra_size))
+                       err =  -EFAULT;
+       }
 
-                       err = copy_to_user(iwr->u.data.pointer, extra,
-                                          extra_size);
-                       if (err)
-                               ret =  -EFAULT;
-               }
+out:
+       kfree(extra);
+       return err;
+}
 
-               /* Cleanup - I told you it wasn't that long ;-) */
-               kfree(extra);
-       }
+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)