+ status, 0, NULL);
+ }
+}
+
+
+int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s,
+ u8 query_reason, int cand_list)
+{
+ u8 buf[2000], *pos;
+ struct ieee80211_mgmt *mgmt;
+ size_t len;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Query to "
+ MACSTR " query_reason=%u%s",
+ MAC2STR(wpa_s->bssid), query_reason,
+ cand_list ? " candidate list" : "");
+
+ mgmt = (struct ieee80211_mgmt *) buf;
+ os_memset(&buf, 0, sizeof(buf));
+ os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
+ os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
+ os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
+ mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_ACTION);
+ mgmt->u.action.category = WLAN_ACTION_WNM;
+ mgmt->u.action.u.bss_tm_query.action = WNM_BSS_TRANS_MGMT_QUERY;
+ mgmt->u.action.u.bss_tm_query.dialog_token = 1;
+ mgmt->u.action.u.bss_tm_query.query_reason = query_reason;
+ pos = mgmt->u.action.u.bss_tm_query.variable;
+
+ if (cand_list)
+ pos += wnm_add_cand_list(wpa_s, pos, buf + sizeof(buf) - pos);
+
+ len = pos - (u8 *) &mgmt->u.action.category;
+
+ ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+ wpa_s->own_addr, wpa_s->bssid,
+ &mgmt->u.action.category, len, 0);
+
+ return ret;
+}
+
+
+static void ieee802_11_rx_wnm_notif_req_wfa(struct wpa_supplicant *wpa_s,
+ const u8 *sa, const u8 *data,
+ int len)
+{
+ const u8 *pos, *end, *next;
+ u8 ie, ie_len;
+
+ pos = data;
+ end = data + len;
+
+ while (end - pos > 1) {
+ ie = *pos++;
+ ie_len = *pos++;
+ wpa_printf(MSG_DEBUG, "WNM: WFA subelement %u len %u",
+ ie, ie_len);
+ if (ie_len > end - pos) {
+ wpa_printf(MSG_DEBUG, "WNM: Not enough room for "
+ "subelement");
+ break;
+ }
+ next = pos + ie_len;
+ if (ie_len < 4) {
+ pos = next;
+ continue;
+ }
+ wpa_printf(MSG_DEBUG, "WNM: Subelement OUI %06x type %u",
+ WPA_GET_BE24(pos), pos[3]);
+
+#ifdef CONFIG_HS20
+ if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 5 &&
+ WPA_GET_BE24(pos) == OUI_WFA &&
+ pos[3] == HS20_WNM_SUB_REM_NEEDED) {
+ /* Subscription Remediation subelement */
+ const u8 *ie_end;
+ u8 url_len;
+ char *url;
+ u8 osu_method;
+
+ wpa_printf(MSG_DEBUG, "WNM: Subscription Remediation "
+ "subelement");
+ ie_end = pos + ie_len;
+ pos += 4;
+ url_len = *pos++;
+ if (url_len == 0) {
+ wpa_printf(MSG_DEBUG, "WNM: No Server URL included");
+ url = NULL;
+ osu_method = 1;
+ } else {
+ if (url_len + 1 > ie_end - pos) {
+ wpa_printf(MSG_DEBUG, "WNM: Not enough room for Server URL (len=%u) and Server Method (left %d)",
+ url_len,
+ (int) (ie_end - pos));
+ break;
+ }
+ url = os_malloc(url_len + 1);
+ if (url == NULL)
+ break;
+ os_memcpy(url, pos, url_len);
+ url[url_len] = '\0';
+ osu_method = pos[url_len];
+ }
+ hs20_rx_subscription_remediation(wpa_s, url,
+ osu_method);
+ os_free(url);
+ pos = next;
+ continue;
+ }
+
+ if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 8 &&
+ WPA_GET_BE24(pos) == OUI_WFA &&
+ pos[3] == HS20_WNM_DEAUTH_IMMINENT_NOTICE) {
+ const u8 *ie_end;
+ u8 url_len;
+ char *url;
+ u8 code;
+ u16 reauth_delay;
+
+ ie_end = pos + ie_len;
+ pos += 4;
+ code = *pos++;
+ reauth_delay = WPA_GET_LE16(pos);
+ pos += 2;
+ url_len = *pos++;
+ wpa_printf(MSG_DEBUG, "WNM: HS 2.0 Deauthentication "
+ "Imminent - Reason Code %u "
+ "Re-Auth Delay %u URL Length %u",
+ code, reauth_delay, url_len);
+ if (url_len > ie_end - pos)
+ break;
+ url = os_malloc(url_len + 1);
+ if (url == NULL)
+ break;
+ os_memcpy(url, pos, url_len);
+ url[url_len] = '\0';
+ hs20_rx_deauth_imminent_notice(wpa_s, code,
+ reauth_delay, url);
+ os_free(url);
+ pos = next;
+ continue;
+ }
+#endif /* CONFIG_HS20 */
+
+ pos = next;
+ }
+}
+
+
+static void ieee802_11_rx_wnm_notif_req(struct wpa_supplicant *wpa_s,
+ const u8 *sa, const u8 *frm, int len)
+{
+ const u8 *pos, *end;
+ u8 dialog_token, type;
+
+ /* Dialog Token [1] | Type [1] | Subelements */
+
+ if (len < 2 || sa == NULL)
+ return;
+ end = frm + len;
+ pos = frm;
+ dialog_token = *pos++;
+ type = *pos++;
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Received WNM-Notification Request "
+ "(dialog_token %u type %u sa " MACSTR ")",
+ dialog_token, type, MAC2STR(sa));
+ wpa_hexdump(MSG_DEBUG, "WNM-Notification Request subelements",
+ pos, end - pos);
+
+ if (wpa_s->wpa_state != WPA_COMPLETED ||
+ os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "WNM: WNM-Notification frame not "
+ "from our AP - ignore it");
+ return;
+ }
+
+ switch (type) {
+ case 1:
+ ieee802_11_rx_wnm_notif_req_wfa(wpa_s, sa, pos, end - pos);
+ break;
+ default:
+ wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Ignore unknown "
+ "WNM-Notification type %u", type);
+ break;