diff --git a/hostapd/Makefile b/hostapd/Makefile index 9e42d037f..2a82920e7 100644 --- a/hostapd/Makefile +++ b/hostapd/Makefile @@ -169,6 +169,10 @@ ifdef CONFIG_IEEE80211N CFLAGS += -DCONFIG_IEEE80211N endif +ifdef CONFIG_WNM +CFLAGS += -DCONFIG_WNM +endif + include ../src/drivers/drivers.mak OBJS += $(DRV_AP_OBJS) CFLAGS += $(DRV_AP_CFLAGS) diff --git a/hostapd/defconfig b/hostapd/defconfig index 3cf0d13bd..dea296c59 100644 --- a/hostapd/defconfig +++ b/hostapd/defconfig @@ -136,6 +136,10 @@ CONFIG_IPV6=y # IEEE 802.11n (High Throughput) support #CONFIG_IEEE80211N=y +# Wireless Network Management (IEEE Std 802.11v-2011) +# Note: This is experimental and not complete implementation. +#CONFIG_WNM=y + # Remove debugging code that is printing out debug messages to stdout. # This can be used to reduce the size of the hostapd considerably if debugging # code is not needed. diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index f305b07de..3996c90d7 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -876,6 +876,7 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, #endif /* CONFIG_IEEE80211N */ p = hostapd_eid_ext_capab(hapd, p); + p = hostapd_eid_bss_max_idle_period(hapd, p); if (sta->flags & WLAN_STA_WMM) p = hostapd_eid_wmm(hapd, p); diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h index d30e90f3b..b60350f4a 100644 --- a/src/ap/ieee802_11.h +++ b/src/ap/ieee802_11.h @@ -72,5 +72,6 @@ u8 * hostapd_eid_time_adv(struct hostapd_data *hapd, u8 *eid); u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid); int hostapd_update_time_adv(struct hostapd_data *hapd); void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr); +u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid); #endif /* IEEE802_11_H */ diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c index 0935cd501..b3fdf3d6e 100644 --- a/src/ap/ieee802_11_shared.c +++ b/src/ap/ieee802_11_shared.c @@ -1,6 +1,6 @@ /* * hostapd / IEEE 802.11 Management - * Copyright (c) 2002-2010, Jouni Malinen + * Copyright (c) 2002-2012, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -397,3 +397,31 @@ int hostapd_update_time_adv(struct hostapd_data *hapd) return 0; } + + +u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid) +{ + u8 *pos = eid; + +#ifdef CONFIG_WNM + if (hapd->conf->ap_max_inactivity > 0) { + unsigned int val; + *pos++ = WLAN_EID_BSS_MAX_IDLE_PERIOD; + *pos++ = 3; + val = hapd->conf->ap_max_inactivity; + if (val > 68000) + val = 68000; + val *= 1000; + val /= 1024; + if (val == 0) + val = 1; + if (val > 65535) + val = 65535; + WPA_PUT_LE16(pos, val); + pos += 2; + *pos++ = 0x00; /* TODO: Protected Keep-Alive Required */ + } +#endif /* CONFIG_WNM */ + + return pos; +} diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c index 5b2f2d567..d65675cde 100644 --- a/src/common/ieee802_11_common.c +++ b/src/common/ieee802_11_common.c @@ -1,6 +1,6 @@ /* * IEEE 802.11 Common routines - * Copyright (c) 2002-2009, Jouni Malinen + * Copyright (c) 2002-2012, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -262,6 +262,15 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, elems->interworking = pos; elems->interworking_len = elen; break; + case WLAN_EID_EXT_CAPAB: + elems->ext_capab = pos; + elems->ext_capab_len = elen; + break; + case WLAN_EID_BSS_MAX_IDLE_PERIOD: + if (elen < 3) + break; + elems->bss_max_idle_period = pos; + break; default: unknown++; if (!show_errors) diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h index 60f13a6a3..d9b2b6c1f 100644 --- a/src/common/ieee802_11_common.h +++ b/src/common/ieee802_11_common.h @@ -38,6 +38,8 @@ struct ieee802_11_elems { const u8 *link_id; const u8 *interworking; const u8 *hs20; + const u8 *ext_capab; + const u8 *bss_max_idle_period; u8 ssid_len; u8 supp_rates_len; @@ -65,6 +67,7 @@ struct ieee802_11_elems { u8 p2p_len; u8 interworking_len; u8 hs20_len; + u8 ext_capab_len; }; typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes; diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index 27b9e61a0..02062944e 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -228,6 +228,7 @@ #define WLAN_EID_20_40_BSS_INTOLERANT 73 #define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74 #define WLAN_EID_MMIE 76 +#define WLAN_EID_BSS_MAX_IDLE_PERIOD 90 #define WLAN_EID_TFS_REQ 91 #define WLAN_EID_TFS_RESP 92 #define WLAN_EID_WNMSLEEP 93 diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index 1d66aa76d..ab2dc8557 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -722,6 +722,10 @@ ifdef CONFIG_IEEE80211N CFLAGS += -DCONFIG_IEEE80211N endif +ifdef CONFIG_WNM +CFLAGS += -DCONFIG_WNM +endif + ifdef NEED_AP_MLME OBJS += ../src/ap/wmm.o OBJS += ../src/ap/ap_list.o diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig index 2d6bc8184..de5e74197 100644 --- a/wpa_supplicant/defconfig +++ b/wpa_supplicant/defconfig @@ -476,6 +476,10 @@ CONFIG_PEERKEY=y # IEEE 802.11n (High Throughput) support (mainly for AP mode) #CONFIG_IEEE80211N=y +# Wireless Network Management (IEEE Std 802.11v-2011) +# Note: This is experimental and not complete implementation. +#CONFIG_WNM=y + # Interworking (IEEE 802.11u) # This can be used to enable functionality to improve interworking with # external networks (GAS/ANQP to learn more about the networks and network diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 407407ad3..3e2fe1886 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -103,6 +103,8 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s) { int bssid_changed; + wnm_bss_keep_alive_deinit(wpa_s); + #ifdef CONFIG_IBSS_RSN ibss_rsn_deinit(wpa_s->ibss_rsn); wpa_s->ibss_rsn = NULL; @@ -1200,6 +1202,78 @@ static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, #endif /* CONFIG_NO_SCAN_PROCESSING */ +#ifdef CONFIG_WNM + +static void wnm_bss_keep_alive(void *eloop_ctx, void *sock_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + + if (wpa_s->wpa_state < WPA_ASSOCIATED) + return; + + wpa_printf(MSG_DEBUG, "WNM: Send keep-alive"); + /* TODO: could skip this if normal data traffic has been sent */ + /* TODO: send keep alive frame - better use some short unicast data + * frame that gets protected if PTK is set */ + + if (wpa_s->sme.bss_max_idle_period) { + unsigned int msec; + msec = wpa_s->sme.bss_max_idle_period * 1024; /* times 1000 */ + if (msec > 100) + msec -= 100; + eloop_register_timeout(msec / 1000, msec % 1000 * 1000, + wnm_bss_keep_alive, wpa_s, NULL); + } +} + + +static void wnm_process_assoc_resp(struct wpa_supplicant *wpa_s, + const u8 *ies, size_t ies_len) +{ + struct ieee802_11_elems elems; + + if (ies == NULL) + return; + + if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) + return; + +#ifdef CONFIG_SME + if (elems.bss_max_idle_period) { + unsigned int msec; + wpa_s->sme.bss_max_idle_period = + WPA_GET_LE16(elems.bss_max_idle_period); + wpa_printf(MSG_DEBUG, "WNM: BSS Max Idle Period: %u (* 1000 " + "TU)%s", wpa_s->sme.bss_max_idle_period, + (elems.bss_max_idle_period[2] & 0x01) ? + " (protected keep-live required)" : ""); + if (wpa_s->sme.bss_max_idle_period == 0) + wpa_s->sme.bss_max_idle_period = 1; + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) { + eloop_cancel_timeout(wnm_bss_keep_alive, wpa_s, NULL); + /* msec times 1000 */ + msec = wpa_s->sme.bss_max_idle_period * 1024; + if (msec > 100) + msec -= 100; + eloop_register_timeout(msec / 1000, msec % 1000 * 1000, + wnm_bss_keep_alive, wpa_s, + NULL); + } + } +#endif /* CONFIG_SME */ +} + +#endif /* CONFIG_WNM */ + + +void wnm_bss_keep_alive_deinit(struct wpa_supplicant *wpa_s) +{ +#ifdef CONFIG_WNM + eloop_cancel_timeout(wnm_bss_keep_alive, wpa_s, NULL); +#endif /* CONFIG_WNM */ +} + + static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, union wpa_event_data *data) { @@ -1217,6 +1291,10 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, wpa_tdls_assoc_resp_ies(wpa_s->wpa, data->assoc_info.resp_ies, data->assoc_info.resp_ies_len); #endif /* CONFIG_TDLS */ +#ifdef CONFIG_WNM + wnm_process_assoc_resp(wpa_s, data->assoc_info.resp_ies, + data->assoc_info.resp_ies_len); +#endif /* CONFIG_WNM */ } if (data->assoc_info.beacon_ies) wpa_hexdump(MSG_DEBUG, "beacon_ies", diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 09b164022..3cb954db8 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -449,6 +449,8 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) os_free(wpa_s->bssid_filter); wpa_s->bssid_filter = NULL; + + wnm_bss_keep_alive_deinit(wpa_s); } diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 23ffd7d42..dadeafb0a 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -423,6 +423,7 @@ struct wpa_supplicant { struct os_time sa_query_start; u8 sched_obss_scan; u16 obss_scan_int; + u16 bss_max_idle_period; } sme; #endif /* CONFIG_SME */ @@ -664,6 +665,7 @@ int wpa_supplicant_connect(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); void wpa_supplicant_stop_countermeasures(void *eloop_ctx, void *sock_ctx); void wpa_supplicant_delayed_mic_error_report(void *eloop_ctx, void *sock_ctx); +void wnm_bss_keep_alive_deinit(struct wpa_supplicant *wpa_s); /* eap_register.c */ int eap_register_methods(void);