|
@@ -1239,15 +1239,15 @@ int cfg80211_wext_siwscan(struct net_device *dev,
|
|
|
}
|
|
|
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
|
|
@@ -1264,10 +1264,11 @@ static void ieee80211_scan_add_ies(struct iw_request_info *info,
|
|
|
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;
|
|
|
}
|
|
|
|
|
@@ -1275,10 +1276,14 @@ static void ieee80211_scan_add_ies(struct iw_request_info *info,
|
|
|
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 *
|
|
@@ -1289,7 +1294,8 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
|
|
|
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;
|
|
|
|
|
@@ -1297,22 +1303,28 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
|
|
|
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));
|
|
@@ -1341,8 +1353,11 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
|
|
|
/* 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));
|
|
@@ -1352,8 +1367,10 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
|
|
|
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);
|
|
@@ -1371,66 +1388,91 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
|
|
|
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:
|
|
@@ -1445,8 +1487,14 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
|
|
|
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;
|
|
@@ -1465,31 +1513,35 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
|
|
|
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;
|
|
|
}
|
|
|
|
|
@@ -1501,19 +1553,27 @@ static int ieee80211_scan_results(struct cfg80211_registered_device *rdev,
|
|
|
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;
|
|
|
}
|
|
|
|