HS 2.0R2: Add WNM-Notification Request for Subscription Remediation
authorJouni Malinen <jouni@qca.qualcomm.com>
Fri, 2 Nov 2012 11:05:57 +0000 (13:05 +0200)
committerJouni Malinen <j@w1.fi>
Tue, 25 Feb 2014 23:24:23 +0000 (01:24 +0200)
Subscription remediation notification WNM-Notification Request is now
shown in the following way in wpa_supplicant control interface:
<3>HS20-SUBSCRIPTION-REMEDIATION http://example.com/foo/

Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>

src/common/ieee802_11_defs.h
src/common/wpa_ctrl.h
src/drivers/driver_nl80211.c
wpa_supplicant/hs20_supplicant.c
wpa_supplicant/hs20_supplicant.h
wpa_supplicant/scan.c
wpa_supplicant/wnm_sta.c
wpa_supplicant/wpa_cli.c
wpa_supplicant/wpa_supplicant.c

index df8c08b..a9ed651 100644 (file)
@@ -914,6 +914,9 @@ enum {
 #define HS20_ANQP_DOMAIN_ID_PRESENT 0x04
 #define HS20_VERSION 0x10 /* Release 2 */
 
+/* WNM-Notification WFA vendors specific subtypes */
+#define HS20_WNM_SUB_REM_NEEDED 0
+
 /* Wi-Fi Direct (P2P) */
 
 #define P2P_OUI_TYPE 9
index 759cee4..54f59b1 100644 (file)
@@ -168,6 +168,8 @@ extern "C" {
 /* parameters: <addr> <dialog_token> <freq> <status_code> <result> */
 #define GAS_QUERY_DONE "GAS-QUERY-DONE "
 
+#define HS20_SUBSCRIPTION_REMEDIATION "HS20-SUBSCRIPTION-REMEDIATION "
+
 #define EXT_RADIO_WORK_START "EXT-RADIO-WORK-START "
 #define EXT_RADIO_WORK_TIMEOUT "EXT-RADIO-WORK-TIMEOUT "
 
index 8f204a9..42578b6 100644 (file)
@@ -4376,6 +4376,12 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
        if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x11", 2) < 0)
                ret = -1;
 
+#ifdef CONFIG_HS20
+       /* WNM-Notification */
+       if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x1a", 2) < 0)
+               return -1;
+#endif /* CONFIG_HS20 */
+
        nl80211_mgmt_handle_register_eloop(bss);
 
        return ret;
index 0040244..d419ffb 100644 (file)
@@ -235,3 +235,14 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
                break;
        }
 }
+
+
+void hs20_rx_subscription_remediation(struct wpa_supplicant *wpa_s,
+                                     const char *url, u8 osu_method)
+{
+       if (url)
+               wpa_msg(wpa_s, MSG_INFO, HS20_SUBSCRIPTION_REMEDIATION "%u %s",
+                       osu_method, url);
+       else
+               wpa_msg(wpa_s, MSG_INFO, HS20_SUBSCRIPTION_REMEDIATION);
+}
index 7f62a15..b19355b 100644 (file)
@@ -20,4 +20,7 @@ int is_hs20_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
                    struct wpa_bss *bss);
 int hs20_get_pps_mo_id(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
 
+void hs20_rx_subscription_remediation(struct wpa_supplicant *wpa_s,
+                                     const char *url, u8 osu_method);
+
 #endif /* HS20_SUPPLICANT_H */
index 6f58667..f7eb537 100644 (file)
@@ -365,11 +365,17 @@ static void wpas_add_interworking_elements(struct wpa_supplicant *wpa_s,
                return;
 
        wpabuf_put_u8(buf, WLAN_EID_EXT_CAPAB);
-       wpabuf_put_u8(buf, 4);
+       wpabuf_put_u8(buf, 6);
        wpabuf_put_u8(buf, 0x00);
        wpabuf_put_u8(buf, 0x00);
        wpabuf_put_u8(buf, 0x00);
        wpabuf_put_u8(buf, 0x80); /* Bit 31 - Interworking */
+       wpabuf_put_u8(buf, 0x00);
+#ifdef CONFIG_HS20
+       wpabuf_put_u8(buf, 0x40); /* Bit 46 - WNM-Notification */
+#else /* CONFIG_HS20 */
+       wpabuf_put_u8(buf, 0x00);
+#endif /* CONFIG_HS20 */
 
        wpabuf_put_u8(buf, WLAN_EID_INTERWORKING);
        wpabuf_put_u8(buf, is_zero_ether_addr(wpa_s->conf->hessid) ? 1 :
index 65b2783..9b7bfa7 100644 (file)
@@ -18,6 +18,7 @@
 #include "ctrl_iface.h"
 #include "bss.h"
 #include "wnm_sta.h"
+#include "hs20_supplicant.h"
 
 #define MAX_TFS_IE_LEN  1024
 #define WNM_MAX_NEIGHBOR_REPORT 10
@@ -751,6 +752,112 @@ int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s,
 }
 
 
+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;
+       u8 ie, ie_len;
+
+       pos = data;
+       end = data + len;
+
+       while (pos + 1 < end) {
+               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;
+               }
+
+#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 (pos + url_len + 1 > ie_end) {
+                                       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);
+                       break;
+               }
+#endif /* CONFIG_HS20 */
+
+               pos += ie_len;
+       }
+}
+
+
+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;
+       }
+}
+
+
 void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
                              const struct ieee80211_mgmt *mgmt, size_t len)
 {
@@ -782,6 +889,9 @@ void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
        case WNM_SLEEP_MODE_RESP:
                ieee802_11_rx_wnmsleep_resp(wpa_s, pos, end - pos);
                break;
+       case WNM_NOTIFICATION_REQ:
+               ieee802_11_rx_wnm_notif_req(wpa_s, mgmt->sa, pos, end - pos);
+               break;
        default:
                wpa_printf(MSG_ERROR, "WNM: Unknown request");
                break;
index 6278806..07a334a 100644 (file)
@@ -3181,6 +3181,8 @@ static void wpa_cli_action_process(const char *msg)
                wpa_cli_exec(action_file, ctrl_ifname, pos);
        } else if (str_match(pos, ESS_DISASSOC_IMMINENT)) {
                wpa_cli_exec(action_file, ctrl_ifname, pos);
+       } else if (str_match(pos, HS20_SUBSCRIPTION_REMEDIATION)) {
+               wpa_cli_exec(action_file, ctrl_ifname, pos);
        } else if (str_match(pos, WPA_EVENT_TERMINATING)) {
                printf("wpa_supplicant is terminating - stop monitoring\n");
                wpa_cli_quit = 1;
index f67daea..71b6b63 100644 (file)
@@ -1208,6 +1208,10 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
 #endif /* CONFIG_INTERWORKING */
                break;
        case 5: /* Bits 40-47 */
+#ifdef CONFIG_HS20
+               if (wpa_s->conf->hs20)
+                       *pos |= 0x40; /* Bit 46 - WNM-Notification */
+#endif /* CONFIG_HS20 */
                break;
        case 6: /* Bits 48-55 */
                break;
@@ -1218,7 +1222,7 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
 int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf)
 {
        u8 *pos = buf;
-       u8 len = 4, i;
+       u8 len = 6, i;
 
        if (len < wpa_s->extended_capa_len)
                len = wpa_s->extended_capa_len;