bss->osen = atoi(pos);
} else if (os_strcmp(buf, "anqp_domain_id") == 0) {
bss->anqp_domain_id = atoi(pos);
+ } else if (os_strcmp(buf, "hs20_deauth_req_timeout") == 0) {
+ bss->hs20_deauth_req_timeout = atoi(pos);
} else if (os_strcmp(buf, "hs20_oper_friendly_name") == 0) {
if (hs20_parse_oper_friendly_name(bss, pos, line) < 0)
errors++;
return hs20_send_wnm_notification(hapd, addr, 1, url);
}
+
+static int hostapd_ctrl_iface_hs20_deauth_req(struct hostapd_data *hapd,
+ const char *cmd)
+{
+ u8 addr[ETH_ALEN];
+ int code, reauth_delay, ret;
+ const char *pos;
+ size_t url_len;
+ struct wpabuf *req;
+
+ /* <STA MAC Addr> <Code(0/1)> <Re-auth-Delay(sec)> [URL] */
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+
+ pos = os_strchr(cmd, ' ');
+ if (pos == NULL)
+ return -1;
+ pos++;
+ code = atoi(pos);
+
+ pos = os_strchr(pos, ' ');
+ if (pos == NULL)
+ return -1;
+ pos++;
+ reauth_delay = atoi(pos);
+
+ url_len = 0;
+ pos = os_strchr(pos, ' ');
+ if (pos) {
+ pos++;
+ url_len = os_strlen(pos);
+ }
+
+ req = wpabuf_alloc(4 + url_len);
+ if (req == NULL)
+ return -1;
+ wpabuf_put_u8(req, code);
+ wpabuf_put_le16(req, reauth_delay);
+ wpabuf_put_u8(req, url_len);
+ if (pos)
+ wpabuf_put_data(req, pos, url_len);
+
+ wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to " MACSTR
+ " to indicate imminent deauthentication (code=%d "
+ "reauth_delay=%d)", MAC2STR(addr), code, reauth_delay);
+ ret = hs20_send_wnm_notification_deauth_req(hapd, addr, req);
+ wpabuf_free(req);
+ return ret;
+}
+
#endif /* 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;
+ } else if (os_strncmp(buf, "HS20_DEAUTH_REQ ", 16) == 0) {
+ if (hostapd_ctrl_iface_hs20_deauth_req(hapd, buf + 16))
+ reply_len = -1;
#endif /* CONFIG_HS20 */
#ifdef CONFIG_WNM
} else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) {
# information. 0 = Some of the ANQP information is unique to this AP (default).
#anqp_domain_id=1234
+# Deauthentication request timeout
+# If the RADIUS server indicates that the station is not allowed to connect to
+# the BSS/ESS, the AP can allow the station some time to download a
+# notification page (URL included in the message). This parameter sets that
+# timeout in seconds.
+#hs20_deauth_req_timeout=60
+
# Operator Friendly Name
# This parameter can be used to configure one or more Operator Friendly Name
# Duples. Each entry has a two or three character language code (ISO-639)
}
+static int hostapd_cli_cmd_hs20_deauth_req(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char buf[300];
+ int res;
+
+ if (argc < 3) {
+ printf("Invalid 'hs20_deauth_req' command - at least three arguments (STA addr, Code, Re-auth Delay) are needed\n");
+ return -1;
+ }
+
+ if (argc > 3)
+ res = os_snprintf(buf, sizeof(buf),
+ "HS20_DEAUTH_REQ %s %s %s %s",
+ argv[0], argv[1], argv[2], argv[3]);
+ else
+ res = os_snprintf(buf, sizeof(buf),
+ "HS20_DEAUTH_REQ %s %s %s",
+ argv[0], argv[1], argv[2]);
+ 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;
{ "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 },
+ { "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req },
{ NULL, NULL }
};
size_t hs20_connection_capability_len;
u8 *hs20_operating_class;
u8 hs20_operating_class_len;
+ unsigned int hs20_deauth_req_timeout;
#endif /* CONFIG_HS20 */
u8 wps_rf_bands; /* RF bands for WPS (WPS_RF_*) */
return ret;
}
+
+
+int hs20_send_wnm_notification_deauth_req(struct hostapd_data *hapd,
+ const u8 *addr,
+ const struct wpabuf *payload)
+{
+ struct wpabuf *buf;
+ 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 */
+
+ buf = wpabuf_alloc(4 + 6 + wpabuf_len(payload));
+ 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 */
+
+ /* Deauthentication Imminent Notice subelement */
+ wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
+ wpabuf_put_u8(buf, 4 + wpabuf_len(payload));
+ wpabuf_put_be24(buf, OUI_WFA);
+ wpabuf_put_u8(buf, HS20_WNM_DEAUTH_IMMINENT_NOTICE);
+ wpabuf_put_buf(buf, payload);
+
+ ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
+ wpabuf_head(buf), wpabuf_len(buf));
+
+ wpabuf_free(buf);
+
+ return ret;
+}
u8 * hostapd_eid_osen(struct hostapd_data *hapd, u8 *eid);
int hs20_send_wnm_notification(struct hostapd_data *hapd, const u8 *addr,
u8 osu_method, const char *url);
+int hs20_send_wnm_notification_deauth_req(struct hostapd_data *hapd,
+ const u8 *addr,
+ const struct wpabuf *payload);
#endif /* HS20_H */
/* TODO: assign the STA into remediation VLAN or add filtering */
}
+
+static void ieee802_1x_hs20_deauth_req(struct hostapd_data *hapd,
+ struct sta_info *sta, u8 *pos,
+ size_t len)
+{
+ if (len < 3)
+ return; /* Malformed information */
+ sta->hs20_deauth_requested = 1;
+ wpa_printf(MSG_DEBUG, "HS 2.0: Deauthentication request - Code %u "
+ "Re-auth Delay %u",
+ *pos, WPA_GET_LE16(pos + 1));
+ wpabuf_free(sta->hs20_deauth_req);
+ sta->hs20_deauth_req = wpabuf_alloc(len + 1);
+ if (sta->hs20_deauth_req) {
+ wpabuf_put_data(sta->hs20_deauth_req, pos, 3);
+ wpabuf_put_u8(sta->hs20_deauth_req, len - 3);
+ wpabuf_put_data(sta->hs20_deauth_req, pos + 3, len - 3);
+ }
+ ap_sta_session_timeout(hapd, sta, hapd->conf->hs20_deauth_req_timeout);
+}
+
#endif /* CONFIG_HS20 */
buf = NULL;
sta->remediation = 0;
+ sta->hs20_deauth_requested = 0;
+
for (;;) {
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
&buf, &len, buf) < 0)
case RADIUS_VENDOR_ATTR_WFA_HS20_SUBSCR_REMEDIATION:
ieee802_1x_hs20_sub_rem(sta, pos, sublen);
break;
+ case RADIUS_VENDOR_ATTR_WFA_HS20_DEAUTH_REQ:
+ ieee802_1x_hs20_deauth_req(hapd, sta, pos, sublen);
+ break;
}
}
#endif /* CONFIG_HS20 */
ieee802_1x_update_sta_cui(hapd, sta, msg);
ieee802_1x_check_hs20(hapd, sta, msg);
if (sm->eap_if->eapKeyAvailable && !sta->remediation &&
+ !sta->hs20_deauth_requested &&
wpa_auth_pmksa_add(sta->wpa_sm, sm->eapol_key_crypt,
session_timeout_set ?
(int) session_timeout : -1, sm) == 0) {
os_free(sta->remediation_url);
sta->remediation_url = NULL;
}
+
+ if (sta->hs20_deauth_req) {
+ wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification "
+ "to " MACSTR " to indicate imminent "
+ "deauthentication", MAC2STR(sta->addr));
+ hs20_send_wnm_notification_deauth_req(
+ hapd, sta->addr, sta->hs20_deauth_req);
+ }
}
#endif /* CONFIG_HS20 */
key = ieee802_1x_get_key(sta->eapol_sm, &len);
if (success && key && len >= PMK_LEN && !sta->remediation &&
+ !sta->hs20_deauth_requested &&
wpa_auth_pmksa_add(sta->wpa_sm, key, dot11RSNAConfigPMKLifetime,
sta->eapol_sm) == 0) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
os_free(sta->identity);
os_free(sta->radius_cui);
os_free(sta->remediation_url);
+ wpabuf_free(sta->hs20_deauth_req);
#ifdef CONFIG_SAE
sae_clear_data(sta->sae);
unsigned int no_p2p_set:1;
unsigned int qos_map_enabled:1;
unsigned int remediation:1;
+ unsigned int hs20_deauth_requested:1;
u16 auth_alg;
u8 previous_ap[6];
struct wpabuf *hs20_ie; /* HS 2.0 IE from (Re)Association Request */
u8 remediation_method;
char *remediation_url; /* HS 2.0 Subscription Remediation Server URL */
+ struct wpabuf *hs20_deauth_req;
struct os_reltime connected_time;
RADIUS_VENDOR_ATTR_WFA_HS20_SUBSCR_REMEDIATION = 1,
RADIUS_VENDOR_ATTR_WFA_HS20_AP_VERSION = 2,
RADIUS_VENDOR_ATTR_WFA_HS20_STA_VERSION = 3,
+ RADIUS_VENDOR_ATTR_WFA_HS20_DEAUTH_REQ = 4,
};
#ifdef _MSC_VER