HS 2.0R2 AP: Add WNM-Notification Request for Subscription Remediation
authorJouni Malinen <jouni@qca.qualcomm.com>
Sun, 17 Mar 2013 14:03:42 +0000 (16:03 +0200)
committerJouni Malinen <j@w1.fi>
Tue, 25 Feb 2014 23:24:24 +0000 (01:24 +0200)
Subscription remediation notification can now be sent from hostapd with:
hostapd_cli hs20_wnm_notif 02:00:00:00:00:00 http://example.com/foo/

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

hostapd/ctrl_iface.c
hostapd/hostapd_cli.c
src/ap/hs20.c
src/ap/hs20.h
src/ap/ieee802_11_shared.c

index b073e8c..53d8d3d 100644 (file)
@@ -30,6 +30,7 @@
 #include "ap/wps_hostapd.h"
 #include "ap/ctrl_iface_ap.h"
 #include "ap/ap_drv_ops.h"
+#include "ap/hs20.h"
 #include "ap/wnm_ap.h"
 #include "ap/wpa_auth.h"
 #include "wps/wps_defs.h"
@@ -617,6 +618,32 @@ static int hostapd_ctrl_iface_wps_get_status(struct hostapd_data *hapd,
 
 #endif /* CONFIG_WPS */
 
+#ifdef CONFIG_HS20
+
+static int hostapd_ctrl_iface_hs20_wnm_notif(struct hostapd_data *hapd,
+                                            const char *cmd)
+{
+       u8 addr[ETH_ALEN];
+       const char *url;
+
+       if (hwaddr_aton(cmd, addr))
+               return -1;
+       url = cmd + 17;
+       if (*url == '\0') {
+               url = NULL;
+       } else {
+               if (*url != ' ')
+                       return -1;
+               url++;
+               if (*url == '\0')
+                       url = NULL;
+       }
+
+       return hs20_send_wnm_notification(hapd, addr, 1, url);
+}
+
+#endif /* CONFIG_HS20 */
+
 
 #ifdef CONFIG_INTERWORKING
 
@@ -1348,6 +1375,11 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
                if (hostapd_ctrl_iface_send_qos_map_conf(hapd, buf + 18))
                        reply_len = -1;
 #endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+       } else if (os_strncmp(buf, "HS20_WNM_NOTIF ", 15) == 0) {
+               if (hostapd_ctrl_iface_hs20_wnm_notif(hapd, buf + 15))
+                       reply_len = -1;
+#endif /* CONFIG_HS20 */
 #ifdef CONFIG_WNM
        } else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) {
                if (hostapd_ctrl_iface_disassoc_imminent(hapd, buf + 18))
index eee8504..4d5f269 100644 (file)
@@ -743,6 +743,26 @@ static int hostapd_cli_cmd_send_qos_map_conf(struct wpa_ctrl *ctrl,
 }
 
 
+static int hostapd_cli_cmd_hs20_wnm_notif(struct wpa_ctrl *ctrl, int argc,
+                                         char *argv[])
+{
+       char buf[300];
+       int res;
+
+       if (argc < 2) {
+               printf("Invalid 'hs20_wnm_notif' command - two arguments (STA "
+                      "addr and URL) are needed\n");
+               return -1;
+       }
+
+       res = os_snprintf(buf, sizeof(buf), "HS20_WNM_NOTIF %s %s",
+                         argv[0], argv[1]);
+       if (res < 0 || res >= (int) sizeof(buf))
+               return -1;
+       return wpa_ctrl_command(ctrl, buf);
+}
+
+
 static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
        hostapd_cli_quit = 1;
@@ -941,6 +961,7 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = {
        { "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set },
        { "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf },
        { "chan_switch", hostapd_cli_cmd_chan_switch },
+       { "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif },
        { NULL, NULL }
 };
 
index 01c87e8..5875b40 100644 (file)
@@ -13,6 +13,7 @@
 #include "common/ieee802_11_defs.h"
 #include "hostapd.h"
 #include "ap_config.h"
+#include "ap_drv_ops.h"
 #include "hs20.h"
 
 
@@ -36,3 +37,54 @@ u8 * hostapd_eid_hs20_indication(struct hostapd_data *hapd, u8 *eid)
 
        return eid;
 }
+
+
+int hs20_send_wnm_notification(struct hostapd_data *hapd, const u8 *addr,
+                              u8 osu_method, const char *url)
+{
+       struct wpabuf *buf;
+       size_t len = 0;
+       int ret;
+
+       /* TODO: should refuse to send notification if the STA is not associated
+        * or if the STA did not indicate support for WNM-Notification */
+
+       if (url) {
+               len = 1 + os_strlen(url);
+               if (5 + len > 255) {
+                       wpa_printf(MSG_INFO, "HS 2.0: Too long URL for "
+                                  "WNM-Notification: '%s'", url);
+                       return -1;
+               }
+       }
+
+       buf = wpabuf_alloc(4 + 7 + len);
+       if (buf == NULL)
+               return -1;
+
+       wpabuf_put_u8(buf, WLAN_ACTION_WNM);
+       wpabuf_put_u8(buf, WNM_NOTIFICATION_REQ);
+       wpabuf_put_u8(buf, 1); /* Dialog token */
+       wpabuf_put_u8(buf, 1); /* Type - 1 reserved for WFA */
+
+       /* Subscription Remediation subelement */
+       wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
+       wpabuf_put_u8(buf, 5 + len);
+       wpabuf_put_be24(buf, OUI_WFA);
+       wpabuf_put_u8(buf, HS20_WNM_SUB_REM_NEEDED);
+       if (url) {
+               wpabuf_put_u8(buf, len - 1);
+               wpabuf_put_data(buf, url, len - 1);
+               wpabuf_put_u8(buf, osu_method);
+       } else {
+               /* Server URL and Server Method fields not included */
+               wpabuf_put_u8(buf, 0);
+       }
+
+       ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
+                                     wpabuf_head(buf), wpabuf_len(buf));
+
+       wpabuf_free(buf);
+
+       return ret;
+}
index 98698ce..059764e 100644 (file)
@@ -12,5 +12,7 @@
 struct hostapd_data;
 
 u8 * hostapd_eid_hs20_indication(struct hostapd_data *hapd, u8 *eid);
+int hs20_send_wnm_notification(struct hostapd_data *hapd, const u8 *addr,
+                              u8 osu_method, const char *url);
 
 #endif /* HS20_H */
index eadaa4d..b78fd01 100644 (file)
@@ -199,6 +199,10 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
                }
                break;
        case 5: /* Bits 40-47 */
+#ifdef CONFIG_HS20
+               if (hapd->conf->hs20)
+                       *pos |= 0x40; /* Bit 46 - WNM-Notification */
+#endif /* CONFIG_HS20 */
                break;
        case 6: /* Bits 48-55 */
                if (hapd->conf->ssid.utf8_ssid)
@@ -225,6 +229,10 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
        if (len < 4)
                len = 4;
 #endif /* CONFIG_WNM */
+#ifdef CONFIG_HS20
+       if (hapd->conf->hs20 && len < 6)
+               len = 6;
+#endif /* CONFIG_HS20 */
        if (len < hapd->iface->extended_capa_len)
                len = hapd->iface->extended_capa_len;
        if (len == 0)