}
 EXPORT_WEXT_HANDLER(cfg80211_wext_siwscan);
 
-static void ieee80211_scan_add_ies(struct iw_request_info *info,
-                                  const struct cfg80211_bss_ies *ies,
-                                  char **current_ev, char *end_buf)
+static char *ieee80211_scan_add_ies(struct iw_request_info *info,
+                                   const struct cfg80211_bss_ies *ies,
+                                   char *current_ev, char *end_buf)
 {
        const u8 *pos, *end, *next;
        struct iw_event iwe;
 
        if (!ies)
-               return;
+               return current_ev;
 
        /*
         * If needed, fragment the IEs buffer (at IE boundaries) into short
                memset(&iwe, 0, sizeof(iwe));
                iwe.cmd = IWEVGENIE;
                iwe.u.data.length = next - pos;
-               *current_ev = iwe_stream_add_point(info, *current_ev,
-                                                  end_buf, &iwe,
-                                                  (void *)pos);
-
+               current_ev = iwe_stream_add_point_check(info, current_ev,
+                                                       end_buf, &iwe,
+                                                       (void *)pos);
+               if (IS_ERR(current_ev))
+                       return current_ev;
                pos = next;
        }
 
                memset(&iwe, 0, sizeof(iwe));
                iwe.cmd = IWEVGENIE;
                iwe.u.data.length = end - pos;
-               *current_ev = iwe_stream_add_point(info, *current_ev,
-                                                  end_buf, &iwe,
-                                                  (void *)pos);
+               current_ev = iwe_stream_add_point_check(info, current_ev,
+                                                       end_buf, &iwe,
+                                                       (void *)pos);
+               if (IS_ERR(current_ev))
+                       return current_ev;
        }
+
+       return current_ev;
 }
 
 static char *
        const struct cfg80211_bss_ies *ies;
        struct iw_event iwe;
        const u8 *ie;
-       u8 *buf, *cfg, *p;
+       u8 buf[50];
+       u8 *cfg, *p, *tmp;
        int rem, i, sig;
        bool ismesh = false;
 
        iwe.cmd = SIOCGIWAP;
        iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
        memcpy(iwe.u.ap_addr.sa_data, bss->pub.bssid, ETH_ALEN);
-       current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
-                                         IW_EV_ADDR_LEN);
+       current_ev = iwe_stream_add_event_check(info, current_ev, end_buf, &iwe,
+                                               IW_EV_ADDR_LEN);
+       if (IS_ERR(current_ev))
+               return current_ev;
 
        memset(&iwe, 0, sizeof(iwe));
        iwe.cmd = SIOCGIWFREQ;
        iwe.u.freq.m = ieee80211_frequency_to_channel(bss->pub.channel->center_freq);
        iwe.u.freq.e = 0;
-       current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
-                                         IW_EV_FREQ_LEN);
+       current_ev = iwe_stream_add_event_check(info, current_ev, end_buf, &iwe,
+                                               IW_EV_FREQ_LEN);
+       if (IS_ERR(current_ev))
+               return current_ev;
 
        memset(&iwe, 0, sizeof(iwe));
        iwe.cmd = SIOCGIWFREQ;
        iwe.u.freq.m = bss->pub.channel->center_freq;
        iwe.u.freq.e = 6;
-       current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
-                                         IW_EV_FREQ_LEN);
+       current_ev = iwe_stream_add_event_check(info, current_ev, end_buf, &iwe,
+                                               IW_EV_FREQ_LEN);
+       if (IS_ERR(current_ev))
+               return current_ev;
 
        if (wiphy->signal_type != CFG80211_SIGNAL_TYPE_NONE) {
                memset(&iwe, 0, sizeof(iwe));
                        /* not reached */
                        break;
                }
-               current_ev = iwe_stream_add_event(info, current_ev, end_buf,
-                                                 &iwe, IW_EV_QUAL_LEN);
+               current_ev = iwe_stream_add_event_check(info, current_ev,
+                                                       end_buf, &iwe,
+                                                       IW_EV_QUAL_LEN);
+               if (IS_ERR(current_ev))
+                       return current_ev;
        }
 
        memset(&iwe, 0, sizeof(iwe));
        else
                iwe.u.data.flags = IW_ENCODE_DISABLED;
        iwe.u.data.length = 0;
-       current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-                                         &iwe, "");
+       current_ev = iwe_stream_add_point_check(info, current_ev, end_buf,
+                                               &iwe, "");
+       if (IS_ERR(current_ev))
+               return current_ev;
 
        rcu_read_lock();
        ies = rcu_dereference(bss->pub.ies);
                        iwe.cmd = SIOCGIWESSID;
                        iwe.u.data.length = ie[1];
                        iwe.u.data.flags = 1;
-                       current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-                                                         &iwe, (u8 *)ie + 2);
+                       current_ev = iwe_stream_add_point_check(info,
+                                                               current_ev,
+                                                               end_buf, &iwe,
+                                                               (u8 *)ie + 2);
+                       if (IS_ERR(current_ev))
+                               goto unlock;
                        break;
                case WLAN_EID_MESH_ID:
                        memset(&iwe, 0, sizeof(iwe));
                        iwe.cmd = SIOCGIWESSID;
                        iwe.u.data.length = ie[1];
                        iwe.u.data.flags = 1;
-                       current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-                                                         &iwe, (u8 *)ie + 2);
+                       current_ev = iwe_stream_add_point_check(info,
+                                                               current_ev,
+                                                               end_buf, &iwe,
+                                                               (u8 *)ie + 2);
+                       if (IS_ERR(current_ev))
+                               goto unlock;
                        break;
                case WLAN_EID_MESH_CONFIG:
                        ismesh = true;
                        if (ie[1] != sizeof(struct ieee80211_meshconf_ie))
                                break;
-                       buf = kmalloc(50, GFP_ATOMIC);
-                       if (!buf)
-                               break;
                        cfg = (u8 *)ie + 2;
                        memset(&iwe, 0, sizeof(iwe));
                        iwe.cmd = IWEVCUSTOM;
                        sprintf(buf, "Mesh Network Path Selection Protocol ID: "
                                "0x%02X", cfg[0]);
                        iwe.u.data.length = strlen(buf);
-                       current_ev = iwe_stream_add_point(info, current_ev,
-                                                         end_buf,
-                                                         &iwe, buf);
+                       current_ev = iwe_stream_add_point_check(info,
+                                                               current_ev,
+                                                               end_buf,
+                                                               &iwe, buf);
+                       if (IS_ERR(current_ev))
+                               goto unlock;
                        sprintf(buf, "Path Selection Metric ID: 0x%02X",
                                cfg[1]);
                        iwe.u.data.length = strlen(buf);
-                       current_ev = iwe_stream_add_point(info, current_ev,
-                                                         end_buf,
-                                                         &iwe, buf);
+                       current_ev = iwe_stream_add_point_check(info,
+                                                               current_ev,
+                                                               end_buf,
+                                                               &iwe, buf);
+                       if (IS_ERR(current_ev))
+                               goto unlock;
                        sprintf(buf, "Congestion Control Mode ID: 0x%02X",
                                cfg[2]);
                        iwe.u.data.length = strlen(buf);
-                       current_ev = iwe_stream_add_point(info, current_ev,
-                                                         end_buf,
-                                                         &iwe, buf);
+                       current_ev = iwe_stream_add_point_check(info,
+                                                               current_ev,
+                                                               end_buf,
+                                                               &iwe, buf);
+                       if (IS_ERR(current_ev))
+                               goto unlock;
                        sprintf(buf, "Synchronization ID: 0x%02X", cfg[3]);
                        iwe.u.data.length = strlen(buf);
-                       current_ev = iwe_stream_add_point(info, current_ev,
-                                                         end_buf,
-                                                         &iwe, buf);
+                       current_ev = iwe_stream_add_point_check(info,
+                                                               current_ev,
+                                                               end_buf,
+                                                               &iwe, buf);
+                       if (IS_ERR(current_ev))
+                               goto unlock;
                        sprintf(buf, "Authentication ID: 0x%02X", cfg[4]);
                        iwe.u.data.length = strlen(buf);
-                       current_ev = iwe_stream_add_point(info, current_ev,
-                                                         end_buf,
-                                                         &iwe, buf);
+                       current_ev = iwe_stream_add_point_check(info,
+                                                               current_ev,
+                                                               end_buf,
+                                                               &iwe, buf);
+                       if (IS_ERR(current_ev))
+                               goto unlock;
                        sprintf(buf, "Formation Info: 0x%02X", cfg[5]);
                        iwe.u.data.length = strlen(buf);
-                       current_ev = iwe_stream_add_point(info, current_ev,
-                                                         end_buf,
-                                                         &iwe, buf);
+                       current_ev = iwe_stream_add_point_check(info,
+                                                               current_ev,
+                                                               end_buf,
+                                                               &iwe, buf);
+                       if (IS_ERR(current_ev))
+                               goto unlock;
                        sprintf(buf, "Capabilities: 0x%02X", cfg[6]);
                        iwe.u.data.length = strlen(buf);
-                       current_ev = iwe_stream_add_point(info, current_ev,
-                                                         end_buf,
-                                                         &iwe, buf);
-                       kfree(buf);
+                       current_ev = iwe_stream_add_point_check(info,
+                                                               current_ev,
+                                                               end_buf,
+                                                               &iwe, buf);
+                       if (IS_ERR(current_ev))
+                               goto unlock;
                        break;
                case WLAN_EID_SUPP_RATES:
                case WLAN_EID_EXT_SUPP_RATES:
                        for (i = 0; i < ie[1]; i++) {
                                iwe.u.bitrate.value =
                                        ((ie[i + 2] & 0x7f) * 500000);
+                               tmp = p;
                                p = iwe_stream_add_value(info, current_ev, p,
-                                               end_buf, &iwe, IW_EV_PARAM_LEN);
+                                                        end_buf, &iwe,
+                                                        IW_EV_PARAM_LEN);
+                               if (p == tmp) {
+                                       current_ev = ERR_PTR(-E2BIG);
+                                       goto unlock;
+                               }
                        }
                        current_ev = p;
                        break;
                        iwe.u.mode = IW_MODE_MASTER;
                else
                        iwe.u.mode = IW_MODE_ADHOC;
-               current_ev = iwe_stream_add_event(info, current_ev, end_buf,
-                                                 &iwe, IW_EV_UINT_LEN);
-       }
-
-       buf = kmalloc(31, GFP_ATOMIC);
-       if (buf) {
-               memset(&iwe, 0, sizeof(iwe));
-               iwe.cmd = IWEVCUSTOM;
-               sprintf(buf, "tsf=%016llx", (unsigned long long)(ies->tsf));
-               iwe.u.data.length = strlen(buf);
-               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-                                                 &iwe, buf);
-               memset(&iwe, 0, sizeof(iwe));
-               iwe.cmd = IWEVCUSTOM;
-               sprintf(buf, " Last beacon: %ums ago",
-                       elapsed_jiffies_msecs(bss->ts));
-               iwe.u.data.length = strlen(buf);
-               current_ev = iwe_stream_add_point(info, current_ev,
-                                                 end_buf, &iwe, buf);
-               kfree(buf);
+               current_ev = iwe_stream_add_event_check(info, current_ev,
+                                                       end_buf, &iwe,
+                                                       IW_EV_UINT_LEN);
+               if (IS_ERR(current_ev))
+                       goto unlock;
        }
 
-       ieee80211_scan_add_ies(info, ies, ¤t_ev, end_buf);
+       memset(&iwe, 0, sizeof(iwe));
+       iwe.cmd = IWEVCUSTOM;
+       sprintf(buf, "tsf=%016llx", (unsigned long long)(ies->tsf));
+       iwe.u.data.length = strlen(buf);
+       current_ev = iwe_stream_add_point_check(info, current_ev, end_buf,
+                                               &iwe, buf);
+       if (IS_ERR(current_ev))
+               goto unlock;
+       memset(&iwe, 0, sizeof(iwe));
+       iwe.cmd = IWEVCUSTOM;
+       sprintf(buf, " Last beacon: %ums ago",
+               elapsed_jiffies_msecs(bss->ts));
+       iwe.u.data.length = strlen(buf);
+       current_ev = iwe_stream_add_point_check(info, current_ev,
+                                               end_buf, &iwe, buf);
+       if (IS_ERR(current_ev))
+               goto unlock;
+
+       current_ev = ieee80211_scan_add_ies(info, ies, current_ev, end_buf);
+
+ unlock:
        rcu_read_unlock();
-
        return current_ev;
 }
 
        char *current_ev = buf;
        char *end_buf = buf + len;
        struct cfg80211_internal_bss *bss;
+       int err = 0;
 
        spin_lock_bh(&rdev->bss_lock);
        cfg80211_bss_expire(rdev);
 
        list_for_each_entry(bss, &rdev->bss_list, list) {
                if (buf + len - current_ev <= IW_EV_ADDR_LEN) {
-                       spin_unlock_bh(&rdev->bss_lock);
-                       return -E2BIG;
+                       err = -E2BIG;
+                       break;
                }
                current_ev = ieee80211_bss(&rdev->wiphy, info, bss,
                                           current_ev, end_buf);
+               if (IS_ERR(current_ev)) {
+                       err = PTR_ERR(current_ev);
+                       break;
+               }
        }
        spin_unlock_bh(&rdev->bss_lock);
+
+       if (err)
+               return err;
        return current_ev - buf;
 }