aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/wireless/wext.c141
1 files changed, 74 insertions, 67 deletions
diff --git a/net/wireless/wext.c b/net/wireless/wext.c
index d17c0f45accb..a1cd19add6d8 100644
--- a/net/wireless/wext.c
+++ b/net/wireless/wext.c
@@ -890,25 +890,22 @@ static int ioctl_standard_call(struct net_device * dev,
890 * a iw_handler but process it in your ioctl handler (i.e. use the 890 * a iw_handler but process it in your ioctl handler (i.e. use the
891 * old driver API). 891 * old driver API).
892 */ 892 */
893static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr, 893static int get_priv_descr_and_size(struct net_device *dev, unsigned int cmd,
894 unsigned int cmd, iw_handler handler) 894 const struct iw_priv_args **descrp)
895{ 895{
896 struct iwreq * iwr = (struct iwreq *) ifr; 896 const struct iw_priv_args *descr;
897 const struct iw_priv_args * descr = NULL; 897 int i, extra_size;
898 struct iw_request_info info;
899 int extra_size = 0;
900 int i;
901 int ret = -EINVAL;
902 898
903 /* Get the description of the IOCTL */ 899 descr = NULL;
904 for (i = 0; i < dev->wireless_handlers->num_private_args; i++) 900 for (i = 0; i < dev->wireless_handlers->num_private_args; i++) {
905 if (cmd == dev->wireless_handlers->private_args[i].cmd) { 901 if (cmd == dev->wireless_handlers->private_args[i].cmd) {
906 descr = &(dev->wireless_handlers->private_args[i]); 902 descr = &dev->wireless_handlers->private_args[i];
907 break; 903 break;
908 } 904 }
905 }
909 906
910 /* Compute the size of the set/get arguments */ 907 extra_size = 0;
911 if (descr != NULL) { 908 if (descr) {
912 if (IW_IS_SET(cmd)) { 909 if (IW_IS_SET(cmd)) {
913 int offset = 0; /* For sub-ioctls */ 910 int offset = 0; /* For sub-ioctls */
914 /* Check for sub-ioctl handler */ 911 /* Check for sub-ioctl handler */
@@ -933,72 +930,82 @@ static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr,
933 extra_size = 0; 930 extra_size = 0;
934 } 931 }
935 } 932 }
933 *descrp = descr;
934 return extra_size;
935}
936 936
937 /* Prepare the call */ 937static int ioctl_private_iw_point(struct iw_point *iwp, unsigned int cmd,
938 info.cmd = cmd; 938 const struct iw_priv_args *descr,
939 info.flags = 0; 939 iw_handler handler, struct net_device *dev,
940 struct iw_request_info *info, int extra_size)
941{
942 char *extra;
943 int err;
940 944
941 /* Check if we have a pointer to user space data or not. */ 945 /* Check what user space is giving us */
942 if (extra_size == 0) { 946 if (IW_IS_SET(cmd)) {
943 /* No extra arguments. Trivial to handle */ 947 if (!iwp->pointer && iwp->length != 0)
944 ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u)); 948 return -EFAULT;
945 } else {
946 char * extra;
947 int err;
948 949
949 /* Check what user space is giving us */ 950 if (iwp->length > (descr->set_args & IW_PRIV_SIZE_MASK))
950 if (IW_IS_SET(cmd)) { 951 return -E2BIG;
951 /* Check NULL pointer */ 952 } else if (!iwp->pointer)
952 if ((iwr->u.data.pointer == NULL) && 953 return -EFAULT;
953 (iwr->u.data.length != 0))
954 return -EFAULT;
955 954
956 /* Does it fits within bounds ? */ 955 extra = kmalloc(extra_size, GFP_KERNEL);
957 if (iwr->u.data.length > (descr->set_args & 956 if (!extra)
958 IW_PRIV_SIZE_MASK)) 957 return -ENOMEM;
959 return -E2BIG;
960 } else if (iwr->u.data.pointer == NULL)
961 return -EFAULT;
962 958
963 /* Always allocate for max space. Easier, and won't last 959 /* If it is a SET, get all the extra data in here */
964 * long... */ 960 if (IW_IS_SET(cmd) && (iwp->length != 0)) {
965 extra = kmalloc(extra_size, GFP_KERNEL); 961 if (copy_from_user(extra, iwp->pointer, extra_size)) {
966 if (extra == NULL) 962 err = -EFAULT;
967 return -ENOMEM; 963 goto out;
968
969 /* If it is a SET, get all the extra data in here */
970 if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
971 err = copy_from_user(extra, iwr->u.data.pointer,
972 extra_size);
973 if (err) {
974 kfree(extra);
975 return -EFAULT;
976 }
977 } 964 }
965 }
978 966
979 /* Call the handler */ 967 /* Call the handler */
980 ret = handler(dev, &info, &(iwr->u), extra); 968 err = handler(dev, info, (union iwreq_data *) iwp, extra);
981 969
982 /* If we have something to return to the user */ 970 /* If we have something to return to the user */
983 if (!ret && IW_IS_GET(cmd)) { 971 if (!err && IW_IS_GET(cmd)) {
972 /* Adjust for the actual length if it's variable,
973 * avoid leaking kernel bits outside.
974 */
975 if (!(descr->get_args & IW_PRIV_SIZE_FIXED))
976 extra_size = adjust_priv_size(descr->get_args, iwp);
984 977
985 /* Adjust for the actual length if it's variable, 978 if (copy_to_user(iwp->pointer, extra, extra_size))
986 * avoid leaking kernel bits outside. */ 979 err = -EFAULT;
987 if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) { 980 }
988 extra_size = adjust_priv_size(descr->get_args,
989 &(iwr->u.data));
990 }
991 981
992 err = copy_to_user(iwr->u.data.pointer, extra, 982out:
993 extra_size); 983 kfree(extra);
994 if (err) 984 return err;
995 ret = -EFAULT; 985}
996 }
997 986
998 /* Cleanup - I told you it wasn't that long ;-) */ 987static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr,
999 kfree(extra); 988 unsigned int cmd, iw_handler handler)
1000 } 989{
990 struct iwreq *iwr = (struct iwreq *) ifr;
991 int extra_size = 0, ret = -EINVAL;
992 const struct iw_priv_args *descr;
993 struct iw_request_info info;
1001 994
995 extra_size = get_priv_descr_and_size(dev, cmd, &descr);
996
997 /* Prepare the call */
998 info.cmd = cmd;
999 info.flags = 0;
1000
1001 /* Check if we have a pointer to user space data or not. */
1002 if (extra_size == 0) {
1003 /* No extra arguments. Trivial to handle */
1004 ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u));
1005 } else {
1006 ret = ioctl_private_iw_point(&iwr->u.data, cmd, descr,
1007 handler, dev, &info, extra_size);
1008 }
1002 1009
1003 /* Call commit handler if needed and defined */ 1010 /* Call commit handler if needed and defined */
1004 if (ret == -EIWCOMMIT) 1011 if (ret == -EIWCOMMIT)