diff --git a/src/drivers/driver.h b/src/drivers/driver.h index f492f9fd1..785c76105 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -132,6 +132,7 @@ struct hostapd_hw_modes { * @age: Age of the information in milliseconds (i.e., how many milliseconds * ago the last Beacon or Probe Response frame was received) * @ie_len: length of the following IE field in octets + * @beacon_ie_len: length of the following Beacon IE field in octets * * This structure is used as a generic format for scan results from the * driver. Each driver interface implementation is responsible for converting @@ -154,7 +155,14 @@ struct wpa_scan_res { u64 tsf; unsigned int age; size_t ie_len; - /* followed by ie_len octets of IEs */ + size_t beacon_ie_len; + /* + * Followed by ie_len octets of IEs from Probe Response frame (or if + * the driver does not indicate source of IEs, these may also be from + * Beacon frame). After the first set of IEs, another set of IEs may + * follow (with beacon_ie_len octets of data) if the driver provides + * both IE sets. + */ }; /** diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index d64b68080..49eedfe6f 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -1481,12 +1481,14 @@ static int bss_info_handler(struct nl_msg *msg, void *arg) [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 }, [NL80211_BSS_STATUS] = { .type = NLA_U32 }, [NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 }, + [NL80211_BSS_BEACON_IES] = { .type = NLA_UNSPEC }, }; struct wpa_scan_results *res = arg; struct wpa_scan_res **tmp; struct wpa_scan_res *r; - const u8 *ie; - size_t ie_len; + const u8 *ie, *beacon_ie; + size_t ie_len, beacon_ie_len; + u8 *pos; nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); @@ -1502,8 +1504,15 @@ static int bss_info_handler(struct nl_msg *msg, void *arg) ie = NULL; ie_len = 0; } + if (bss[NL80211_BSS_BEACON_IES]) { + beacon_ie = nla_data(bss[NL80211_BSS_BEACON_IES]); + beacon_ie_len = nla_len(bss[NL80211_BSS_BEACON_IES]); + } else { + beacon_ie = NULL; + beacon_ie_len = 0; + } - r = os_zalloc(sizeof(*r) + ie_len); + r = os_zalloc(sizeof(*r) + ie_len + beacon_ie_len); if (r == NULL) return NL_SKIP; if (bss[NL80211_BSS_BSSID]) @@ -1530,8 +1539,14 @@ static int bss_info_handler(struct nl_msg *msg, void *arg) if (bss[NL80211_BSS_SEEN_MS_AGO]) r->age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]); r->ie_len = ie_len; - if (ie) - os_memcpy(r + 1, ie, ie_len); + pos = (u8 *) (r + 1); + if (ie) { + os_memcpy(pos, ie, ie_len); + pos += ie_len; + } + r->beacon_ie_len = beacon_ie_len; + if (beacon_ie) + os_memcpy(pos, beacon_ie, beacon_ie_len); if (bss[NL80211_BSS_STATUS]) { enum nl80211_bss_status status; diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c index b1d9b674a..414fa3555 100644 --- a/wpa_supplicant/bss.c +++ b/wpa_supplicant/bss.c @@ -120,7 +120,7 @@ static void wpa_bss_add(struct wpa_supplicant *wpa_s, { struct wpa_bss *bss; - bss = os_zalloc(sizeof(*bss) + res->ie_len); + bss = os_zalloc(sizeof(*bss) + res->ie_len + res->beacon_ie_len); if (bss == NULL) return; bss->id = wpa_s->bss_next_id++; @@ -129,7 +129,8 @@ static void wpa_bss_add(struct wpa_supplicant *wpa_s, os_memcpy(bss->ssid, ssid, ssid_len); bss->ssid_len = ssid_len; bss->ie_len = res->ie_len; - os_memcpy(bss + 1, res + 1, res->ie_len); + bss->beacon_ie_len = res->beacon_ie_len; + os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len); dl_list_add_tail(&wpa_s->bss, &bss->list); dl_list_add_tail(&wpa_s->bss_id, &bss->list_id); @@ -273,18 +274,23 @@ static void wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, wpa_bss_copy_res(bss, res); /* Move the entry to the end of the list */ dl_list_del(&bss->list); - if (bss->ie_len >= res->ie_len) { - os_memcpy(bss + 1, res + 1, res->ie_len); + if (bss->ie_len + bss->beacon_ie_len >= + res->ie_len + res->beacon_ie_len) { + os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len); bss->ie_len = res->ie_len; + bss->beacon_ie_len = res->beacon_ie_len; } else { struct wpa_bss *nbss; struct dl_list *prev = bss->list_id.prev; dl_list_del(&bss->list_id); - nbss = os_realloc(bss, sizeof(*bss) + res->ie_len); + nbss = os_realloc(bss, sizeof(*bss) + res->ie_len + + res->beacon_ie_len); if (nbss) { bss = nbss; - os_memcpy(bss + 1, res + 1, res->ie_len); + os_memcpy(bss + 1, res + 1, + res->ie_len + res->beacon_ie_len); bss->ie_len = res->ie_len; + bss->beacon_ie_len = res->beacon_ie_len; } dl_list_add(prev, &bss->list_id); } diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h index 2fa4863a2..1de4722a6 100644 --- a/wpa_supplicant/bss.h +++ b/wpa_supplicant/bss.h @@ -41,7 +41,8 @@ struct wpa_scan_res; * @level: signal level * @tsf: Timestamp of last Beacon/Probe Response frame * @last_update: Time of the last update (i.e., Beacon or Probe Response RX) - * @ie_len: length of the following IE field in octets + * @ie_len: length of the following IE field in octets (from Probe Response) + * @beacon_ie_len: length of the following Beacon IE field in octets * * This structure is used to store information about neighboring BSSes in * generic format. It is mainly updated based on scan results from the driver. @@ -65,7 +66,9 @@ struct wpa_bss { u64 tsf; struct os_time last_update; size_t ie_len; + size_t beacon_ie_len; /* followed by ie_len octets of IEs */ + /* followed by beacon_ie_len octets of IEs */ }; void wpa_bss_update_start(struct wpa_supplicant *wpa_s);