HS 2.0R2 AP: Add WNM-Notification Request for Subscription Remediation
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>
This commit is contained in:
parent
d5d24784e6
commit
3fb17a9530
5 changed files with 115 additions and 0 deletions
|
@ -30,6 +30,7 @@
|
||||||
#include "ap/wps_hostapd.h"
|
#include "ap/wps_hostapd.h"
|
||||||
#include "ap/ctrl_iface_ap.h"
|
#include "ap/ctrl_iface_ap.h"
|
||||||
#include "ap/ap_drv_ops.h"
|
#include "ap/ap_drv_ops.h"
|
||||||
|
#include "ap/hs20.h"
|
||||||
#include "ap/wnm_ap.h"
|
#include "ap/wnm_ap.h"
|
||||||
#include "ap/wpa_auth.h"
|
#include "ap/wpa_auth.h"
|
||||||
#include "wps/wps_defs.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 */
|
#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
|
#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))
|
if (hostapd_ctrl_iface_send_qos_map_conf(hapd, buf + 18))
|
||||||
reply_len = -1;
|
reply_len = -1;
|
||||||
#endif /* CONFIG_INTERWORKING */
|
#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
|
#ifdef CONFIG_WNM
|
||||||
} else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) {
|
} else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) {
|
||||||
if (hostapd_ctrl_iface_disassoc_imminent(hapd, buf + 18))
|
if (hostapd_ctrl_iface_disassoc_imminent(hapd, buf + 18))
|
||||||
|
|
|
@ -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[])
|
static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||||
{
|
{
|
||||||
hostapd_cli_quit = 1;
|
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 },
|
{ "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set },
|
||||||
{ "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf },
|
{ "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf },
|
||||||
{ "chan_switch", hostapd_cli_cmd_chan_switch },
|
{ "chan_switch", hostapd_cli_cmd_chan_switch },
|
||||||
|
{ "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "common/ieee802_11_defs.h"
|
#include "common/ieee802_11_defs.h"
|
||||||
#include "hostapd.h"
|
#include "hostapd.h"
|
||||||
#include "ap_config.h"
|
#include "ap_config.h"
|
||||||
|
#include "ap_drv_ops.h"
|
||||||
#include "hs20.h"
|
#include "hs20.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,3 +37,54 @@ u8 * hostapd_eid_hs20_indication(struct hostapd_data *hapd, u8 *eid)
|
||||||
|
|
||||||
return 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;
|
||||||
|
}
|
||||||
|
|
|
@ -12,5 +12,7 @@
|
||||||
struct hostapd_data;
|
struct hostapd_data;
|
||||||
|
|
||||||
u8 * hostapd_eid_hs20_indication(struct hostapd_data *hapd, u8 *eid);
|
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 */
|
#endif /* HS20_H */
|
||||||
|
|
|
@ -199,6 +199,10 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 5: /* Bits 40-47 */
|
case 5: /* Bits 40-47 */
|
||||||
|
#ifdef CONFIG_HS20
|
||||||
|
if (hapd->conf->hs20)
|
||||||
|
*pos |= 0x40; /* Bit 46 - WNM-Notification */
|
||||||
|
#endif /* CONFIG_HS20 */
|
||||||
break;
|
break;
|
||||||
case 6: /* Bits 48-55 */
|
case 6: /* Bits 48-55 */
|
||||||
if (hapd->conf->ssid.utf8_ssid)
|
if (hapd->conf->ssid.utf8_ssid)
|
||||||
|
@ -225,6 +229,10 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
|
||||||
if (len < 4)
|
if (len < 4)
|
||||||
len = 4;
|
len = 4;
|
||||||
#endif /* CONFIG_WNM */
|
#endif /* CONFIG_WNM */
|
||||||
|
#ifdef CONFIG_HS20
|
||||||
|
if (hapd->conf->hs20 && len < 6)
|
||||||
|
len = 6;
|
||||||
|
#endif /* CONFIG_HS20 */
|
||||||
if (len < hapd->iface->extended_capa_len)
|
if (len < hapd->iface->extended_capa_len)
|
||||||
len = hapd->iface->extended_capa_len;
|
len = hapd->iface->extended_capa_len;
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
|
|
Loading…
Reference in a new issue