Loading net/wireless/wext.c +134 −124 Original line number Diff line number Diff line Loading @@ -694,49 +694,17 @@ void wext_proc_exit(struct net *net) */ /* ---------------------------------------------------------------- */ /* * 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) 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) { 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 { int err, extra_size, user_length = 0, essid_compat = 0; 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... */ * for max space. */ extra_size = descr->max_tokens * descr->token_size; /* Check need for ESSID compatibility for WE < 21 */ Loading @@ -745,18 +713,18 @@ static int ioctl_standard_call(struct net_device * dev, case SIOCGIWESSID: case SIOCSIWNICKN: case SIOCGIWNICKN: if (iwr->u.data.length == descr->max_tokens + 1) if (iwp->length == descr->max_tokens + 1) essid_compat = 1; else if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { else if (IW_IS_SET(cmd) && (iwp->length != 0)) { char essid[IW_ESSID_MAX_SIZE + 1]; err = copy_from_user(essid, iwr->u.data.pointer, iwr->u.data.length * err = copy_from_user(essid, iwp->pointer, iwp->length * descr->token_size); if (err) return -EFAULT; if (essid[iwr->u.data.length - 1] == '\0') if (essid[iwp->length - 1] == '\0') essid_compat = 1; } break; Loading @@ -764,95 +732,137 @@ static int ioctl_standard_call(struct net_device * dev, break; } iwr->u.data.length -= essid_compat; iwp->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)) if (!iwp->pointer && iwp->length != 0) return -EFAULT; /* Check if number of token fits within bounds */ if (iwr->u.data.length > descr->max_tokens) if (iwp->length > descr->max_tokens) return -E2BIG; if (iwr->u.data.length < descr->min_tokens) if (iwp->length < descr->min_tokens) return -EINVAL; } else { /* Check NULL pointer */ if (iwr->u.data.pointer == NULL) if (!iwp->pointer) return -EFAULT; /* Save user space buffer size for checking */ user_length = iwr->u.data.length; 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. */ * 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. */ * 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... */ * won't overflow... */ } } /* Create the kernel buffer */ /* kzalloc ensures NULL-termination for essid_compat */ /* kzalloc() ensures NULL-termination for essid_compat. */ extra = kzalloc(extra_size, GFP_KERNEL); if (extra == NULL) if (!extra) 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; if (IW_IS_SET(cmd) && (iwp->length != 0)) { if (copy_from_user(extra, iwp->pointer, iwp->length * descr->token_size)) { err = -EFAULT; goto out; } } /* Call the handler */ ret = handler(dev, &info, &(iwr->u), extra); err = handler(dev, info, (union iwreq_data *) iwp, extra); iwr->u.data.length += essid_compat; iwp->length += essid_compat; /* If we have something to return to the user */ if (!ret && IW_IS_GET(cmd)) { if (!err && IW_IS_GET(cmd)) { /* Check if there is enough buffer up there */ if (user_length < iwr->u.data.length) { kfree(extra); return -E2BIG; if (user_length < iwp->length) { err = -E2BIG; goto out; } err = copy_to_user(iwr->u.data.pointer, extra, iwr->u.data.length * descr->token_size); if (err) ret = -EFAULT; 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) && ((ret == 0) || (ret == -EIWCOMMIT))) { 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, &(iwr->u), NULL); * export the payload. */ wireless_send_event(dev, cmd, data, NULL); else wireless_send_event(dev, cmd, &(iwr->u), extra); wireless_send_event(dev, cmd, data, extra); } /* Cleanup - I told you it wasn't that long ;-) */ out: kfree(extra); return err; } /* * 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 { ret = ioctl_standard_iw_point(&iwr->u.data, cmd, descr, handler, dev, &info); } /* Call commit handler if needed and defined */ Loading Loading
net/wireless/wext.c +134 −124 Original line number Diff line number Diff line Loading @@ -694,49 +694,17 @@ void wext_proc_exit(struct net *net) */ /* ---------------------------------------------------------------- */ /* * 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) 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) { 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 { int err, extra_size, user_length = 0, essid_compat = 0; 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... */ * for max space. */ extra_size = descr->max_tokens * descr->token_size; /* Check need for ESSID compatibility for WE < 21 */ Loading @@ -745,18 +713,18 @@ static int ioctl_standard_call(struct net_device * dev, case SIOCGIWESSID: case SIOCSIWNICKN: case SIOCGIWNICKN: if (iwr->u.data.length == descr->max_tokens + 1) if (iwp->length == descr->max_tokens + 1) essid_compat = 1; else if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { else if (IW_IS_SET(cmd) && (iwp->length != 0)) { char essid[IW_ESSID_MAX_SIZE + 1]; err = copy_from_user(essid, iwr->u.data.pointer, iwr->u.data.length * err = copy_from_user(essid, iwp->pointer, iwp->length * descr->token_size); if (err) return -EFAULT; if (essid[iwr->u.data.length - 1] == '\0') if (essid[iwp->length - 1] == '\0') essid_compat = 1; } break; Loading @@ -764,95 +732,137 @@ static int ioctl_standard_call(struct net_device * dev, break; } iwr->u.data.length -= essid_compat; iwp->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)) if (!iwp->pointer && iwp->length != 0) return -EFAULT; /* Check if number of token fits within bounds */ if (iwr->u.data.length > descr->max_tokens) if (iwp->length > descr->max_tokens) return -E2BIG; if (iwr->u.data.length < descr->min_tokens) if (iwp->length < descr->min_tokens) return -EINVAL; } else { /* Check NULL pointer */ if (iwr->u.data.pointer == NULL) if (!iwp->pointer) return -EFAULT; /* Save user space buffer size for checking */ user_length = iwr->u.data.length; 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. */ * 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. */ * 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... */ * won't overflow... */ } } /* Create the kernel buffer */ /* kzalloc ensures NULL-termination for essid_compat */ /* kzalloc() ensures NULL-termination for essid_compat. */ extra = kzalloc(extra_size, GFP_KERNEL); if (extra == NULL) if (!extra) 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; if (IW_IS_SET(cmd) && (iwp->length != 0)) { if (copy_from_user(extra, iwp->pointer, iwp->length * descr->token_size)) { err = -EFAULT; goto out; } } /* Call the handler */ ret = handler(dev, &info, &(iwr->u), extra); err = handler(dev, info, (union iwreq_data *) iwp, extra); iwr->u.data.length += essid_compat; iwp->length += essid_compat; /* If we have something to return to the user */ if (!ret && IW_IS_GET(cmd)) { if (!err && IW_IS_GET(cmd)) { /* Check if there is enough buffer up there */ if (user_length < iwr->u.data.length) { kfree(extra); return -E2BIG; if (user_length < iwp->length) { err = -E2BIG; goto out; } err = copy_to_user(iwr->u.data.pointer, extra, iwr->u.data.length * descr->token_size); if (err) ret = -EFAULT; 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) && ((ret == 0) || (ret == -EIWCOMMIT))) { 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, &(iwr->u), NULL); * export the payload. */ wireless_send_event(dev, cmd, data, NULL); else wireless_send_event(dev, cmd, &(iwr->u), extra); wireless_send_event(dev, cmd, data, extra); } /* Cleanup - I told you it wasn't that long ;-) */ out: kfree(extra); return err; } /* * 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 { ret = ioctl_standard_iw_point(&iwr->u.data, cmd, descr, handler, dev, &info); } /* Call commit handler if needed and defined */ Loading