HS 2.0R2 AP: Add support for deauthentication request

If the RADIUS server includes deauthentication request in Access-Accept,
send a WNM-Notification frame to the station after 4-way handshake and
disconnect the station after configurable timeout.

A new control interface command, WNM_DEAUTH_REQ, is added for testing
purposes to allow the notification frame to sent based on local request.
This case does not disconnect the station automatically, i.e., a
separate control interface command would be needed for that.

Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
Jouni Malinen 2013-07-26 22:13:58 +03:00 committed by Jouni Malinen
parent a14896e8bb
commit 8e1146d9da
11 changed files with 167 additions and 0 deletions

View file

@ -465,6 +465,7 @@ struct hostapd_bss_config {
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_*) */

View file

@ -140,3 +140,38 @@ int hs20_send_wnm_notification(struct hostapd_data *hapd, const u8 *addr,
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;
}

View file

@ -15,5 +15,8 @@ u8 * hostapd_eid_hs20_indication(struct hostapd_data *hapd, u8 *eid);
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 */

View file

@ -1265,6 +1265,27 @@ static void ieee802_1x_hs20_sub_rem(struct sta_info *sta, u8 *pos, size_t len)
/* 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 */
@ -1278,6 +1299,8 @@ static void ieee802_1x_check_hs20(struct hostapd_data *hapd,
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)
@ -1302,6 +1325,9 @@ static void ieee802_1x_check_hs20(struct hostapd_data *hapd,
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 */
@ -1468,6 +1494,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
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) {
@ -2234,11 +2261,20 @@ static void ieee802_1x_finished(struct hostapd_data *hapd,
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,

View file

@ -266,6 +266,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
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);

View file

@ -58,6 +58,7 @@ struct sta_info {
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];
@ -128,6 +129,7 @@ struct sta_info {
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;

View file

@ -171,6 +171,7 @@ enum {
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