Interworking: Move BSS ANQP information into separate struct

This is an initial step in allowing the ANQP responses to be shared
among multiple BSSes if the BSSes are determined to be operating under
identical configuration.

Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
Jouni Malinen 2012-09-04 16:02:29 +03:00 committed by Jouni Malinen
parent 59ff6653aa
commit 476aed355a
5 changed files with 138 additions and 86 deletions

View file

@ -35,6 +35,48 @@
#define WPA_BSS_IES_CHANGED_FLAG BIT(8)
struct wpa_bss_anqp * wpa_bss_anqp_alloc(void)
{
struct wpa_bss_anqp *anqp;
anqp = os_zalloc(sizeof(*anqp));
if (anqp == NULL)
return NULL;
anqp->users = 1;
return anqp;
}
static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
{
if (anqp == NULL)
return;
anqp->users--;
if (anqp->users > 0) {
/* Another BSS entry holds a pointer to this ANQP info */
return;
}
#ifdef CONFIG_INTERWORKING
wpabuf_free(anqp->venue_name);
wpabuf_free(anqp->network_auth_type);
wpabuf_free(anqp->roaming_consortium);
wpabuf_free(anqp->ip_addr_type_availability);
wpabuf_free(anqp->nai_realm);
wpabuf_free(anqp->anqp_3gpp);
wpabuf_free(anqp->domain_name);
#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_HS20
wpabuf_free(anqp->hs20_operator_friendly_name);
wpabuf_free(anqp->hs20_wan_metrics);
wpabuf_free(anqp->hs20_connection_capability);
wpabuf_free(anqp->hs20_operating_class);
#endif /* CONFIG_HS20 */
os_free(anqp);
}
static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
const char *reason)
{
@ -58,21 +100,7 @@ static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
" SSID '%s' due to %s", bss->id, MAC2STR(bss->bssid),
wpa_ssid_txt(bss->ssid, bss->ssid_len), reason);
wpas_notify_bss_removed(wpa_s, bss->bssid, bss->id);
#ifdef CONFIG_INTERWORKING
wpabuf_free(bss->anqp_venue_name);
wpabuf_free(bss->anqp_network_auth_type);
wpabuf_free(bss->anqp_roaming_consortium);
wpabuf_free(bss->anqp_ip_addr_type_availability);
wpabuf_free(bss->anqp_nai_realm);
wpabuf_free(bss->anqp_3gpp);
wpabuf_free(bss->anqp_domain_name);
#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_HS20
wpabuf_free(bss->hs20_operator_friendly_name);
wpabuf_free(bss->hs20_wan_metrics);
wpabuf_free(bss->hs20_connection_capability);
wpabuf_free(bss->hs20_operating_class);
#endif /* CONFIG_HS20 */
wpa_bss_anqp_free(bss->anqp);
os_free(bss);
}

View file

@ -19,6 +19,25 @@ struct wpa_scan_res;
#define WPA_BSS_ASSOCIATED BIT(5)
#define WPA_BSS_ANQP_FETCH_TRIED BIT(6)
struct wpa_bss_anqp {
unsigned int users;
#ifdef CONFIG_INTERWORKING
struct wpabuf *venue_name;
struct wpabuf *network_auth_type;
struct wpabuf *roaming_consortium;
struct wpabuf *ip_addr_type_availability;
struct wpabuf *nai_realm;
struct wpabuf *anqp_3gpp;
struct wpabuf *domain_name;
#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_HS20
struct wpabuf *hs20_operator_friendly_name;
struct wpabuf *hs20_wan_metrics;
struct wpabuf *hs20_connection_capability;
struct wpabuf *hs20_operating_class;
#endif /* CONFIG_HS20 */
};
/**
* struct wpa_bss - BSS table
* @list: List entry for struct wpa_supplicant::bss
@ -60,21 +79,7 @@ struct wpa_bss {
int level;
u64 tsf;
struct os_time last_update;
#ifdef CONFIG_INTERWORKING
struct wpabuf *anqp_venue_name;
struct wpabuf *anqp_network_auth_type;
struct wpabuf *anqp_roaming_consortium;
struct wpabuf *anqp_ip_addr_type_availability;
struct wpabuf *anqp_nai_realm;
struct wpabuf *anqp_3gpp;
struct wpabuf *anqp_domain_name;
#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_HS20
struct wpabuf *hs20_operator_friendly_name;
struct wpabuf *hs20_wan_metrics;
struct wpabuf *hs20_connection_capability;
struct wpabuf *hs20_operating_class;
#endif /* CONFIG_HS20 */
struct wpa_bss_anqp *anqp;
size_t ie_len;
size_t beacon_ie_len;
/* followed by ie_len octets of IEs */
@ -105,5 +110,6 @@ struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss,
u32 vendor_type);
int wpa_bss_get_max_rate(const struct wpa_bss *bss);
int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates);
struct wpa_bss_anqp * wpa_bss_anqp_alloc(void);
#endif /* BSS_H */

View file

@ -2772,27 +2772,28 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
#endif /* CONFIG_WIFI_DISPLAY */
#ifdef CONFIG_INTERWORKING
if (mask & WPA_BSS_MASK_INTERNETW) {
if ((mask & WPA_BSS_MASK_INTERNETW) && bss->anqp) {
struct wpa_bss_anqp *anqp = bss->anqp;
pos = anqp_add_hex(pos, end, "anqp_venue_name",
bss->anqp_venue_name);
anqp->venue_name);
pos = anqp_add_hex(pos, end, "anqp_network_auth_type",
bss->anqp_network_auth_type);
anqp->network_auth_type);
pos = anqp_add_hex(pos, end, "anqp_roaming_consortium",
bss->anqp_roaming_consortium);
anqp->roaming_consortium);
pos = anqp_add_hex(pos, end, "anqp_ip_addr_type_availability",
bss->anqp_ip_addr_type_availability);
anqp->ip_addr_type_availability);
pos = anqp_add_hex(pos, end, "anqp_nai_realm",
bss->anqp_nai_realm);
pos = anqp_add_hex(pos, end, "anqp_3gpp", bss->anqp_3gpp);
anqp->nai_realm);
pos = anqp_add_hex(pos, end, "anqp_3gpp", anqp->anqp_3gpp);
pos = anqp_add_hex(pos, end, "anqp_domain_name",
bss->anqp_domain_name);
anqp->domain_name);
#ifdef CONFIG_HS20
pos = anqp_add_hex(pos, end, "hs20_operator_friendly_name",
bss->hs20_operator_friendly_name);
anqp->hs20_operator_friendly_name);
pos = anqp_add_hex(pos, end, "hs20_wan_metrics",
bss->hs20_wan_metrics);
anqp->hs20_wan_metrics);
pos = anqp_add_hex(pos, end, "hs20_connection_capability",
bss->hs20_connection_capability);
anqp->hs20_connection_capability);
#endif /* CONFIG_HS20 */
}
#endif /* CONFIG_INTERWORKING */

View file

@ -110,10 +110,14 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
const u8 *pos = data;
u8 subtype;
struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa);
struct wpa_bss_anqp *anqp = NULL;
if (slen < 2)
return;
if (bss)
anqp = bss->anqp;
subtype = *pos++;
slen--;
@ -130,9 +134,9 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
" Operator Friendly Name", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "oper friendly name", pos, slen);
if (bss) {
wpabuf_free(bss->hs20_operator_friendly_name);
bss->hs20_operator_friendly_name =
if (anqp) {
wpabuf_free(anqp->hs20_operator_friendly_name);
anqp->hs20_operator_friendly_name =
wpabuf_alloc_copy(pos, slen);
}
break;
@ -140,18 +144,18 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
" WAN Metrics", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "WAN Metrics", pos, slen);
if (bss) {
wpabuf_free(bss->hs20_wan_metrics);
bss->hs20_wan_metrics = wpabuf_alloc_copy(pos, slen);
if (anqp) {
wpabuf_free(anqp->hs20_wan_metrics);
anqp->hs20_wan_metrics = wpabuf_alloc_copy(pos, slen);
}
break;
case HS20_STYPE_CONNECTION_CAPABILITY:
wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
" Connection Capability", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "conn capability", pos, slen);
if (bss) {
wpabuf_free(bss->hs20_connection_capability);
bss->hs20_connection_capability =
if (anqp) {
wpabuf_free(anqp->hs20_connection_capability);
anqp->hs20_connection_capability =
wpabuf_alloc_copy(pos, slen);
}
break;
@ -159,9 +163,9 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
" Operating Class", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "Operating Class", pos, slen);
if (bss) {
wpabuf_free(bss->hs20_operating_class);
bss->hs20_operating_class =
if (anqp) {
wpabuf_free(anqp->hs20_operating_class);
anqp->hs20_operating_class =
wpabuf_alloc_copy(pos, slen);
}
break;

View file

@ -737,7 +737,7 @@ static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid;
const u8 *ie;
if (bss->anqp_3gpp == NULL)
if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL)
return -1;
for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
@ -768,7 +768,7 @@ static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
#ifdef PCSC_FUNCS
compare:
#endif /* PCSC_FUNCS */
if (plmn_id_match(bss->anqp_3gpp, imsi, mnc_len))
if (plmn_id_match(bss->anqp->anqp_3gpp, imsi, mnc_len))
break;
}
if (cred == NULL)
@ -923,7 +923,8 @@ static struct wpa_cred * interworking_credentials_available_roaming_consortium(
ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
if (ie == NULL && bss->anqp_roaming_consortium == NULL)
if (ie == NULL &&
(bss->anqp == NULL || bss->anqp->roaming_consortium == NULL))
return NULL;
if (wpa_s->conf->cred == NULL)
@ -933,7 +934,10 @@ static struct wpa_cred * interworking_credentials_available_roaming_consortium(
if (cred->roaming_consortium_len == 0)
continue;
if (!roaming_consortium_match(ie, bss->anqp_roaming_consortium,
if (!roaming_consortium_match(ie,
bss->anqp ?
bss->anqp->roaming_consortium :
NULL,
cred->roaming_consortium,
cred->roaming_consortium_len))
continue;
@ -1123,7 +1127,8 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
return interworking_connect_roaming_consortium(wpa_s, cred,
bss, ie);
realm = nai_realm_parse(bss->anqp_nai_realm, &count);
realm = nai_realm_parse(bss->anqp ? bss->anqp->nai_realm : NULL,
&count);
if (realm == NULL) {
wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
"Realm list from " MACSTR, MAC2STR(bss->bssid));
@ -1250,7 +1255,7 @@ static struct wpa_cred * interworking_credentials_available_3gpp(
int ret;
#ifdef INTERWORKING_3GPP
if (bss->anqp_3gpp == NULL)
if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL)
return NULL;
for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
@ -1283,7 +1288,7 @@ static struct wpa_cred * interworking_credentials_available_3gpp(
#endif /* PCSC_FUNCS */
wpa_printf(MSG_DEBUG, "Interworking: Parsing 3GPP info from "
MACSTR, MAC2STR(bss->bssid));
ret = plmn_id_match(bss->anqp_3gpp, imsi, mnc_len);
ret = plmn_id_match(bss->anqp->anqp_3gpp, imsi, mnc_len);
wpa_printf(MSG_DEBUG, "PLMN match %sfound", ret ? "" : "not ");
if (ret) {
if (selected == NULL ||
@ -1303,7 +1308,7 @@ static struct wpa_cred * interworking_credentials_available_realm(
struct nai_realm *realm;
u16 count, i;
if (bss->anqp_nai_realm == NULL)
if (bss->anqp == NULL || bss->anqp->nai_realm == NULL)
return NULL;
if (wpa_s->conf->cred == NULL)
@ -1311,7 +1316,7 @@ static struct wpa_cred * interworking_credentials_available_realm(
wpa_printf(MSG_DEBUG, "Interworking: Parsing NAI Realm list from "
MACSTR, MAC2STR(bss->bssid));
realm = nai_realm_parse(bss->anqp_nai_realm, &count);
realm = nai_realm_parse(bss->anqp->nai_realm, &count);
if (realm == NULL) {
wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
"Realm list from " MACSTR, MAC2STR(bss->bssid));
@ -1492,7 +1497,8 @@ static void interworking_select_network(struct wpa_supplicant *wpa_s)
continue;
}
count++;
res = interworking_home_sp(wpa_s, bss->anqp_domain_name);
res = interworking_home_sp(wpa_s, bss->anqp ?
bss->anqp->domain_name : NULL);
if (res > 0)
type = "home";
else if (res == 0)
@ -1572,6 +1578,11 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
continue; /* AP does not support Interworking */
if (!(bss->flags & WPA_BSS_ANQP_FETCH_TRIED)) {
if (bss->anqp == NULL) {
bss->anqp = wpa_bss_anqp_alloc();
if (bss->anqp == NULL)
break;
}
found++;
bss->flags |= WPA_BSS_ANQP_FETCH_TRIED;
wpa_msg(wpa_s, MSG_INFO, "Starting ANQP fetch for "
@ -1667,10 +1678,14 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
{
const u8 *pos = data;
struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa);
struct wpa_bss_anqp *anqp = NULL;
#ifdef CONFIG_HS20
u8 type;
#endif /* CONFIG_HS20 */
if (bss)
anqp = bss->anqp;
switch (info_id) {
case ANQP_CAPABILITY_LIST:
wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
@ -1680,9 +1695,9 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
" Venue Name", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Venue Name", pos, slen);
if (bss) {
wpabuf_free(bss->anqp_venue_name);
bss->anqp_venue_name = wpabuf_alloc_copy(pos, slen);
if (anqp) {
wpabuf_free(anqp->venue_name);
anqp->venue_name = wpabuf_alloc_copy(pos, slen);
}
break;
case ANQP_NETWORK_AUTH_TYPE:
@ -1691,10 +1706,9 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Network Authentication "
"Type", pos, slen);
if (bss) {
wpabuf_free(bss->anqp_network_auth_type);
bss->anqp_network_auth_type =
wpabuf_alloc_copy(pos, slen);
if (anqp) {
wpabuf_free(anqp->network_auth_type);
anqp->network_auth_type = wpabuf_alloc_copy(pos, slen);
}
break;
case ANQP_ROAMING_CONSORTIUM:
@ -1702,10 +1716,9 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
" Roaming Consortium list", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Roaming Consortium",
pos, slen);
if (bss) {
wpabuf_free(bss->anqp_roaming_consortium);
bss->anqp_roaming_consortium =
wpabuf_alloc_copy(pos, slen);
if (anqp) {
wpabuf_free(anqp->roaming_consortium);
anqp->roaming_consortium = wpabuf_alloc_copy(pos, slen);
}
break;
case ANQP_IP_ADDR_TYPE_AVAILABILITY:
@ -1714,9 +1727,9 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
MAC2STR(sa));
wpa_hexdump(MSG_MSGDUMP, "ANQP: IP Address Availability",
pos, slen);
if (bss) {
wpabuf_free(bss->anqp_ip_addr_type_availability);
bss->anqp_ip_addr_type_availability =
if (anqp) {
wpabuf_free(anqp->ip_addr_type_availability);
anqp->ip_addr_type_availability =
wpabuf_alloc_copy(pos, slen);
}
break;
@ -1724,9 +1737,9 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
" NAI Realm list", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: NAI Realm", pos, slen);
if (bss) {
wpabuf_free(bss->anqp_nai_realm);
bss->anqp_nai_realm = wpabuf_alloc_copy(pos, slen);
if (anqp) {
wpabuf_free(anqp->nai_realm);
anqp->nai_realm = wpabuf_alloc_copy(pos, slen);
}
break;
case ANQP_3GPP_CELLULAR_NETWORK:
@ -1734,18 +1747,18 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
" 3GPP Cellular Network information", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: 3GPP Cellular Network",
pos, slen);
if (bss) {
wpabuf_free(bss->anqp_3gpp);
bss->anqp_3gpp = wpabuf_alloc_copy(pos, slen);
if (anqp) {
wpabuf_free(anqp->anqp_3gpp);
anqp->anqp_3gpp = wpabuf_alloc_copy(pos, slen);
}
break;
case ANQP_DOMAIN_NAME:
wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
" Domain Name list", MAC2STR(sa));
wpa_hexdump_ascii(MSG_MSGDUMP, "ANQP: Domain Name", pos, slen);
if (bss) {
wpabuf_free(bss->anqp_domain_name);
bss->anqp_domain_name = wpabuf_alloc_copy(pos, slen);
if (anqp) {
wpabuf_free(anqp->domain_name);
anqp->domain_name = wpabuf_alloc_copy(pos, slen);
}
break;
case ANQP_VENDOR_SPECIFIC: