diff options
Diffstat (limited to 'src/ap')
33 files changed, 1754 insertions, 1125 deletions
diff --git a/src/ap/accounting.c b/src/ap/accounting.c index dbfb058..03421b3 100644 --- a/src/ap/accounting.c +++ b/src/ap/accounting.c @@ -236,6 +236,7 @@ static void accounting_interim_update(void *eloop_ctx, void *timeout_ctx) void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta) { struct radius_msg *msg; + struct os_time t; int interval; if (sta->acct_session_started) @@ -247,7 +248,8 @@ void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta) "starting accounting session %08X-%08X", sta->acct_session_id_hi, sta->acct_session_id_lo); - time(&sta->acct_session_start); + os_get_time(&t); + sta->acct_session_start = t.sec; sta->last_rx_bytes = sta->last_tx_bytes = 0; sta->acct_input_gigawords = sta->acct_output_gigawords = 0; hostapd_drv_sta_clear_stats(hapd, sta->addr); diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index e77716b..b24cd90 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -426,6 +426,8 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf) ssid->dyn_vlan_keys = NULL; } + os_free(conf->time_zone); + #ifdef CONFIG_IEEE80211R { struct ft_remote_r0kh *r0kh, *r0kh_prev; @@ -467,6 +469,12 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf) os_free(conf->model_url); os_free(conf->upc); #endif /* CONFIG_WPS */ + + os_free(conf->roaming_consortium); + +#ifdef CONFIG_RADIUS_TEST + os_free(conf->dump_msk_file); +#endif /* CONFIG_RADIUS_TEST */ } diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 09eed5a..485092d 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -104,7 +104,6 @@ struct hostapd_wpa_psk { u8 addr[ETH_ALEN]; }; -#define EAP_USER_MAX_METHODS 8 struct hostapd_eap_user { struct hostapd_eap_user *next; u8 *identity; @@ -112,7 +111,7 @@ struct hostapd_eap_user { struct { int vendor; u32 method; - } methods[EAP_USER_MAX_METHODS]; + } methods[EAP_MAX_METHODS]; u8 *password; size_t password_len; int phase2; @@ -142,6 +141,13 @@ struct hostapd_wmm_ac_params { }; +#define MAX_ROAMING_CONSORTIUM_LEN 15 + +struct hostapd_roaming_consortium { + u8 len; + u8 oi[MAX_ROAMING_CONSORTIUM_LEN]; +}; + /** * struct hostapd_bss_config - Per-BSS configuration */ @@ -213,6 +219,11 @@ struct hostapd_bss_config { /* dot11AssociationSAQueryRetryTimeout (in TUs) */ int assoc_sa_query_retry_timeout; #endif /* CONFIG_IEEE80211W */ + enum { + PSK_RADIUS_IGNORED = 0, + PSK_RADIUS_ACCEPTED = 1, + PSK_RADIUS_REQUIRED = 2 + } wpa_psk_radius; int wpa_pairwise; int wpa_group; int wpa_group_rekey; @@ -329,11 +340,38 @@ struct hostapd_bss_config { int p2p; int disassoc_low_ack; + int skip_inactivity_poll; #define TDLS_PROHIBIT BIT(0) #define TDLS_PROHIBIT_CHAN_SWITCH BIT(1) int tdls; int disable_11n; + + /* IEEE 802.11v */ + int time_advertisement; + char *time_zone; + + /* IEEE 802.11u - Interworking */ + int interworking; + int access_network_type; + int internet; + int asra; + int esr; + int uesa; + int venue_info_set; + u8 venue_group; + u8 venue_type; + u8 hessid[ETH_ALEN]; + + /* IEEE 802.11u - Roaming Consortium list */ + unsigned int roaming_consortium_count; + struct hostapd_roaming_consortium *roaming_consortium; + + u8 wps_rf_bands; /* RF bands for WPS (WPS_RF_*) */ + +#ifdef CONFIG_RADIUS_TEST + char *dump_msk_file; +#endif /* CONFIG_RADIUS_TEST */ }; @@ -354,12 +392,6 @@ struct hostapd_config { LONG_PREAMBLE = 0, SHORT_PREAMBLE = 1 } preamble; - enum { - CTS_PROTECTION_AUTOMATIC = 0, - CTS_PROTECTION_FORCE_ENABLED = 1, - CTS_PROTECTION_FORCE_DISABLED = 2, - CTS_PROTECTION_AUTOMATIC_NO_OLBC = 3, - } cts_protection_type; int *supported_rates; int *basic_rates; diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c index 0b6836c..429c187 100644 --- a/src/ap/ap_drv_ops.c +++ b/src/ap/ap_drv_ops.c @@ -41,117 +41,159 @@ u32 hostapd_sta_flags_to_drv(u32 flags) } -int hostapd_set_ap_wps_ie(struct hostapd_data *hapd) +int hostapd_build_ap_extra_ies(struct hostapd_data *hapd, + struct wpabuf **beacon_ret, + struct wpabuf **proberesp_ret, + struct wpabuf **assocresp_ret) { - struct wpabuf *beacon, *proberesp, *assocresp = NULL; - int ret; + struct wpabuf *beacon = NULL, *proberesp = NULL, *assocresp = NULL; + u8 buf[200], *pos; - if (hapd->driver == NULL || hapd->driver->set_ap_wps_ie == NULL) - return 0; + *beacon_ret = *proberesp_ret = *assocresp_ret = NULL; + + pos = buf; + pos = hostapd_eid_time_adv(hapd, pos); + if (pos != buf) { + if (wpabuf_resize(&beacon, pos - buf) != 0) + goto fail; + wpabuf_put_data(beacon, buf, pos - buf); + } + pos = hostapd_eid_time_zone(hapd, pos); + if (pos != buf) { + if (wpabuf_resize(&proberesp, pos - buf) != 0) + goto fail; + wpabuf_put_data(proberesp, buf, pos - buf); + } + + pos = buf; + pos = hostapd_eid_ext_capab(hapd, pos); + if (pos != buf) { + if (wpabuf_resize(&assocresp, pos - buf) != 0) + goto fail; + wpabuf_put_data(assocresp, buf, pos - buf); + } + pos = hostapd_eid_interworking(hapd, pos); + pos = hostapd_eid_adv_proto(hapd, pos); + pos = hostapd_eid_roaming_consortium(hapd, pos); + if (pos != buf) { + if (wpabuf_resize(&beacon, pos - buf) != 0) + goto fail; + wpabuf_put_data(beacon, buf, pos - buf); + + if (wpabuf_resize(&proberesp, pos - buf) != 0) + goto fail; + wpabuf_put_data(proberesp, buf, pos - buf); + } + + if (hapd->wps_beacon_ie) { + if (wpabuf_resize(&beacon, wpabuf_len(hapd->wps_beacon_ie)) < + 0) + goto fail; + wpabuf_put_buf(beacon, hapd->wps_beacon_ie); + } - beacon = hapd->wps_beacon_ie; - proberesp = hapd->wps_probe_resp_ie; + if (hapd->wps_probe_resp_ie) { + if (wpabuf_resize(&proberesp, + wpabuf_len(hapd->wps_probe_resp_ie)) < 0) + goto fail; + wpabuf_put_buf(proberesp, hapd->wps_probe_resp_ie); + } #ifdef CONFIG_P2P - if (hapd->wps_beacon_ie == NULL && hapd->p2p_beacon_ie == NULL) - beacon = NULL; - else { - beacon = wpabuf_alloc((hapd->wps_beacon_ie ? - wpabuf_len(hapd->wps_beacon_ie) : 0) + - (hapd->p2p_beacon_ie ? - wpabuf_len(hapd->p2p_beacon_ie) : 0)); - if (beacon == NULL) - return -1; - if (hapd->wps_beacon_ie) - wpabuf_put_buf(beacon, hapd->wps_beacon_ie); - if (hapd->p2p_beacon_ie) - wpabuf_put_buf(beacon, hapd->p2p_beacon_ie); + if (hapd->p2p_beacon_ie) { + if (wpabuf_resize(&beacon, wpabuf_len(hapd->p2p_beacon_ie)) < + 0) + goto fail; + wpabuf_put_buf(beacon, hapd->p2p_beacon_ie); } - if (hapd->wps_probe_resp_ie == NULL && hapd->p2p_probe_resp_ie == NULL) - proberesp = NULL; - else { - proberesp = wpabuf_alloc( - (hapd->wps_probe_resp_ie ? - wpabuf_len(hapd->wps_probe_resp_ie) : 0) + - (hapd->p2p_probe_resp_ie ? - wpabuf_len(hapd->p2p_probe_resp_ie) : 0)); - if (proberesp == NULL) { - wpabuf_free(beacon); - return -1; - } - if (hapd->wps_probe_resp_ie) - wpabuf_put_buf(proberesp, hapd->wps_probe_resp_ie); - if (hapd->p2p_probe_resp_ie) - wpabuf_put_buf(proberesp, hapd->p2p_probe_resp_ie); + if (hapd->p2p_probe_resp_ie) { + if (wpabuf_resize(&proberesp, + wpabuf_len(hapd->p2p_probe_resp_ie)) < 0) + goto fail; + wpabuf_put_buf(proberesp, hapd->p2p_probe_resp_ie); } #endif /* CONFIG_P2P */ #ifdef CONFIG_P2P_MANAGER if (hapd->conf->p2p & P2P_MANAGE) { - struct wpabuf *a; - - a = wpabuf_alloc(100 + (beacon ? wpabuf_len(beacon) : 0)); - if (a) { + if (wpabuf_resize(&beacon, 100) == 0) { u8 *start, *p; - if (beacon) - wpabuf_put_buf(a, beacon); - if (beacon != hapd->wps_beacon_ie) - wpabuf_free(beacon); - start = wpabuf_put(a, 0); + start = wpabuf_put(beacon, 0); p = hostapd_eid_p2p_manage(hapd, start); - wpabuf_put(a, p - start); - beacon = a; + wpabuf_put(beacon, p - start); } - a = wpabuf_alloc(100 + (proberesp ? wpabuf_len(proberesp) : - 0)); - if (a) { + if (wpabuf_resize(&proberesp, 100) == 0) { u8 *start, *p; - if (proberesp) - wpabuf_put_buf(a, proberesp); - if (proberesp != hapd->wps_probe_resp_ie) - wpabuf_free(proberesp); - start = wpabuf_put(a, 0); + start = wpabuf_put(proberesp, 0); p = hostapd_eid_p2p_manage(hapd, start); - wpabuf_put(a, p - start); - proberesp = a; + wpabuf_put(proberesp, p - start); } } #endif /* CONFIG_P2P_MANAGER */ #ifdef CONFIG_WPS2 - if (hapd->conf->wps_state) - assocresp = wps_build_assoc_resp_ie(); + if (hapd->conf->wps_state) { + struct wpabuf *a = wps_build_assoc_resp_ie(); + if (a && wpabuf_resize(&assocresp, wpabuf_len(a)) == 0) + wpabuf_put_buf(assocresp, a); + wpabuf_free(a); + } #endif /* CONFIG_WPS2 */ #ifdef CONFIG_P2P_MANAGER if (hapd->conf->p2p & P2P_MANAGE) { - struct wpabuf *a; - a = wpabuf_alloc(100 + (assocresp ? wpabuf_len(assocresp) : - 0)); - if (a) { + if (wpabuf_resize(&assocresp, 100) == 0) { u8 *start, *p; - start = wpabuf_put(a, 0); + start = wpabuf_put(assocresp, 0); p = hostapd_eid_p2p_manage(hapd, start); - wpabuf_put(a, p - start); - if (assocresp) { - wpabuf_put_buf(a, assocresp); - wpabuf_free(assocresp); - } - assocresp = a; + wpabuf_put(assocresp, p - start); } } #endif /* CONFIG_P2P_MANAGER */ + *beacon_ret = beacon; + *proberesp_ret = proberesp; + *assocresp_ret = assocresp; + + return 0; + +fail: + wpabuf_free(beacon); + wpabuf_free(proberesp); + wpabuf_free(assocresp); + return -1; +} + + +void hostapd_free_ap_extra_ies(struct hostapd_data *hapd, + struct wpabuf *beacon, + struct wpabuf *proberesp, + struct wpabuf *assocresp) +{ + wpabuf_free(beacon); + wpabuf_free(proberesp); + wpabuf_free(assocresp); +} + + +int hostapd_set_ap_wps_ie(struct hostapd_data *hapd) +{ + struct wpabuf *beacon, *proberesp, *assocresp; + int ret; + + if (hapd->driver == NULL || hapd->driver->set_ap_wps_ie == NULL) + return 0; + + if (hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp) < + 0) + return -1; + ret = hapd->driver->set_ap_wps_ie(hapd->drv_priv, beacon, proberesp, assocresp); - if (beacon != hapd->wps_beacon_ie) - wpabuf_free(beacon); - if (proberesp != hapd->wps_probe_resp_ie) - wpabuf_free(proberesp); - wpabuf_free(assocresp); + hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp); return ret; } @@ -211,74 +253,6 @@ int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname, } -static int hostapd_set_ap_isolate(struct hostapd_data *hapd, int value) -{ - if (hapd->driver == NULL || hapd->driver->set_intra_bss == NULL) - return 0; - return hapd->driver->set_intra_bss(hapd->drv_priv, !value); -} - - -int hostapd_set_bss_params(struct hostapd_data *hapd, int use_protection) -{ - int ret = 0; - int preamble; -#ifdef CONFIG_IEEE80211N - u8 buf[60], *ht_capab, *ht_oper, *pos; - - pos = buf; - ht_capab = pos; - pos = hostapd_eid_ht_capabilities(hapd, pos); - ht_oper = pos; - pos = hostapd_eid_ht_operation(hapd, pos); - if (pos > ht_oper && ht_oper > ht_capab && - hostapd_set_ht_params(hapd, ht_capab + 2, ht_capab[1], - ht_oper + 2, ht_oper[1])) { - wpa_printf(MSG_ERROR, "Could not set HT capabilities " - "for kernel driver"); - ret = -1; - } - -#endif /* CONFIG_IEEE80211N */ - - if (hostapd_set_cts_protect(hapd, use_protection)) { - wpa_printf(MSG_ERROR, "Failed to set CTS protect in kernel " - "driver"); - ret = -1; - } - - if (hapd->iface->current_mode && - hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G && - hostapd_set_short_slot_time(hapd, - hapd->iface->num_sta_no_short_slot_time - > 0 ? 0 : 1)) { - wpa_printf(MSG_ERROR, "Failed to set Short Slot Time option " - "in kernel driver"); - ret = -1; - } - - if (hapd->iface->num_sta_no_short_preamble == 0 && - hapd->iconf->preamble == SHORT_PREAMBLE) - preamble = SHORT_PREAMBLE; - else - preamble = LONG_PREAMBLE; - if (hostapd_set_preamble(hapd, preamble)) { - wpa_printf(MSG_ERROR, "Could not set preamble for kernel " - "driver"); - ret = -1; - } - - if (hostapd_set_ap_isolate(hapd, hapd->conf->isolate) && - hapd->conf->isolate) { - wpa_printf(MSG_ERROR, "Could not enable AP isolation in " - "kernel driver"); - ret = -1; - } - - return ret; -} - - int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname) { char force_ifname[IFNAMSIZ]; @@ -310,11 +284,41 @@ int hostapd_set_wds_sta(struct hostapd_data *hapd, const u8 *addr, int aid, } +int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr, + u16 auth_alg) +{ + if (hapd->driver == NULL || hapd->driver->add_sta_node == NULL) + return 0; + return hapd->driver->add_sta_node(hapd->drv_priv, addr, auth_alg); +} + + +int hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr, + u16 seq, u16 status, const u8 *ie, size_t len) +{ + if (hapd->driver == NULL || hapd->driver->sta_auth == NULL) + return 0; + return hapd->driver->sta_auth(hapd->drv_priv, hapd->own_addr, addr, + seq, status, ie, len); +} + + +int hostapd_sta_assoc(struct hostapd_data *hapd, const u8 *addr, + int reassoc, u16 status, const u8 *ie, size_t len) +{ + if (hapd->driver == NULL || hapd->driver->sta_assoc == NULL) + return 0; + return hapd->driver->sta_assoc(hapd->drv_priv, hapd->own_addr, addr, + reassoc, status, ie, len); +} + + int hostapd_sta_add(struct hostapd_data *hapd, const u8 *addr, u16 aid, u16 capability, const u8 *supp_rates, size_t supp_rates_len, u16 listen_interval, - const struct ieee80211_ht_capabilities *ht_capab) + const struct ieee80211_ht_capabilities *ht_capab, + u32 flags, u8 qosinfo) { struct hostapd_sta_add_params params; @@ -331,10 +335,22 @@ int hostapd_sta_add(struct hostapd_data *hapd, params.supp_rates_len = supp_rates_len; params.listen_interval = listen_interval; params.ht_capabilities = ht_capab; + params.flags = hostapd_sta_flags_to_drv(flags); + params.qosinfo = qosinfo; return hapd->driver->sta_add(hapd->drv_priv, ¶ms); } +int hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr, + u8 *tspec_ie, size_t tspec_ielen) +{ + if (hapd->driver == NULL || hapd->driver->add_tspec == NULL) + return 0; + return hapd->driver->add_tspec(hapd->drv_priv, addr, tspec_ie, + tspec_ielen); +} + + int hostapd_set_privacy(struct hostapd_data *hapd, int enabled) { if (hapd->driver == NULL || hapd->driver->set_privacy == NULL) @@ -460,16 +476,6 @@ int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr, } -int hostapd_set_rate_sets(struct hostapd_data *hapd, int *supp_rates, - int *basic_rates, int mode) -{ - if (hapd->driver == NULL || hapd->driver->set_rate_sets == NULL) - return 0; - return hapd->driver->set_rate_sets(hapd->drv_priv, supp_rates, - basic_rates, mode); -} - - int hostapd_set_country(struct hostapd_data *hapd, const char *country) { if (hapd->driver == NULL || @@ -479,30 +485,6 @@ int hostapd_set_country(struct hostapd_data *hapd, const char *country) } -int hostapd_set_cts_protect(struct hostapd_data *hapd, int value) -{ - if (hapd->driver == NULL || hapd->driver->set_cts_protect == NULL) - return 0; - return hapd->driver->set_cts_protect(hapd->drv_priv, value); -} - - -int hostapd_set_preamble(struct hostapd_data *hapd, int value) -{ - if (hapd->driver == NULL || hapd->driver->set_preamble == NULL) - return 0; - return hapd->driver->set_preamble(hapd->drv_priv, value); -} - - -int hostapd_set_short_slot_time(struct hostapd_data *hapd, int value) -{ - if (hapd->driver == NULL || hapd->driver->set_short_slot_time == NULL) - return 0; - return hapd->driver->set_short_slot_time(hapd->drv_priv, value); -} - - int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs, int cw_min, int cw_max, int burst_time) { @@ -513,15 +495,6 @@ int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs, } -int hostapd_valid_bss_mask(struct hostapd_data *hapd, const u8 *addr, - const u8 *mask) -{ - if (hapd->driver == NULL || hapd->driver->valid_bss_mask == NULL) - return 1; - return hapd->driver->valid_bss_mask(hapd->drv_priv, addr, mask); -} - - struct hostapd_hw_modes * hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes, u16 *flags) @@ -542,19 +515,6 @@ int hostapd_driver_commit(struct hostapd_data *hapd) } -int hostapd_set_ht_params(struct hostapd_data *hapd, - const u8 *ht_capab, size_t ht_capab_len, - const u8 *ht_oper, size_t ht_oper_len) -{ - if (hapd->driver == NULL || hapd->driver->set_ht_params == NULL || - ht_capab == NULL || ht_oper == NULL) - return 0; - return hapd->driver->set_ht_params(hapd->drv_priv, - ht_capab, ht_capab_len, - ht_oper, ht_oper_len); -} - - int hostapd_drv_none(struct hostapd_data *hapd) { return hapd->driver && os_strcmp(hapd->driver->name, "none") == 0; @@ -604,11 +564,11 @@ int hostapd_drv_set_key(const char *ifname, struct hostapd_data *hapd, int hostapd_drv_send_mlme(struct hostapd_data *hapd, - const void *msg, size_t len) + const void *msg, size_t len, int noack) { if (hapd->driver == NULL || hapd->driver->send_mlme == NULL) return 0; - return hapd->driver->send_mlme(hapd->drv_priv, msg, len); + return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack); } diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h index f6076af..835cdde 100644 --- a/src/ap/ap_drv_ops.h +++ b/src/ap/ap_drv_ops.h @@ -21,13 +21,19 @@ struct wpa_driver_scan_params; struct ieee80211_ht_capabilities; u32 hostapd_sta_flags_to_drv(u32 flags); +int hostapd_build_ap_extra_ies(struct hostapd_data *hapd, + struct wpabuf **beacon, + struct wpabuf **proberesp, + struct wpabuf **assocresp); +void hostapd_free_ap_extra_ies(struct hostapd_data *hapd, struct wpabuf *beacon, + struct wpabuf *proberesp, + struct wpabuf *assocresp); int hostapd_set_ap_wps_ie(struct hostapd_data *hapd); int hostapd_set_authorized(struct hostapd_data *hapd, struct sta_info *sta, int authorized); int hostapd_set_sta_flags(struct hostapd_data *hapd, struct sta_info *sta); int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname, int enabled); -int hostapd_set_bss_params(struct hostapd_data *hapd, int use_protection); int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname); int hostapd_vlan_if_remove(struct hostapd_data *hapd, const char *ifname); int hostapd_set_wds_sta(struct hostapd_data *hapd, const u8 *addr, int aid, @@ -36,7 +42,8 @@ int hostapd_sta_add(struct hostapd_data *hapd, const u8 *addr, u16 aid, u16 capability, const u8 *supp_rates, size_t supp_rates_len, u16 listen_interval, - const struct ieee80211_ht_capabilities *ht_capab); + const struct ieee80211_ht_capabilities *ht_capab, + u32 flags, u8 qosinfo); int hostapd_set_privacy(struct hostapd_data *hapd, int enabled); int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem, size_t elem_len); @@ -59,23 +66,13 @@ int hostapd_set_rts(struct hostapd_data *hapd, int rts); int hostapd_set_frag(struct hostapd_data *hapd, int frag); int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr, int total_flags, int flags_or, int flags_and); -int hostapd_set_rate_sets(struct hostapd_data *hapd, int *supp_rates, - int *basic_rates, int mode); int hostapd_set_country(struct hostapd_data *hapd, const char *country); -int hostapd_set_cts_protect(struct hostapd_data *hapd, int value); -int hostapd_set_preamble(struct hostapd_data *hapd, int value); -int hostapd_set_short_slot_time(struct hostapd_data *hapd, int value); int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs, int cw_min, int cw_max, int burst_time); -int hostapd_valid_bss_mask(struct hostapd_data *hapd, const u8 *addr, - const u8 *mask); struct hostapd_hw_modes * hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes, u16 *flags); int hostapd_driver_commit(struct hostapd_data *hapd); -int hostapd_set_ht_params(struct hostapd_data *hapd, - const u8 *ht_capab, size_t ht_capab_len, - const u8 *ht_oper, size_t ht_oper_len); int hostapd_drv_none(struct hostapd_data *hapd); int hostapd_driver_scan(struct hostapd_data *hapd, struct wpa_driver_scan_params *params); @@ -90,11 +87,19 @@ int hostapd_drv_set_key(const char *ifname, const u8 *seq, size_t seq_len, const u8 *key, size_t key_len); int hostapd_drv_send_mlme(struct hostapd_data *hapd, - const void *msg, size_t len); + const void *msg, size_t len, int noack); int hostapd_drv_sta_deauth(struct hostapd_data *hapd, const u8 *addr, int reason); int hostapd_drv_sta_disassoc(struct hostapd_data *hapd, const u8 *addr, int reason); +int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr, + u16 auth_alg); +int hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr, + u16 seq, u16 status, const u8 *ie, size_t len); +int hostapd_sta_assoc(struct hostapd_data *hapd, const u8 *addr, + int reassoc, u16 status, const u8 *ie, size_t len); +int hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr, + u8 *tspec_ie, size_t tspec_ielen); #include "drivers/driver.h" @@ -163,16 +168,12 @@ static inline int hostapd_drv_sta_clear_stats(struct hostapd_data *hapd, return hapd->driver->sta_clear_stats(hapd->drv_priv, addr); } -static inline int hostapd_drv_set_beacon(struct hostapd_data *hapd, - const u8 *head, size_t head_len, - const u8 *tail, size_t tail_len, - int dtim_period, int beacon_int) +static inline int hostapd_drv_set_ap(struct hostapd_data *hapd, + struct wpa_driver_ap_params *params) { - if (hapd->driver == NULL || hapd->driver->set_beacon == NULL) + if (hapd->driver == NULL || hapd->driver->set_ap == NULL) return 0; - return hapd->driver->set_beacon(hapd->drv_priv, - head, head_len, tail, tail_len, - dtim_period, beacon_int); + return hapd->driver->set_ap(hapd->drv_priv, params); } static inline int hostapd_drv_set_radius_acl_auth(struct hostapd_data *hapd, @@ -202,4 +203,13 @@ static inline int hostapd_drv_set_authmode(struct hostapd_data *hapd, return hapd->driver->set_authmode(hapd->drv_priv, auth_algs); } +static inline void hostapd_drv_poll_client(struct hostapd_data *hapd, + const u8 *own_addr, const u8 *addr, + int qos) +{ + if (hapd->driver == NULL || hapd->driver->poll_client == NULL) + return; + hapd->driver->poll_client(hapd->drv_priv, own_addr, addr, qos); +} + #endif /* AP_DRV_OPS */ diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c index 7c87fde..6f56c95 100644 --- a/src/ap/authsrv.c +++ b/src/ap/authsrv.c @@ -60,7 +60,7 @@ static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity, struct eap_user *user) { const struct hostapd_eap_user *eap_user; - int i, count; + int i; eap_user = hostapd_get_eap_user(ctx, identity, identity_len, phase2); if (eap_user == NULL) @@ -70,10 +70,7 @@ static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity, return 0; os_memset(user, 0, sizeof(*user)); - count = EAP_USER_MAX_METHODS; - if (count > EAP_MAX_METHODS) - count = EAP_MAX_METHODS; - for (i = 0; i < count; i++) { + for (i = 0; i < EAP_MAX_METHODS; i++) { user->methods[i].vendor = eap_user->methods[i].vendor; user->methods[i].method = eap_user->methods[i].method; } @@ -120,6 +117,9 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd) srv.eap_req_id_text = conf->eap_req_id_text; srv.eap_req_id_text_len = conf->eap_req_id_text_len; srv.pwd_group = conf->pwd_group; +#ifdef CONFIG_RADIUS_TEST + srv.dump_msk_file = conf->dump_msk_file; +#endif /* CONFIG_RADIUS_TEST */ hapd->radius_srv = radius_server_init(&srv); if (hapd->radius_srv == NULL) { diff --git a/src/ap/beacon.c b/src/ap/beacon.c index 0091064..4d8b277 100644 --- a/src/ap/beacon.c +++ b/src/ap/beacon.c @@ -35,6 +35,8 @@ #include "beacon.h" +#ifdef NEED_AP_MLME + static u8 ieee802_11_erp_info(struct hostapd_data *hapd) { u8 erp = 0; @@ -43,23 +45,11 @@ static u8 ieee802_11_erp_info(struct hostapd_data *hapd) hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G) return 0; - switch (hapd->iconf->cts_protection_type) { - case CTS_PROTECTION_FORCE_ENABLED: - erp |= ERP_INFO_NON_ERP_PRESENT | ERP_INFO_USE_PROTECTION; - break; - case CTS_PROTECTION_FORCE_DISABLED: - erp = 0; - break; - case CTS_PROTECTION_AUTOMATIC: - if (hapd->iface->olbc) - erp |= ERP_INFO_USE_PROTECTION; - /* continue */ - case CTS_PROTECTION_AUTOMATIC_NO_OLBC: - if (hapd->iface->num_sta_non_erp > 0) { - erp |= ERP_INFO_NON_ERP_PRESENT | - ERP_INFO_USE_PROTECTION; - } - break; + if (hapd->iface->olbc) + erp |= ERP_INFO_USE_PROTECTION; + if (hapd->iface->num_sta_non_erp > 0) { + erp |= ERP_INFO_NON_ERP_PRESENT | + ERP_INFO_USE_PROTECTION; } if (hapd->iface->num_sta_no_short_preamble > 0 || hapd->iconf->preamble == LONG_PREAMBLE) @@ -182,8 +172,7 @@ static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid, } -static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len, - struct sta_info *sta) +static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len) { const u8 *ie; size_t ielen; @@ -197,30 +186,134 @@ static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len, } +static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, + struct sta_info *sta, + const struct ieee80211_mgmt *req, + int is_p2p, size_t *resp_len) +{ + struct ieee80211_mgmt *resp; + u8 *pos, *epos; + size_t buflen; + +#define MAX_PROBERESP_LEN 768 + buflen = MAX_PROBERESP_LEN; +#ifdef CONFIG_WPS + if (hapd->wps_probe_resp_ie) + buflen += wpabuf_len(hapd->wps_probe_resp_ie); +#endif /* CONFIG_WPS */ +#ifdef CONFIG_P2P + if (hapd->p2p_probe_resp_ie) + buflen += wpabuf_len(hapd->p2p_probe_resp_ie); +#endif /* CONFIG_P2P */ + resp = os_zalloc(buflen); + if (resp == NULL) + return NULL; + + epos = ((u8 *) resp) + MAX_PROBERESP_LEN; + + resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_PROBE_RESP); + if (req) + os_memcpy(resp->da, req->sa, ETH_ALEN); + os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN); + + os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN); + resp->u.probe_resp.beacon_int = + host_to_le16(hapd->iconf->beacon_int); + + /* hardware or low-level driver will setup seq_ctrl and timestamp */ + resp->u.probe_resp.capab_info = + host_to_le16(hostapd_own_capab_info(hapd, sta, 1)); + + pos = resp->u.probe_resp.variable; + *pos++ = WLAN_EID_SSID; + *pos++ = hapd->conf->ssid.ssid_len; + os_memcpy(pos, hapd->conf->ssid.ssid, hapd->conf->ssid.ssid_len); + pos += hapd->conf->ssid.ssid_len; + + /* Supported rates */ + pos = hostapd_eid_supp_rates(hapd, pos); + + /* DS Params */ + pos = hostapd_eid_ds_params(hapd, pos); + + pos = hostapd_eid_country(hapd, pos, epos - pos); + + /* ERP Information element */ + pos = hostapd_eid_erp_info(hapd, pos); + + /* Extended supported rates */ + pos = hostapd_eid_ext_supp_rates(hapd, pos); + + /* RSN, MDIE, WPA */ + pos = hostapd_eid_wpa(hapd, pos, epos - pos); + +#ifdef CONFIG_IEEE80211N + pos = hostapd_eid_ht_capabilities(hapd, pos); + pos = hostapd_eid_ht_operation(hapd, pos); +#endif /* CONFIG_IEEE80211N */ + + pos = hostapd_eid_ext_capab(hapd, pos); + + pos = hostapd_eid_time_adv(hapd, pos); + pos = hostapd_eid_time_zone(hapd, pos); + + pos = hostapd_eid_interworking(hapd, pos); + pos = hostapd_eid_adv_proto(hapd, pos); + pos = hostapd_eid_roaming_consortium(hapd, pos); + + /* Wi-Fi Alliance WMM */ + pos = hostapd_eid_wmm(hapd, pos); + +#ifdef CONFIG_WPS + if (hapd->conf->wps_state && hapd->wps_probe_resp_ie) { + os_memcpy(pos, wpabuf_head(hapd->wps_probe_resp_ie), + wpabuf_len(hapd->wps_probe_resp_ie)); + pos += wpabuf_len(hapd->wps_probe_resp_ie); + } +#endif /* CONFIG_WPS */ + +#ifdef CONFIG_P2P + if ((hapd->conf->p2p & P2P_ENABLED) && is_p2p && + hapd->p2p_probe_resp_ie) { + os_memcpy(pos, wpabuf_head(hapd->p2p_probe_resp_ie), + wpabuf_len(hapd->p2p_probe_resp_ie)); + pos += wpabuf_len(hapd->p2p_probe_resp_ie); + } +#endif /* CONFIG_P2P */ +#ifdef CONFIG_P2P_MANAGER + if ((hapd->conf->p2p & (P2P_MANAGE | P2P_ENABLED | P2P_GROUP_OWNER)) == + P2P_MANAGE) + pos = hostapd_eid_p2p_manage(hapd, pos); +#endif /* CONFIG_P2P_MANAGER */ + + *resp_len = pos - (u8 *) resp; + return (u8 *) resp; +} + + void handle_probe_req(struct hostapd_data *hapd, const struct ieee80211_mgmt *mgmt, size_t len) { - struct ieee80211_mgmt *resp; + u8 *resp; struct ieee802_11_elems elems; - char *ssid; - u8 *pos, *epos; const u8 *ie; - size_t ssid_len, ie_len; + size_t ie_len; struct sta_info *sta = NULL; - size_t buflen; - size_t i; + size_t i, resp_len; + int noack; ie = mgmt->u.probe_req.variable; if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)) return; ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)); -#ifndef ANDROID_BRCM_P2P_PATCH for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx, - mgmt->sa, ie, ie_len) > 0) + mgmt->sa, mgmt->da, mgmt->bssid, + ie, ie_len) > 0) return; -#endif + if (!hapd->iconf->send_probe_response) return; @@ -230,9 +323,6 @@ void handle_probe_req(struct hostapd_data *hapd, return; } - ssid = NULL; - ssid_len = 0; - if ((!elems.ssid || !elems.supp_rates)) { wpa_printf(MSG_DEBUG, "STA " MACSTR " sent probe request " "without SSID or supported rates element", @@ -277,13 +367,9 @@ void handle_probe_req(struct hostapd_data *hapd, (elems.ssid_len == hapd->conf->ssid.ssid_len && os_memcmp(elems.ssid, hapd->conf->ssid.ssid, elems.ssid_len) == 0)) { - ssid = hapd->conf->ssid.ssid; - ssid_len = hapd->conf->ssid.ssid_len; if (sta) sta->ssid_probe = &hapd->conf->ssid; - } - - if (!ssid) { + } else { if (!(mgmt->da[0] & 0x01)) { char ssid_txt[33]; ieee802_11_print_ssid(ssid_txt, elems.ssid, @@ -296,113 +382,116 @@ void handle_probe_req(struct hostapd_data *hapd, return; } +#ifdef CONFIG_INTERWORKING + if (elems.interworking && elems.interworking_len >= 1) { + u8 ant = elems.interworking[0] & 0x0f; + if (ant != INTERWORKING_ANT_WILDCARD && + ant != hapd->conf->access_network_type) { + wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR + " for mismatching ANT %u ignored", + MAC2STR(mgmt->sa), ant); + return; + } + } + + if (elems.interworking && + (elems.interworking_len == 7 || elems.interworking_len == 9)) { + const u8 *hessid; + if (elems.interworking_len == 7) + hessid = elems.interworking + 1; + else + hessid = elems.interworking + 1 + 2; + if (!is_broadcast_ether_addr(hessid) && + os_memcmp(hessid, hapd->conf->hessid, ETH_ALEN) != 0) { + wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR + " for mismatching HESSID " MACSTR + " ignored", + MAC2STR(mgmt->sa), MAC2STR(hessid)); + return; + } + } +#endif /* CONFIG_INTERWORKING */ + /* TODO: verify that supp_rates contains at least one matching rate * with AP configuration */ -#define MAX_PROBERESP_LEN 768 - buflen = MAX_PROBERESP_LEN; -#ifdef CONFIG_WPS - if (hapd->wps_probe_resp_ie) - buflen += wpabuf_len(hapd->wps_probe_resp_ie); -#endif /* CONFIG_WPS */ -#ifdef CONFIG_P2P - if (hapd->p2p_probe_resp_ie) - buflen += wpabuf_len(hapd->p2p_probe_resp_ie); -#endif /* CONFIG_P2P */ - resp = os_zalloc(buflen); + + resp = hostapd_gen_probe_resp(hapd, sta, mgmt, elems.p2p != NULL, + &resp_len); if (resp == NULL) return; - epos = ((u8 *) resp) + MAX_PROBERESP_LEN; - resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_PROBE_RESP); - os_memcpy(resp->da, mgmt->sa, ETH_ALEN); - os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN); + /* + * If this is a broadcast probe request, apply no ack policy to avoid + * excessive retries. + */ + noack = !!(elems.ssid_len == 0 && is_broadcast_ether_addr(mgmt->da)); - os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN); - resp->u.probe_resp.beacon_int = - host_to_le16(hapd->iconf->beacon_int); - - /* hardware or low-level driver will setup seq_ctrl and timestamp */ - resp->u.probe_resp.capab_info = - host_to_le16(hostapd_own_capab_info(hapd, sta, 1)); - - pos = resp->u.probe_resp.variable; - *pos++ = WLAN_EID_SSID; - *pos++ = ssid_len; - os_memcpy(pos, ssid, ssid_len); - pos += ssid_len; - - /* Supported rates */ - pos = hostapd_eid_supp_rates(hapd, pos); - - /* DS Params */ - pos = hostapd_eid_ds_params(hapd, pos); - - pos = hostapd_eid_country(hapd, pos, epos - pos); - - /* ERP Information element */ - pos = hostapd_eid_erp_info(hapd, pos); - - /* Extended supported rates */ - pos = hostapd_eid_ext_supp_rates(hapd, pos); + if (hostapd_drv_send_mlme(hapd, resp, resp_len, noack) < 0) + perror("handle_probe_req: send"); - /* RSN, MDIE, WPA */ - pos = hostapd_eid_wpa(hapd, pos, epos - pos, sta); + os_free(resp); -#ifdef CONFIG_IEEE80211N - pos = hostapd_eid_ht_capabilities(hapd, pos); - pos = hostapd_eid_ht_operation(hapd, pos); -#endif /* CONFIG_IEEE80211N */ + wpa_printf(MSG_EXCESSIVE, "STA " MACSTR " sent probe request for %s " + "SSID", MAC2STR(mgmt->sa), + elems.ssid_len == 0 ? "broadcast" : "our"); +} - pos = hostapd_eid_ext_capab(hapd, pos); - /* Wi-Fi Alliance WMM */ - pos = hostapd_eid_wmm(hapd, pos); +static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd, + size_t *resp_len) +{ + /* check probe response offloading caps and print warnings */ + if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD)) + return NULL; #ifdef CONFIG_WPS - if (hapd->conf->wps_state && hapd->wps_probe_resp_ie) { - os_memcpy(pos, wpabuf_head(hapd->wps_probe_resp_ie), - wpabuf_len(hapd->wps_probe_resp_ie)); - pos += wpabuf_len(hapd->wps_probe_resp_ie); - } + if (hapd->conf->wps_state && hapd->wps_probe_resp_ie && + (!(hapd->iface->probe_resp_offloads & + (WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS | + WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2)))) + wpa_printf(MSG_WARNING, "Device is trying to offload WPS " + "Probe Response while not supporting this"); #endif /* CONFIG_WPS */ #ifdef CONFIG_P2P - if ((hapd->conf->p2p & P2P_ENABLED) && elems.p2p && - hapd->p2p_probe_resp_ie) { - os_memcpy(pos, wpabuf_head(hapd->p2p_probe_resp_ie), - wpabuf_len(hapd->p2p_probe_resp_ie)); - pos += wpabuf_len(hapd->p2p_probe_resp_ie); - } -#endif /* CONFIG_P2P */ -#ifdef CONFIG_P2P_MANAGER - if ((hapd->conf->p2p & (P2P_MANAGE | P2P_ENABLED | P2P_GROUP_OWNER)) == - P2P_MANAGE) - pos = hostapd_eid_p2p_manage(hapd, pos); -#endif /* CONFIG_P2P_MANAGER */ - - if (hostapd_drv_send_mlme(hapd, resp, pos - (u8 *) resp) < 0) - perror("handle_probe_req: send"); - - os_free(resp); - - wpa_printf(MSG_EXCESSIVE, "STA " MACSTR " sent probe request for %s " - "SSID", MAC2STR(mgmt->sa), - elems.ssid_len == 0 ? "broadcast" : "our"); + if ((hapd->conf->p2p & P2P_ENABLED) && hapd->p2p_probe_resp_ie && + !(hapd->iface->probe_resp_offloads & + WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P)) + wpa_printf(MSG_WARNING, "Device is trying to offload P2P " + "Probe Response while not supporting this"); +#endif /* CONFIG_P2P */ + + if (hapd->conf->interworking && + !(hapd->iface->probe_resp_offloads & + WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING)) + wpa_printf(MSG_WARNING, "Device is trying to offload " + "Interworking Probe Response while not supporting " + "this"); + + /* Generate a Probe Response template for the non-P2P case */ + return hostapd_gen_probe_resp(hapd, NULL, NULL, 0, resp_len); } +#endif /* NEED_AP_MLME */ + void ieee802_11_set_beacon(struct hostapd_data *hapd) { - struct ieee80211_mgmt *head; - u8 *pos, *tail, *tailpos; + struct ieee80211_mgmt *head = NULL; + u8 *tail = NULL; + size_t head_len = 0, tail_len = 0; + u8 *resp = NULL; + size_t resp_len = 0; + struct wpa_driver_ap_params params; + struct wpabuf *beacon, *proberesp, *assocresp; +#ifdef NEED_AP_MLME u16 capab_info; - size_t head_len, tail_len; + u8 *pos, *tailpos; +#endif /* NEED_AP_MLME */ -#ifdef CONFIG_P2P - if ((hapd->conf->p2p & (P2P_ENABLED | P2P_GROUP_OWNER)) == P2P_ENABLED) - goto no_beacon; -#endif /* CONFIG_P2P */ + hapd->beacon_set_done = 1; + +#ifdef NEED_AP_MLME #define BEACON_HEAD_BUF_SIZE 256 #define BEACON_TAIL_BUF_SIZE 512 @@ -474,7 +563,7 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd) /* RSN, MDIE, WPA */ tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE - - tailpos, NULL); + tailpos); #ifdef CONFIG_IEEE80211N tailpos = hostapd_eid_ht_capabilities(hapd, tailpos); @@ -483,6 +572,16 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd) tailpos = hostapd_eid_ext_capab(hapd, tailpos); + /* + * TODO: Time Advertisement element should only be included in some + * DTIM Beacon frames. + */ + tailpos = hostapd_eid_time_adv(hapd, tailpos); + + tailpos = hostapd_eid_interworking(hapd, tailpos); + tailpos = hostapd_eid_adv_proto(hapd, tailpos); + tailpos = hostapd_eid_roaming_consortium(hapd, tailpos); + /* Wi-Fi Alliance WMM */ tailpos = hostapd_eid_wmm(hapd, tailpos); @@ -509,20 +608,75 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd) tail_len = tailpos > tail ? tailpos - tail : 0; - if (hostapd_drv_set_beacon(hapd, (u8 *) head, head_len, - tail, tail_len, hapd->conf->dtim_period, - hapd->iconf->beacon_int)) - wpa_printf(MSG_ERROR, "Failed to set beacon head/tail or DTIM " - "period"); + resp = hostapd_probe_resp_offloads(hapd, &resp_len); +#endif /* NEED_AP_MLME */ + + os_memset(¶ms, 0, sizeof(params)); + params.head = (u8 *) head; + params.head_len = head_len; + params.tail = tail; + params.tail_len = tail_len; + params.proberesp = resp; + params.proberesp_len = resp_len; + params.dtim_period = hapd->conf->dtim_period; + params.beacon_int = hapd->iconf->beacon_int; + params.basic_rates = hapd->iconf->basic_rates; + params.ssid = (u8 *) hapd->conf->ssid.ssid; + params.ssid_len = hapd->conf->ssid.ssid_len; + params.pairwise_ciphers = hapd->conf->rsn_pairwise ? + hapd->conf->rsn_pairwise : hapd->conf->wpa_pairwise; + params.group_cipher = hapd->conf->wpa_group; + params.key_mgmt_suites = hapd->conf->wpa_key_mgmt; + params.auth_algs = hapd->conf->auth_algs; + params.wpa_version = hapd->conf->wpa; + params.privacy = hapd->conf->ssid.wep.keys_set || hapd->conf->wpa || + (hapd->conf->ieee802_1x && + (hapd->conf->default_wep_key_len || + hapd->conf->individual_wep_key_len)); + switch (hapd->conf->ignore_broadcast_ssid) { + case 0: + params.hide_ssid = NO_SSID_HIDING; + break; + case 1: + params.hide_ssid = HIDDEN_SSID_ZERO_LEN; + break; + case 2: + params.hide_ssid = HIDDEN_SSID_ZERO_CONTENTS; + break; + } + hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp); + params.beacon_ies = beacon; + params.proberesp_ies = proberesp; + params.assocresp_ies = assocresp; + params.isolate = hapd->conf->isolate; +#ifdef NEED_AP_MLME + params.cts_protect = !!(ieee802_11_erp_info(hapd) & + ERP_INFO_USE_PROTECTION); + params.preamble = hapd->iface->num_sta_no_short_preamble == 0 && + hapd->iconf->preamble == SHORT_PREAMBLE; + if (hapd->iface->current_mode && + hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) + params.short_slot_time = + hapd->iface->num_sta_no_short_slot_time > 0 ? 0 : 1; + else + params.short_slot_time = -1; + if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n) + params.ht_opmode = -1; + else + params.ht_opmode = hapd->iface->ht_op_mode; +#endif /* NEED_AP_MLME */ + params.interworking = hapd->conf->interworking; + if (hapd->conf->interworking && + !is_zero_ether_addr(hapd->conf->hessid)) + params.hessid = hapd->conf->hessid; + params.access_network_type = hapd->conf->access_network_type; + if (hostapd_drv_set_ap(hapd, ¶ms)) + wpa_printf(MSG_ERROR, "Failed to set beacon parameters"); + hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp); os_free(tail); os_free(head); - -#ifdef CONFIG_P2P -no_beacon: -#endif /* CONFIG_P2P */ - hostapd_set_bss_params(hapd, !!(ieee802_11_erp_info(hapd) & - ERP_INFO_USE_PROTECTION)); + os_free(resp); } diff --git a/src/ap/beacon.h b/src/ap/beacon.h index c1510e1..a944f5f 100644 --- a/src/ap/beacon.h +++ b/src/ap/beacon.h @@ -20,17 +20,7 @@ struct ieee80211_mgmt; void handle_probe_req(struct hostapd_data *hapd, const struct ieee80211_mgmt *mgmt, size_t len); -#ifdef NEED_AP_MLME void ieee802_11_set_beacon(struct hostapd_data *hapd); void ieee802_11_set_beacons(struct hostapd_iface *iface); -#else /* NEED_AP_MLME */ -static inline void ieee802_11_set_beacon(struct hostapd_data *hapd) -{ -} - -static inline void ieee802_11_set_beacons(struct hostapd_iface *iface) -{ -} -#endif /* NEED_AP_MLME */ #endif /* BEACON_H */ diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c index 10e3af9..b7febdc 100644 --- a/src/ap/drv_callbacks.c +++ b/src/ap/drv_callbacks.c @@ -19,7 +19,6 @@ #include "drivers/driver.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" -#include "common/wpa_ctrl.h" #include "crypto/random.h" #include "p2p/p2p.h" #include "wps/wps.h" @@ -28,25 +27,22 @@ #include "sta_info.h" #include "accounting.h" #include "tkip_countermeasures.h" -#include "iapp.h" #include "ieee802_1x.h" #include "wpa_auth.h" -#include "wmm.h" #include "wps_hostapd.h" #include "ap_drv_ops.h" #include "ap_config.h" int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, - const u8 *ie, size_t ielen, int reassoc) + const u8 *req_ies, size_t req_ies_len, int reassoc) { struct sta_info *sta; int new_assoc, res; struct ieee802_11_elems elems; -#ifdef CONFIG_P2P - const u8 *all_ies = ie; - size_t all_ies_len = ielen; -#endif /* CONFIG_P2P */ + const u8 *ie; + size_t ielen; + u16 reason = WLAN_REASON_UNSPECIFIED; if (addr == NULL) { /* @@ -65,7 +61,7 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "associated"); - ieee802_11_parse_elems(ie, ielen, &elems, 0); + ieee802_11_parse_elems(req_ies, req_ies_len, &elems, 0); if (elems.wps_ie) { ie = elems.wps_ie - 2; ielen = elems.wps_ie_len + 2; @@ -93,18 +89,19 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, if (sta == NULL) return -1; } - sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS); + sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2); #ifdef CONFIG_P2P if (elems.p2p) { wpabuf_free(sta->p2p_ie); - sta->p2p_ie = ieee802_11_vendor_ie_concat(all_ies, all_ies_len, + sta->p2p_ie = ieee802_11_vendor_ie_concat(req_ies, req_ies_len, P2P_IE_VENDOR_TYPE); } #endif /* CONFIG_P2P */ if (hapd->conf->wpa) { if (ie == NULL || ielen == 0) { +#ifdef CONFIG_WPS if (hapd->conf->wps_state) { wpa_printf(MSG_DEBUG, "STA did not include " "WPA/RSN IE in (Re)Association " @@ -112,15 +109,29 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, sta->flags |= WLAN_STA_MAYBE_WPS; goto skip_wpa_check; } +#endif /* CONFIG_WPS */ wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA"); return -1; } +#ifdef CONFIG_WPS if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 && os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) { + struct wpabuf *wps; sta->flags |= WLAN_STA_WPS; + wps = ieee802_11_vendor_ie_concat(ie, ielen, + WPS_IE_VENDOR_TYPE); + if (wps) { + if (wps_is_20(wps)) { + wpa_printf(MSG_DEBUG, "WPS: STA " + "supports WPS 2.0"); + sta->flags |= WLAN_STA_WPS2; + } + wpabuf_free(wps); + } goto skip_wpa_check; } +#endif /* CONFIG_WPS */ if (sta->wpa_sm == NULL) sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, @@ -133,52 +144,55 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, ie, ielen, NULL, 0); if (res != WPA_IE_OK) { - int resp; wpa_printf(MSG_DEBUG, "WPA/RSN information element " "rejected? (res %u)", res); wpa_hexdump(MSG_DEBUG, "IE", ie, ielen); if (res == WPA_INVALID_GROUP) - resp = WLAN_REASON_GROUP_CIPHER_NOT_VALID; + reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID; else if (res == WPA_INVALID_PAIRWISE) - resp = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID; + reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID; else if (res == WPA_INVALID_AKMP) - resp = WLAN_REASON_AKMP_NOT_VALID; + reason = WLAN_REASON_AKMP_NOT_VALID; #ifdef CONFIG_IEEE80211W else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) - resp = WLAN_REASON_INVALID_IE; + reason = WLAN_REASON_INVALID_IE; else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) - resp = WLAN_REASON_GROUP_CIPHER_NOT_VALID; + reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID; #endif /* CONFIG_IEEE80211W */ else - resp = WLAN_REASON_INVALID_IE; - hostapd_drv_sta_disassoc(hapd, sta->addr, resp); - ap_free_sta(hapd, sta); - return -1; + reason = WLAN_REASON_INVALID_IE; + goto fail; } } else if (hapd->conf->wps_state) { -#ifdef CONFIG_WPS_STRICT - if (ie) { - struct wpabuf *wps; - wps = ieee802_11_vendor_ie_concat(ie, ielen, +#ifdef CONFIG_WPS + struct wpabuf *wps; + if (req_ies) + wps = ieee802_11_vendor_ie_concat(req_ies, req_ies_len, WPS_IE_VENDOR_TYPE); - if (wps && wps_validate_assoc_req(wps) < 0) { - hostapd_drv_sta_disassoc( - hapd, sta->addr, - WLAN_REASON_INVALID_IE); - ap_free_sta(hapd, sta); - wpabuf_free(wps); - return -1; - } + else + wps = NULL; +#ifdef CONFIG_WPS_STRICT + if (wps && wps_validate_assoc_req(wps) < 0) { + reason = WLAN_REASON_INVALID_IE; wpabuf_free(wps); + goto fail; } #endif /* CONFIG_WPS_STRICT */ - if (ie && ielen > 4 && ie[0] == 0xdd && ie[1] >= 4 && - os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) { + if (wps) { sta->flags |= WLAN_STA_WPS; + if (wps_is_20(wps)) { + wpa_printf(MSG_DEBUG, "WPS: STA supports " + "WPS 2.0"); + sta->flags |= WLAN_STA_WPS2; + } } else sta->flags |= WLAN_STA_MAYBE_WPS; + wpabuf_free(wps); +#endif /* CONFIG_WPS */ } +#ifdef CONFIG_WPS skip_wpa_check: +#endif /* CONFIG_WPS */ new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; @@ -189,11 +203,18 @@ skip_wpa_check: ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); #ifdef CONFIG_P2P - p2p_group_notif_assoc(hapd->p2p_group, sta->addr, - all_ies, all_ies_len); + if (req_ies) { + p2p_group_notif_assoc(hapd->p2p_group, sta->addr, + req_ies, req_ies_len); + } #endif /* CONFIG_P2P */ return 0; + +fail: + hostapd_drv_sta_disassoc(hapd, sta->addr, reason); + ap_free_sta(hapd, sta); + return -1; } @@ -224,14 +245,8 @@ void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr) return; } + ap_sta_set_authorized(hapd, sta, 0); sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); - wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR, - MAC2STR(sta->addr)); -#ifdef ANDROID_BRCM_P2P_PATCH - if(hapd->msg_ctx_parent) - wpa_msg(hapd->msg_ctx_parent, MSG_INFO, AP_STA_DISCONNECTED MACSTR, - MAC2STR(sta->addr)); -#endif /* ANDROID_BRCM_P2P_PATCH */ wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC); sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); @@ -255,8 +270,8 @@ void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr) } -int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, - const u8 *ie, size_t ie_len) +int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da, + const u8 *bssid, const u8 *ie, size_t ie_len) { size_t i; int ret = 0; @@ -267,7 +282,7 @@ int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, random_add_randomness(sa, ETH_ALEN); for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) { if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx, - sa, ie, ie_len) > 0) { + sa, da, bssid, ie, ie_len) > 0) { ret = 1; break; } @@ -280,46 +295,6 @@ int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, #ifdef NEED_AP_MLME -static const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len) -{ - u16 fc, type, stype; - - /* - * PS-Poll frames are 16 bytes. All other frames are - * 24 bytes or longer. - */ - if (len < 16) - return NULL; - - fc = le_to_host16(hdr->frame_control); - type = WLAN_FC_GET_TYPE(fc); - stype = WLAN_FC_GET_STYPE(fc); - - switch (type) { - case WLAN_FC_TYPE_DATA: - if (len < 24) - return NULL; - switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) { - case WLAN_FC_FROMDS | WLAN_FC_TODS: - case WLAN_FC_TODS: - return hdr->addr1; - case WLAN_FC_FROMDS: - return hdr->addr2; - default: - return NULL; - } - case WLAN_FC_TYPE_CTRL: - if (stype != WLAN_FC_STYPE_PSPOLL) - return NULL; - return hdr->addr1; - case WLAN_FC_TYPE_MGMT: - return hdr->addr3; - default: - return NULL; - } -} - - #define HAPD_BROADCAST ((struct hostapd_data *) -1) static struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface, @@ -343,17 +318,14 @@ static struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface, static void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd, - const u8 *frame, size_t len) + const u8 *bssid, const u8 *addr, + int wds) { - const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *) frame; - u16 fc = le_to_host16(hdr->frame_control); - hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len)); + hapd = get_hapd_bssid(hapd->iface, bssid); if (hapd == NULL || hapd == HAPD_BROADCAST) return; - ieee802_11_rx_from_unknown(hapd, hdr->addr2, - (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) == - (WLAN_FC_TODS | WLAN_FC_FROMDS)); + ieee802_11_rx_from_unknown(hapd, addr, wds); } @@ -497,6 +469,23 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, union wpa_event_data *data) { struct hostapd_data *hapd = ctx; +#ifndef CONFIG_NO_STDOUT_DEBUG + int level = MSG_DEBUG; + + if (event == EVENT_RX_MGMT && data && data->rx_mgmt.frame && + data->rx_mgmt.frame_len >= 24) { + const struct ieee80211_hdr *hdr; + u16 fc; + hdr = (const struct ieee80211_hdr *) data->rx_mgmt.frame; + fc = le_to_host16(hdr->frame_control); + if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && + WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON) + level = MSG_EXCESSIVE; + } + + wpa_dbg(hapd->msg_ctx, level, "Event %s (%d) received", + event_to_string(event), event); +#endif /* CONFIG_NO_STDOUT_DEBUG */ switch (event) { case EVENT_MICHAEL_MIC_FAILURE: @@ -532,9 +521,19 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, break; } break; + case EVENT_EAPOL_TX_STATUS: + hostapd_eapol_tx_status(hapd, data->eapol_tx_status.dst, + data->eapol_tx_status.data, + data->eapol_tx_status.data_len, + data->eapol_tx_status.ack); + break; + case EVENT_DRIVER_CLIENT_POLL_OK: + hostapd_client_poll_ok(hapd, data->client_poll.addr); + break; case EVENT_RX_FROM_UNKNOWN: - hostapd_rx_from_unknown_sta(hapd, data->rx_from_unknown.frame, - data->rx_from_unknown.len); + hostapd_rx_from_unknown_sta(hapd, data->rx_from_unknown.bssid, + data->rx_from_unknown.addr, + data->rx_from_unknown.wds); break; case EVENT_RX_MGMT: hostapd_mgmt_rx(hapd, &data->rx_mgmt); @@ -545,6 +544,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, data->rx_probe_req.ie == NULL) break; hostapd_probe_req_rx(hapd, data->rx_probe_req.sa, + data->rx_probe_req.da, + data->rx_probe_req.bssid, data->rx_probe_req.ie, data->rx_probe_req.ie_len); break; diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index f00a544..0c5ee2e 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -61,9 +61,11 @@ static void hostapd_reload_bss(struct hostapd_data *hapd) else hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0); - if (hapd->conf->wpa && hapd->wpa_auth == NULL) + if (hapd->conf->wpa && hapd->wpa_auth == NULL) { hostapd_setup_wpa(hapd); - else if (hapd->conf->wpa) { + if (hapd->wpa_auth) + wpa_init_keys(hapd->wpa_auth); + } else if (hapd->conf->wpa) { const u8 *wpa_ie; size_t wpa_ie_len; hostapd_reconfig_wpa(hapd); @@ -259,6 +261,8 @@ static void hostapd_cleanup(struct hostapd_data *hapd) wpabuf_free(hapd->p2p_probe_resp_ie); hapd->p2p_probe_resp_ie = NULL; #endif /* CONFIG_P2P */ + + wpabuf_free(hapd->time_adv); } @@ -287,6 +291,8 @@ static void hostapd_cleanup_iface(struct hostapd_iface *iface) iface->hw_features = NULL; os_free(iface->current_rates); iface->current_rates = NULL; + os_free(iface->basic_rates); + iface->basic_rates = NULL; ap_list_deinit(iface); hostapd_config_free(iface->conf); iface->conf = NULL; @@ -341,12 +347,13 @@ static int hostapd_flush_old_stations(struct hostapd_data *hapd) if (hostapd_drv_none(hapd) || hapd->drv_priv == NULL) return 0; - wpa_printf(MSG_DEBUG, "Flushing old station entries"); + wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "Flushing old station entries"); if (hostapd_flush(hapd)) { - wpa_printf(MSG_WARNING, "Could not connect to kernel driver."); + wpa_msg(hapd->msg_ctx, MSG_WARNING, "Could not connect to " + "kernel driver"); ret = -1; } - wpa_printf(MSG_DEBUG, "Deauthenticate all stations"); + wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "Deauthenticate all stations"); os_memset(addr, 0xff, ETH_ALEN); hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID); hostapd_free_stas(hapd); @@ -367,7 +374,6 @@ static int hostapd_validate_bssid_configuration(struct hostapd_iface *iface) u8 mask[ETH_ALEN] = { 0 }; struct hostapd_data *hapd = iface->bss[0]; unsigned int i = iface->conf->num_bss, bits = 0, j; - int res; int auto_addr = 0; if (hostapd_drv_none(hapd)) @@ -431,17 +437,6 @@ skip_mask_ext: wpa_printf(MSG_DEBUG, "BSS count %lu, BSSID mask " MACSTR " (%d bits)", (unsigned long) iface->conf->num_bss, MAC2STR(mask), bits); - res = hostapd_valid_bss_mask(hapd, hapd->own_addr, mask); - if (res == 0) - return 0; - - if (res < 0) { - wpa_printf(MSG_ERROR, "Driver did not accept BSSID mask " - MACSTR " for start address " MACSTR ".", - MAC2STR(mask), MAC2STR(hapd->own_addr)); - return -1; - } - if (!auto_addr) return 0; @@ -639,6 +634,9 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) ieee802_11_set_beacon(hapd); + if (hapd->wpa_auth && wpa_init_keys(hapd->wpa_auth) < 0) + return -1; + if (hapd->driver && hapd->driver->set_operstate) hapd->driver->set_operstate(hapd->drv_priv, 1); @@ -746,7 +744,7 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err) } if (iface->current_mode) { - if (hostapd_prepare_rates(hapd, iface->current_mode)) { + if (hostapd_prepare_rates(iface, iface->current_mode)) { wpa_printf(MSG_ERROR, "Failed to prepare rates " "table."); hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index 3764be4..c6f6205 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -31,7 +31,8 @@ enum wps_event; union wps_event_data; struct hostapd_probereq_cb { - int (*cb)(void *ctx, const u8 *sa, const u8 *ie, size_t ie_len); + int (*cb)(void *ctx, const u8 *sa, const u8 *da, const u8 *bssid, + const u8 *ie, size_t ie_len); void *ctx; }; @@ -81,10 +82,7 @@ struct hostapd_data { struct sta_info *sta, int reassoc); void *msg_ctx; /* ctx for wpa_msg() calls */ -#ifdef ANDROID_BRCM_P2P_PATCH - /* Sending the event to parent is required as SSL listens on parent ctrl iface */ - void *msg_ctx_parent; /* ctx for wpa_msg() calls */ -#endif /*ANDROID_BRCM_P2P_PATCH*/ + void *msg_ctx_parent; /* parent interface ctx for wpa_msg() calls */ struct radius_client_data *radius; u32 acct_session_id_hi, acct_session_id_lo; @@ -111,6 +109,10 @@ struct hostapd_data { int parameter_set_count; + /* Time Advertisement */ + u8 time_update_counter; + struct wpabuf *time_adv; + #ifdef CONFIG_FULL_DYNAMIC_VLAN struct full_dynamic_vlan *full_dynamic_vlan; #endif /* CONFIG_FULL_DYNAMIC_VLAN */ @@ -118,6 +120,7 @@ struct hostapd_data { struct l2_packet_data *l2; struct wps_context *wps; + int beacon_set_done; struct wpabuf *wps_beacon_ie; struct wpabuf *wps_probe_resp_ie; #ifdef CONFIG_WPS @@ -146,7 +149,7 @@ struct hostapd_data { void *wps_event_cb_ctx; void (*sta_authorized_cb)(void *ctx, const u8 *mac_addr, - int authorized); + int authorized, const u8 *p2p_dev_addr); void *sta_authorized_cb_ctx; void (*setup_complete_cb)(void *ctx); @@ -189,6 +192,13 @@ struct hostapd_iface { struct ap_info *ap_iter_list; unsigned int drv_flags; + + /* + * A bitmap of supported protocols for probe response offload. See + * struct wpa_driver_capa in driver.h + */ + unsigned int probe_resp_offloads; + struct hostapd_hw_modes *hw_features; int num_hw_features; struct hostapd_hw_modes *current_mode; @@ -196,6 +206,7 @@ struct hostapd_iface { * current_mode->channels */ int num_rates; struct hostapd_rate_data *current_rates; + int *basic_rates; int freq; u16 hw_flags; @@ -251,6 +262,7 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta, /* utils.c */ int hostapd_register_probereq_cb(struct hostapd_data *hapd, int (*cb)(void *ctx, const u8 *sa, + const u8 *da, const u8 *bssid, const u8 *ie, size_t ie_len), void *ctx); void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr); @@ -260,7 +272,7 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, const u8 *ie, size_t ielen, int reassoc); void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr); void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr); -int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, - const u8 *ie, size_t ie_len); +int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da, + const u8 *bssid, const u8 *ie, size_t ie_len); #endif /* HOSTAPD_H */ diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c index 86f6811..8c6fef2 100644 --- a/src/ap/hw_features.c +++ b/src/ap/hw_features.c @@ -2,7 +2,7 @@ * hostapd / Hardware feature query and different modes * Copyright 2002-2003, Instant802 Networks, Inc. * Copyright 2005-2006, Devicescape Software, Inc. - * Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi> + * Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -101,7 +101,7 @@ int hostapd_get_hw_features(struct hostapd_iface *iface) } -int hostapd_prepare_rates(struct hostapd_data *hapd, +int hostapd_prepare_rates(struct hostapd_iface *iface, struct hostapd_hw_modes *mode) { int i, num_basic_rates = 0; @@ -110,8 +110,8 @@ int hostapd_prepare_rates(struct hostapd_data *hapd, int basic_rates_g[] = { 10, 20, 55, 110, -1 }; int *basic_rates; - if (hapd->iconf->basic_rates) - basic_rates = hapd->iconf->basic_rates; + if (iface->conf->basic_rates) + basic_rates = iface->conf->basic_rates; else switch (mode->mode) { case HOSTAPD_MODE_IEEE80211A: basic_rates = basic_rates_a; @@ -126,18 +126,20 @@ int hostapd_prepare_rates(struct hostapd_data *hapd, return -1; } - if (hostapd_set_rate_sets(hapd, hapd->iconf->supported_rates, - basic_rates, mode->mode)) { - wpa_printf(MSG_ERROR, "Failed to update rate sets in kernel " - "module"); - } + i = 0; + while (basic_rates[i] >= 0) + i++; + os_free(iface->basic_rates); + iface->basic_rates = os_malloc(i * sizeof(int)); + if (iface->basic_rates) + os_memcpy(iface->basic_rates, basic_rates, i * sizeof(int)); - os_free(hapd->iface->current_rates); - hapd->iface->num_rates = 0; + os_free(iface->current_rates); + iface->num_rates = 0; - hapd->iface->current_rates = + iface->current_rates = os_zalloc(mode->num_rates * sizeof(struct hostapd_rate_data)); - if (!hapd->iface->current_rates) { + if (!iface->current_rates) { wpa_printf(MSG_ERROR, "Failed to allocate memory for rate " "table."); return -1; @@ -146,27 +148,27 @@ int hostapd_prepare_rates(struct hostapd_data *hapd, for (i = 0; i < mode->num_rates; i++) { struct hostapd_rate_data *rate; - if (hapd->iconf->supported_rates && - !hostapd_rate_found(hapd->iconf->supported_rates, + if (iface->conf->supported_rates && + !hostapd_rate_found(iface->conf->supported_rates, mode->rates[i])) continue; - rate = &hapd->iface->current_rates[hapd->iface->num_rates]; + rate = &iface->current_rates[iface->num_rates]; rate->rate = mode->rates[i]; if (hostapd_rate_found(basic_rates, rate->rate)) { rate->flags |= HOSTAPD_RATE_BASIC; num_basic_rates++; } wpa_printf(MSG_DEBUG, "RATE[%d] rate=%d flags=0x%x", - hapd->iface->num_rates, rate->rate, rate->flags); - hapd->iface->num_rates++; + iface->num_rates, rate->rate, rate->flags); + iface->num_rates++; } - if ((hapd->iface->num_rates == 0 || num_basic_rates == 0) && - (!hapd->iconf->ieee80211n || !hapd->iconf->require_ht)) { + if ((iface->num_rates == 0 || num_basic_rates == 0) && + (!iface->conf->ieee80211n || !iface->conf->require_ht)) { wpa_printf(MSG_ERROR, "No rates remaining in supported/basic " "rate sets (%d,%d).", - hapd->iface->num_rates, num_basic_rates); + iface->num_rates, num_basic_rates); return -1; } @@ -407,20 +409,6 @@ static int ieee80211n_check_40mhz_2g4(struct hostapd_iface *iface, } -static void wpa_scan_results_free(struct wpa_scan_results *res) -{ - size_t i; - - if (res == NULL) - return; - - for (i = 0; i < res->num; i++) - os_free(res->res[i]); - os_free(res->res); - os_free(res); -} - - static void ieee80211n_check_scan(struct hostapd_iface *iface) { struct wpa_scan_results *scan_res; @@ -630,7 +618,8 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface) hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_WARNING, "Hardware does not support configured mode " - "(%d)", (int) iface->conf->hw_mode); + "(%d) (hw_mode in hostapd.conf)", + (int) iface->conf->hw_mode); return -2; } @@ -642,8 +631,15 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface) if (chan->flag & HOSTAPD_CHAN_DISABLED) { wpa_printf(MSG_ERROR, "channel [%i] (%i) is disabled for " - "use in AP mode, flags: 0x%x", - j, chan->chan, chan->flag); + "use in AP mode, flags: 0x%x%s%s%s", + j, chan->chan, chan->flag, + chan->flag & HOSTAPD_CHAN_NO_IBSS ? + " NO-IBSS" : "", + chan->flag & + HOSTAPD_CHAN_PASSIVE_SCAN ? + " PASSIVE-SCAN" : "", + chan->flag & HOSTAPD_CHAN_RADAR ? + " RADAR" : ""); } else { ok = 1; break; diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h index b84bca6..abadcd1 100644 --- a/src/ap/hw_features.h +++ b/src/ap/hw_features.h @@ -2,6 +2,7 @@ * hostapd / Hardware feature query and different modes * Copyright 2002-2003, Instant802 Networks, Inc. * Copyright 2005-2006, Devicescape Software, Inc. + * Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -25,7 +26,7 @@ const char * hostapd_hw_mode_txt(int mode); int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan); int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq); int hostapd_check_ht_capab(struct hostapd_iface *iface); -int hostapd_prepare_rates(struct hostapd_data *hapd, +int hostapd_prepare_rates(struct hostapd_iface *iface, struct hostapd_hw_modes *mode); #else /* NEED_AP_MLME */ static inline void @@ -59,7 +60,7 @@ static inline int hostapd_check_ht_capab(struct hostapd_iface *iface) return 0; } -static inline int hostapd_prepare_rates(struct hostapd_data *hapd, +static inline int hostapd_prepare_rates(struct hostapd_iface *iface, struct hostapd_hw_modes *mode) { return 0; diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index e0a3a36..a1a7270 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -1,6 +1,6 @@ /* * hostapd / IEEE 802.11 Management - * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi> + * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -163,59 +163,6 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta, } -u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid) -{ - u8 *pos = eid; - - if ((hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH)) == - 0) - return eid; - - *pos++ = WLAN_EID_EXT_CAPAB; - *pos++ = 5; - *pos++ = 0x00; - *pos++ = 0x00; - *pos++ = 0x00; - *pos++ = 0x00; - *pos = 0x00; - if (hapd->conf->tdls & TDLS_PROHIBIT) - *pos |= 0x40; /* Bit 38 - TDLS Prohibited */ - if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH) - *pos |= 0x80; /* Bit 39 - TDLS Channel Switching Prohibited */ - pos++; - - return pos; -} - - -#ifdef CONFIG_IEEE80211W -static u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd, - struct sta_info *sta, u8 *eid) -{ - u8 *pos = eid; - u32 timeout, tu; - struct os_time now, passed; - - *pos++ = WLAN_EID_TIMEOUT_INTERVAL; - *pos++ = 5; - *pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK; - os_get_time(&now); - os_time_sub(&now, &sta->sa_query_start, &passed); - tu = (passed.sec * 1000000 + passed.usec) / 1024; - if (hapd->conf->assoc_sa_query_max_timeout > tu) - timeout = hapd->conf->assoc_sa_query_max_timeout - tu; - else - timeout = 0; - if (timeout < hapd->conf->assoc_sa_query_max_timeout) - timeout++; /* add some extra time for local timers */ - WPA_PUT_LE32(pos, timeout); - pos += 4; - - return pos; -} -#endif /* CONFIG_IEEE80211W */ - - void ieee802_11_print_ssid(char *buf, const u8 *ssid, u8 len) { int i; @@ -322,7 +269,7 @@ static void send_auth_reply(struct hostapd_data *hapd, " auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu)", MAC2STR(dst), auth_alg, auth_transaction, resp, (unsigned long) ies_len); - if (hostapd_drv_send_mlme(hapd, reply, rlen) < 0) + if (hostapd_drv_send_mlme(hapd, reply, rlen, 0) < 0) perror("send_auth_reply: send"); os_free(buf); @@ -366,6 +313,8 @@ static void handle_auth(struct hostapd_data *hapd, const u8 *challenge = NULL; u32 session_timeout, acct_interim_interval; int vlan_id = 0; + u8 psk[PMK_LEN]; + int has_psk = 0; u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN]; size_t resp_ies_len = 0; @@ -400,9 +349,7 @@ static void handle_auth(struct hostapd_data *hapd, if (!(((hapd->conf->auth_algs & WPA_AUTH_ALG_OPEN) && auth_alg == WLAN_AUTH_OPEN) || #ifdef CONFIG_IEEE80211R - (hapd->conf->wpa && - (hapd->conf->wpa_key_mgmt & - (WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_FT_PSK)) && + (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) && auth_alg == WLAN_AUTH_FT) || #endif /* CONFIG_IEEE80211R */ ((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) && @@ -430,7 +377,9 @@ static void handle_auth(struct hostapd_data *hapd, res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len, &session_timeout, - &acct_interim_interval, &vlan_id); + &acct_interim_interval, &vlan_id, + psk, &has_psk); + if (res == HOSTAPD_ACL_REJECT) { printf("Station " MACSTR " not allowed to authenticate.\n", MAC2STR(mgmt->sa)); @@ -468,6 +417,16 @@ static void handle_auth(struct hostapd_data *hapd, HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id); } + if (has_psk && hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) { + os_free(sta->psk); + sta->psk = os_malloc(PMK_LEN); + if (sta->psk) + os_memcpy(sta->psk, psk, PMK_LEN); + } else { + os_free(sta->psk); + sta->psk = NULL; + } + sta->flags &= ~WLAN_STA_PREAUTH; ieee802_1x_notify_pre_auth(sta->eapol_sm, 0); @@ -592,15 +551,22 @@ static u16 check_wmm(struct hostapd_data *hapd, struct sta_info *sta, const u8 *wmm_ie, size_t wmm_ie_len) { sta->flags &= ~WLAN_STA_WMM; + sta->qosinfo = 0; if (wmm_ie && hapd->conf->wmm_enabled) { - if (hostapd_eid_wmm_valid(hapd, wmm_ie, wmm_ie_len)) + struct wmm_information_element *wmm; + + if (!hostapd_eid_wmm_valid(hapd, wmm_ie, wmm_ie_len)) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, HOSTAPD_LEVEL_DEBUG, "invalid WMM element in association " "request"); - else - sta->flags |= WLAN_STA_WMM; + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + + sta->flags |= WLAN_STA_WMM; + wmm = (struct wmm_information_element *) wmm_ie; + sta->qosinfo = wmm->qos_info; } return WLAN_STATUS_SUCCESS; } @@ -701,7 +667,7 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, } #ifdef CONFIG_WPS - sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS); + sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2); if (hapd->conf->wps_state && elems.wps_ie) { wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)Association " "Request - assume WPS is used"); @@ -709,6 +675,10 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, wpabuf_free(sta->wps_ie); sta->wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len, WPS_IE_VENDOR_TYPE); + if (sta->wps_ie && wps_is_20(sta->wps_ie)) { + wpa_printf(MSG_DEBUG, "WPS: STA supports WPS 2.0"); + sta->flags |= WLAN_STA_WPS2; + } wpa_ie = NULL; wpa_ie_len = 0; if (sta->wps_ie && wps_validate_assoc_req(sta->wps_ie) < 0) { @@ -854,7 +824,7 @@ static void send_deauth(struct hostapd_data *hapd, const u8 *addr, send_len = IEEE80211_HDRLEN + sizeof(reply.u.deauth); reply.u.deauth.reason_code = host_to_le16(reason_code); - if (hostapd_drv_send_mlme(hapd, &reply, send_len) < 0) + if (hostapd_drv_send_mlme(hapd, &reply, send_len, 0) < 0) wpa_printf(MSG_INFO, "Failed to send deauth: %s", strerror(errno)); } @@ -917,7 +887,8 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, p = hostapd_eid_wmm(hapd, p); #ifdef CONFIG_WPS - if (sta->flags & WLAN_STA_WPS) { + if ((sta->flags & WLAN_STA_WPS) || + ((sta->flags & WLAN_STA_MAYBE_WPS) && hapd->conf->wpa)) { struct wpabuf *wps = wps_build_assoc_resp_ie(); if (wps) { os_memcpy(p, wpabuf_head(wps), wpabuf_len(wps)); @@ -959,7 +930,7 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, send_len += p - reply->u.assoc_resp.variable; - if (hostapd_drv_send_mlme(hapd, reply, send_len) < 0) + if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0) wpa_printf(MSG_INFO, "Failed to send assoc resp: %s", strerror(errno)); } @@ -1160,15 +1131,8 @@ static void handle_disassoc(struct hostapd_data *hapd, return; } + ap_sta_set_authorized(hapd, sta, 0); sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK); - wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR, - MAC2STR(sta->addr)); -#ifdef ANDROID_BRCM_P2P_PATCH - if(hapd->msg_ctx_parent) - wpa_msg(hapd->msg_ctx_parent, MSG_INFO, AP_STA_DISCONNECTED MACSTR, - MAC2STR(sta->addr)); -#endif /* ANDROID_BRCM_P2P_PATCH */ - wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC); hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "disassociated"); @@ -1199,32 +1163,26 @@ static void handle_deauth(struct hostapd_data *hapd, struct sta_info *sta; if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.deauth)) { - wpa_msg(hapd, MSG_DEBUG, "handle_deauth - too short payload " - "(len=%lu)", (unsigned long) len); + wpa_msg(hapd->msg_ctx, MSG_DEBUG, "handle_deauth - too short " + "payload (len=%lu)", (unsigned long) len); return; } - wpa_msg(hapd, MSG_DEBUG, "deauthentication: STA=" MACSTR + wpa_msg(hapd->msg_ctx, MSG_DEBUG, "deauthentication: STA=" MACSTR " reason_code=%d", MAC2STR(mgmt->sa), le_to_host16(mgmt->u.deauth.reason_code)); sta = ap_get_sta(hapd, mgmt->sa); if (sta == NULL) { - wpa_msg(hapd, MSG_DEBUG, "Station " MACSTR " trying to " - "deauthenticate, but it is not authenticated", + wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR " trying " + "to deauthenticate, but it is not authenticated", MAC2STR(mgmt->sa)); return; } + ap_sta_set_authorized(hapd, sta, 0); sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK); - wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR, - MAC2STR(sta->addr)); -#ifdef ANDROID_BRCM_P2P_PATCH - if(hapd->msg_ctx_parent) - wpa_msg(hapd->msg_ctx_parent, MSG_INFO, AP_STA_DISCONNECTED MACSTR, - MAC2STR(sta->addr)); -#endif /* ANDROID_BRCM_P2P_PATCH */ wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH); hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "deauthenticated"); @@ -1259,81 +1217,11 @@ static void handle_beacon(struct hostapd_data *hapd, #ifdef CONFIG_IEEE80211W -/* MLME-SAQuery.request */ -void ieee802_11_send_sa_query_req(struct hostapd_data *hapd, - const u8 *addr, const u8 *trans_id) -{ - struct ieee80211_mgmt mgmt; - u8 *end; - - wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Request to " - MACSTR, MAC2STR(addr)); - wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID", - trans_id, WLAN_SA_QUERY_TR_ID_LEN); - - os_memset(&mgmt, 0, sizeof(mgmt)); - mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_ACTION); - os_memcpy(mgmt.da, addr, ETH_ALEN); - os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN); - os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN); - mgmt.u.action.category = WLAN_ACTION_SA_QUERY; - mgmt.u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST; - os_memcpy(mgmt.u.action.u.sa_query_req.trans_id, trans_id, - WLAN_SA_QUERY_TR_ID_LEN); - end = mgmt.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN; - if (hostapd_drv_send_mlme(hapd, &mgmt, end - (u8 *) &mgmt) < 0) - perror("ieee802_11_send_sa_query_req: send"); -} - - -static void hostapd_sa_query_request(struct hostapd_data *hapd, - const struct ieee80211_mgmt *mgmt) -{ - struct sta_info *sta; - struct ieee80211_mgmt resp; - u8 *end; - - wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Request from " - MACSTR, MAC2STR(mgmt->sa)); - wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID", - mgmt->u.action.u.sa_query_resp.trans_id, - WLAN_SA_QUERY_TR_ID_LEN); - - sta = ap_get_sta(hapd, mgmt->sa); - if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) { - wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignore SA Query Request " - "from unassociated STA " MACSTR, MAC2STR(mgmt->sa)); - return; - } - - wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Response to " - MACSTR, MAC2STR(mgmt->sa)); - - os_memset(&resp, 0, sizeof(resp)); - resp.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_ACTION); - os_memcpy(resp.da, mgmt->sa, ETH_ALEN); - os_memcpy(resp.sa, hapd->own_addr, ETH_ALEN); - os_memcpy(resp.bssid, hapd->own_addr, ETH_ALEN); - resp.u.action.category = WLAN_ACTION_SA_QUERY; - resp.u.action.u.sa_query_req.action = WLAN_SA_QUERY_RESPONSE; - os_memcpy(resp.u.action.u.sa_query_req.trans_id, - mgmt->u.action.u.sa_query_req.trans_id, - WLAN_SA_QUERY_TR_ID_LEN); - end = resp.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN; - if (hostapd_drv_send_mlme(hapd, &resp, end - (u8 *) &resp) < 0) - perror("hostapd_sa_query_request: send"); -} - - static void hostapd_sa_query_action(struct hostapd_data *hapd, const struct ieee80211_mgmt *mgmt, size_t len) { - struct sta_info *sta; const u8 *end; - int i; end = mgmt->u.action.u.sa_query_resp.trans_id + WLAN_SA_QUERY_TR_ID_LEN; @@ -1343,50 +1231,9 @@ static void hostapd_sa_query_action(struct hostapd_data *hapd, return; } - if (mgmt->u.action.u.sa_query_resp.action == WLAN_SA_QUERY_REQUEST) { - hostapd_sa_query_request(hapd, mgmt); - return; - } - - if (mgmt->u.action.u.sa_query_resp.action != WLAN_SA_QUERY_RESPONSE) { - wpa_printf(MSG_DEBUG, "IEEE 802.11: Unexpected SA Query " - "Action %d", mgmt->u.action.u.sa_query_resp.action); - return; - } - - wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Response from " - MACSTR, MAC2STR(mgmt->sa)); - wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID", - mgmt->u.action.u.sa_query_resp.trans_id, - WLAN_SA_QUERY_TR_ID_LEN); - - /* MLME-SAQuery.confirm */ - - sta = ap_get_sta(hapd, mgmt->sa); - if (sta == NULL || sta->sa_query_trans_id == NULL) { - wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching STA with " - "pending SA Query request found"); - return; - } - - for (i = 0; i < sta->sa_query_count; i++) { - if (os_memcmp(sta->sa_query_trans_id + - i * WLAN_SA_QUERY_TR_ID_LEN, - mgmt->u.action.u.sa_query_resp.trans_id, - WLAN_SA_QUERY_TR_ID_LEN) == 0) - break; - } - - if (i >= sta->sa_query_count) { - wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching SA Query " - "transaction identifier found"); - return; - } - - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "Reply to pending SA Query received"); - ap_sta_stop_sa_query(hapd, sta); + ieee802_11_sa_query_action(hapd, mgmt->sa, + mgmt->u.action.u.sa_query_resp.action, + mgmt->u.action.u.sa_query_resp.trans_id); } @@ -1401,7 +1248,10 @@ static int robust_action_frame(u8 category) static void handle_action(struct hostapd_data *hapd, const struct ieee80211_mgmt *mgmt, size_t len) { +#if defined(CONFIG_IEEE80211W) || defined(CONFIG_IEEE80211R) struct sta_info *sta; + sta = ap_get_sta(hapd, mgmt->sa); +#endif /* CONFIG_IEEE80211W || CONFIG_IEEE80211R */ if (len < IEEE80211_HDRLEN + 1) { hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, @@ -1411,7 +1261,6 @@ static void handle_action(struct hostapd_data *hapd, return; } - sta = ap_get_sta(hapd, mgmt->sa); #ifdef CONFIG_IEEE80211W if (sta && (sta->flags & WLAN_STA_MFP) && !(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP) && @@ -1493,7 +1342,7 @@ static void handle_action(struct hostapd_data *hapd, os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN); resp->u.action.category |= 0x80; - hostapd_drv_send_mlme(hapd, resp, len); + hostapd_drv_send_mlme(hapd, resp, len, 0); os_free(resp); } } @@ -1536,6 +1385,11 @@ void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, mgmt->bssid[4] == 0xff && mgmt->bssid[5] == 0xff; if (!broadcast && +#ifdef CONFIG_P2P + /* Invitation responses can be sent with the peer MAC as BSSID */ + !((hapd->conf->p2p & P2P_GROUP_OWNER) && + stype == WLAN_FC_STYPE_ACTION) && +#endif /* CONFIG_P2P */ os_memcmp(mgmt->bssid, hapd->own_addr, ETH_ALEN) != 0) { printf("MGMT: BSSID=" MACSTR " not our address\n", MAC2STR(mgmt->bssid)); @@ -1574,7 +1428,7 @@ void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, handle_disassoc(hapd, mgmt, len); break; case WLAN_FC_STYPE_DEAUTH: - wpa_msg(hapd, MSG_DEBUG, "mgmt::deauth"); + wpa_msg(hapd->msg_ctx, MSG_DEBUG, "mgmt::deauth"); handle_deauth(hapd, mgmt, len); break; case WLAN_FC_STYPE_ACTION: @@ -1688,14 +1542,6 @@ static void handle_assoc_cb(struct hostapd_data *hapd, * step. */ ap_sta_set_authorized(hapd, sta, 1); - wpa_msg(hapd->msg_ctx, MSG_INFO, - AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr)); -#ifdef ANDROID_BRCM_P2P_PATCH - /* Sending the event to parent is required as SSL listens on parent ctrl iface */ - if(hapd->msg_ctx_parent) - wpa_msg(hapd->msg_ctx_parent, MSG_INFO, - AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr)); -#endif /* ANDROID_BRCM_P2P_PATCH */ } if (reassoc) @@ -1722,10 +1568,16 @@ static void handle_assoc_cb(struct hostapd_data *hapd, if (hostapd_sta_add(hapd, sta->addr, sta->aid, sta->capability, sta->supported_rates, sta->supported_rates_len, sta->listen_interval, - sta->flags & WLAN_STA_HT ? &ht_cap : NULL)) { + sta->flags & WLAN_STA_HT ? &ht_cap : NULL, + sta->flags, sta->qosinfo)) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_NOTICE, "Could not add STA to kernel driver"); + + ap_sta_disconnect(hapd, sta, sta->addr, + WLAN_REASON_DISASSOC_AP_BUSY); + + goto fail; } if (sta->flags & WLAN_STA_WDS) @@ -1764,6 +1616,54 @@ static void handle_assoc_cb(struct hostapd_data *hapd, } +static void handle_deauth_cb(struct hostapd_data *hapd, + const struct ieee80211_mgmt *mgmt, + size_t len, int ok) +{ + struct sta_info *sta; + if (mgmt->da[0] & 0x01) + return; + sta = ap_get_sta(hapd, mgmt->da); + if (!sta) { + wpa_printf(MSG_DEBUG, "handle_deauth_cb: STA " MACSTR + " not found", MAC2STR(mgmt->da)); + return; + } + if (ok) + wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged deauth", + MAC2STR(sta->addr)); + else + wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge " + "deauth", MAC2STR(sta->addr)); + + ap_sta_deauth_cb(hapd, sta); +} + + +static void handle_disassoc_cb(struct hostapd_data *hapd, + const struct ieee80211_mgmt *mgmt, + size_t len, int ok) +{ + struct sta_info *sta; + if (mgmt->da[0] & 0x01) + return; + sta = ap_get_sta(hapd, mgmt->da); + if (!sta) { + wpa_printf(MSG_DEBUG, "handle_disassoc_cb: STA " MACSTR + " not found", MAC2STR(mgmt->da)); + return; + } + if (ok) + wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged disassoc", + MAC2STR(sta->addr)); + else + wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge " + "disassoc", MAC2STR(sta->addr)); + + ap_sta_disassoc_cb(hapd, sta); +} + + /** * ieee802_11_mgmt_cb - Process management frame TX status callback * @hapd: hostapd BSS data structure (the BSS from which the management frame @@ -1796,7 +1696,12 @@ void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len, wpa_printf(MSG_EXCESSIVE, "mgmt::proberesp cb"); break; case WLAN_FC_STYPE_DEAUTH: - /* ignore */ + wpa_printf(MSG_DEBUG, "mgmt::deauth cb"); + handle_deauth_cb(hapd, mgmt, len, ok); + break; + case WLAN_FC_STYPE_DISASSOC: + wpa_printf(MSG_DEBUG, "mgmt::disassoc cb"); + handle_disassoc_cb(hapd, mgmt, len, ok); break; case WLAN_FC_STYPE_ACTION: wpa_printf(MSG_DEBUG, "mgmt::action cb"); @@ -1853,6 +1758,55 @@ void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr, } +void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst, + const u8 *data, size_t len, int ack) +{ + struct sta_info *sta; + struct hostapd_iface *iface = hapd->iface; + + sta = ap_get_sta(hapd, dst); + if (sta == NULL && iface->num_bss > 1) { + size_t j; + for (j = 0; j < iface->num_bss; j++) { + hapd = iface->bss[j]; + sta = ap_get_sta(hapd, dst); + if (sta) + break; + } + } + if (sta == NULL) + return; + + ieee802_1x_eapol_tx_status(hapd, sta, data, len, ack); +} + + +void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr) +{ + struct sta_info *sta; + struct hostapd_iface *iface = hapd->iface; + + sta = ap_get_sta(hapd, addr); + if (sta == NULL && iface->num_bss > 1) { + size_t j; + for (j = 0; j < iface->num_bss; j++) { + hapd = iface->bss[j]; + sta = ap_get_sta(hapd, addr); + if (sta) + break; + } + } + if (sta == NULL) + return; + if (!(sta->flags & WLAN_STA_PENDING_POLL)) + return; + + wpa_printf(MSG_DEBUG, "STA " MACSTR " ACKed pending " + "activity poll", MAC2STR(sta->addr)); + sta->flags &= ~WLAN_STA_PENDING_POLL; +} + + void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src, int wds) { diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h index 157198c..43042a5 100644 --- a/src/ap/ieee802_11.h +++ b/src/ap/ieee802_11.h @@ -62,7 +62,21 @@ u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta, void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta); void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr, const u8 *buf, size_t len, int ack); +void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst, + const u8 *data, size_t len, int ack); void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src, int wds); +u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd, + struct sta_info *sta, u8 *eid); +void ieee802_11_sa_query_action(struct hostapd_data *hapd, + const u8 *sa, const u8 action_type, + const u8 *trans_id); +u8 * hostapd_eid_interworking(struct hostapd_data *hapd, u8 *eid); +u8 * hostapd_eid_adv_proto(struct hostapd_data *hapd, u8 *eid); +u8 * hostapd_eid_roaming_consortium(struct hostapd_data *hapd, u8 *eid); +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); #endif /* IEEE802_11_H */ diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c index b933263..f3f313d 100644 --- a/src/ap/ieee802_11_auth.c +++ b/src/ap/ieee802_11_auth.c @@ -21,6 +21,7 @@ #include "utils/common.h" #include "utils/eloop.h" +#include "crypto/sha1.h" #include "radius/radius.h" #include "radius/radius_client.h" #include "hostapd.h" @@ -40,6 +41,8 @@ struct hostapd_cached_radius_acl { u32 session_timeout; u32 acct_interim_interval; int vlan_id; + int has_psk; + u8 psk[PMK_LEN]; }; @@ -68,7 +71,8 @@ static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache) static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr, u32 *session_timeout, - u32 *acct_interim_interval, int *vlan_id) + u32 *acct_interim_interval, int *vlan_id, + u8 *psk, int *has_psk) { struct hostapd_cached_radius_acl *entry; struct os_time now; @@ -89,6 +93,10 @@ static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr, entry->acct_interim_interval; if (vlan_id) *vlan_id = entry->vlan_id; + if (psk) + os_memcpy(psk, entry->psk, PMK_LEN); + if (has_psk) + *has_psk = entry->has_psk; return entry->accepted; } @@ -210,11 +218,14 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr, * @session_timeout: Buffer for returning session timeout (from RADIUS) * @acct_interim_interval: Buffer for returning account interval (from RADIUS) * @vlan_id: Buffer for returning VLAN ID + * @psk: Buffer for returning WPA PSK + * @has_psk: Buffer for indicating whether psk was filled * Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING */ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr, const u8 *msg, size_t len, u32 *session_timeout, - u32 *acct_interim_interval, int *vlan_id) + u32 *acct_interim_interval, int *vlan_id, + u8 *psk, int *has_psk) { if (session_timeout) *session_timeout = 0; @@ -222,6 +233,10 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr, *acct_interim_interval = 0; if (vlan_id) *vlan_id = 0; + if (has_psk) + *has_psk = 0; + if (psk) + os_memset(psk, 0, PMK_LEN); if (hostapd_maclist_found(hapd->conf->accept_mac, hapd->conf->num_accept_mac, addr, vlan_id)) @@ -241,11 +256,12 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr, return HOSTAPD_ACL_REJECT; #else /* CONFIG_NO_RADIUS */ struct hostapd_acl_query_data *query; + struct os_time t; /* Check whether ACL cache has an entry for this station */ int res = hostapd_acl_cache_get(hapd, addr, session_timeout, acct_interim_interval, - vlan_id); + vlan_id, psk, has_psk); if (res == HOSTAPD_ACL_ACCEPT || res == HOSTAPD_ACL_ACCEPT_TIMEOUT) return res; @@ -271,7 +287,8 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr, wpa_printf(MSG_ERROR, "malloc for query data failed"); return HOSTAPD_ACL_REJECT; } - time(&query->timestamp); + os_get_time(&t); + query->timestamp = t.sec; os_memcpy(query->addr, addr, ETH_ALEN); if (hostapd_radius_acl_query(hapd, addr, query)) { wpa_printf(MSG_DEBUG, "Failed to send Access-Request " @@ -397,6 +414,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req, struct hostapd_acl_query_data *query, *prev; struct hostapd_cached_radius_acl *cache; struct radius_hdr *hdr = radius_msg_get_hdr(msg); + struct os_time t; query = hapd->acl_queries; prev = NULL; @@ -431,9 +449,13 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req, wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry"); goto done; } - time(&cache->timestamp); + os_get_time(&t); + cache->timestamp = t.sec; os_memcpy(cache->addr, query->addr, sizeof(cache->addr)); if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) { + int passphraselen; + char *passphrase; + if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT, &cache->session_timeout) == 0) cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT; @@ -452,6 +474,32 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req, } cache->vlan_id = radius_msg_get_vlanid(msg); + + passphrase = radius_msg_get_tunnel_password( + msg, &passphraselen, + hapd->conf->radius->auth_server->shared_secret, + hapd->conf->radius->auth_server->shared_secret_len, + req); + cache->has_psk = passphrase != NULL; + if (passphrase != NULL) { + /* passphrase does not contain the NULL termination. + * Add it here as pbkdf2_sha1 requires it. */ + char *strpassphrase = os_zalloc(passphraselen + 1); + if (strpassphrase) { + os_memcpy(strpassphrase, passphrase, + passphraselen); + pbkdf2_sha1(strpassphrase, + hapd->conf->ssid.ssid, + hapd->conf->ssid.ssid_len, 4096, + cache->psk, PMK_LEN); + os_free(strpassphrase); + } + os_free(passphrase); + } + + if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED && + cache->psk == NULL) + cache->accepted = HOSTAPD_ACL_REJECT; } else cache->accepted = HOSTAPD_ACL_REJECT; cache->next = hapd->acl_cache; diff --git a/src/ap/ieee802_11_auth.h b/src/ap/ieee802_11_auth.h index b2971e5..a90571f 100644 --- a/src/ap/ieee802_11_auth.h +++ b/src/ap/ieee802_11_auth.h @@ -24,7 +24,8 @@ enum { int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr, const u8 *msg, size_t len, u32 *session_timeout, - u32 *acct_interim_interval, int *vlan_id); + u32 *acct_interim_interval, int *vlan_id, + u8 *psk, int *has_psk); int hostapd_acl_init(struct hostapd_data *hapd); void hostapd_acl_deinit(struct hostapd_data *hapd); diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c new file mode 100644 index 0000000..8503fce --- /dev/null +++ b/src/ap/ieee802_11_shared.c @@ -0,0 +1,405 @@ +/* + * hostapd / IEEE 802.11 Management + * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "utils/includes.h" + +#include "utils/common.h" +#include "common/ieee802_11_defs.h" +#include "hostapd.h" +#include "sta_info.h" +#include "ap_config.h" +#include "ap_drv_ops.h" +#include "ieee802_11.h" + + +#ifdef CONFIG_IEEE80211W + +u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd, + struct sta_info *sta, u8 *eid) +{ + u8 *pos = eid; + u32 timeout, tu; + struct os_time now, passed; + + *pos++ = WLAN_EID_TIMEOUT_INTERVAL; + *pos++ = 5; + *pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK; + os_get_time(&now); + os_time_sub(&now, &sta->sa_query_start, &passed); + tu = (passed.sec * 1000000 + passed.usec) / 1024; + if (hapd->conf->assoc_sa_query_max_timeout > tu) + timeout = hapd->conf->assoc_sa_query_max_timeout - tu; + else + timeout = 0; + if (timeout < hapd->conf->assoc_sa_query_max_timeout) + timeout++; /* add some extra time for local timers */ + WPA_PUT_LE32(pos, timeout); + pos += 4; + + return pos; +} + + +/* MLME-SAQuery.request */ +void ieee802_11_send_sa_query_req(struct hostapd_data *hapd, + const u8 *addr, const u8 *trans_id) +{ + struct ieee80211_mgmt mgmt; + u8 *end; + + wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Request to " + MACSTR, MAC2STR(addr)); + wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID", + trans_id, WLAN_SA_QUERY_TR_ID_LEN); + + os_memset(&mgmt, 0, sizeof(mgmt)); + mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_ACTION); + os_memcpy(mgmt.da, addr, ETH_ALEN); + os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN); + os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN); + mgmt.u.action.category = WLAN_ACTION_SA_QUERY; + mgmt.u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST; + os_memcpy(mgmt.u.action.u.sa_query_req.trans_id, trans_id, + WLAN_SA_QUERY_TR_ID_LEN); + end = mgmt.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN; + if (hostapd_drv_send_mlme(hapd, &mgmt, end - (u8 *) &mgmt, 0) < 0) + perror("ieee802_11_send_sa_query_req: send"); +} + + +static void ieee802_11_send_sa_query_resp(struct hostapd_data *hapd, + const u8 *sa, const u8 *trans_id) +{ + struct sta_info *sta; + struct ieee80211_mgmt resp; + u8 *end; + + wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Request from " + MACSTR, MAC2STR(sa)); + wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID", + trans_id, WLAN_SA_QUERY_TR_ID_LEN); + + sta = ap_get_sta(hapd, sa); + if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) { + wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignore SA Query Request " + "from unassociated STA " MACSTR, MAC2STR(sa)); + return; + } + + wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Response to " + MACSTR, MAC2STR(sa)); + + os_memset(&resp, 0, sizeof(resp)); + resp.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_ACTION); + os_memcpy(resp.da, sa, ETH_ALEN); + os_memcpy(resp.sa, hapd->own_addr, ETH_ALEN); + os_memcpy(resp.bssid, hapd->own_addr, ETH_ALEN); + resp.u.action.category = WLAN_ACTION_SA_QUERY; + resp.u.action.u.sa_query_req.action = WLAN_SA_QUERY_RESPONSE; + os_memcpy(resp.u.action.u.sa_query_req.trans_id, trans_id, + WLAN_SA_QUERY_TR_ID_LEN); + end = resp.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN; + if (hostapd_drv_send_mlme(hapd, &resp, end - (u8 *) &resp, 0) < 0) + perror("ieee80211_mgmt_sa_query_request: send"); +} + + +void ieee802_11_sa_query_action(struct hostapd_data *hapd, const u8 *sa, + const u8 action_type, const u8 *trans_id) +{ + struct sta_info *sta; + int i; + + if (action_type == WLAN_SA_QUERY_REQUEST) { + ieee802_11_send_sa_query_resp(hapd, sa, trans_id); + return; + } + + if (action_type != WLAN_SA_QUERY_RESPONSE) { + wpa_printf(MSG_DEBUG, "IEEE 802.11: Unexpected SA Query " + "Action %d", action_type); + return; + } + + wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Response from " + MACSTR, MAC2STR(sa)); + wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID", + trans_id, WLAN_SA_QUERY_TR_ID_LEN); + + /* MLME-SAQuery.confirm */ + + sta = ap_get_sta(hapd, sa); + if (sta == NULL || sta->sa_query_trans_id == NULL) { + wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching STA with " + "pending SA Query request found"); + return; + } + + for (i = 0; i < sta->sa_query_count; i++) { + if (os_memcmp(sta->sa_query_trans_id + + i * WLAN_SA_QUERY_TR_ID_LEN, + trans_id, WLAN_SA_QUERY_TR_ID_LEN) == 0) + break; + } + + if (i >= sta->sa_query_count) { + wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching SA Query " + "transaction identifier found"); + return; + } + + hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, + "Reply to pending SA Query received"); + ap_sta_stop_sa_query(hapd, sta); +} + +#endif /* CONFIG_IEEE80211W */ + + +u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid) +{ + u8 *pos = eid; + u8 len = 0; + + if (hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH)) + len = 5; + if (len < 4 && hapd->conf->interworking) + len = 4; + if (len == 0) + return eid; + + *pos++ = WLAN_EID_EXT_CAPAB; + *pos++ = len; + *pos++ = 0x00; + *pos++ = 0x00; + *pos++ = 0x00; + + *pos = 0x00; + if (hapd->conf->time_advertisement == 2) + *pos |= 0x08; /* Bit 27 - UTC TSF Offset */ + if (hapd->conf->interworking) + *pos |= 0x80; /* Bit 31 - Interworking */ + pos++; + + if (len < 5) + return pos; + *pos = 0x00; + if (hapd->conf->tdls & TDLS_PROHIBIT) + *pos |= 0x40; /* Bit 38 - TDLS Prohibited */ + if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH) + *pos |= 0x80; /* Bit 39 - TDLS Channel Switching Prohibited */ + pos++; + + return pos; +} + + +u8 * hostapd_eid_interworking(struct hostapd_data *hapd, u8 *eid) +{ + u8 *pos = eid; +#ifdef CONFIG_INTERWORKING + u8 *len; + + if (!hapd->conf->interworking) + return eid; + + *pos++ = WLAN_EID_INTERWORKING; + len = pos++; + + *pos = hapd->conf->access_network_type; + if (hapd->conf->internet) + *pos |= INTERWORKING_ANO_INTERNET; + if (hapd->conf->asra) + *pos |= INTERWORKING_ANO_ASRA; + if (hapd->conf->esr) + *pos |= INTERWORKING_ANO_ESR; + if (hapd->conf->uesa) + *pos |= INTERWORKING_ANO_UESA; + pos++; + + if (hapd->conf->venue_info_set) { + *pos++ = hapd->conf->venue_group; + *pos++ = hapd->conf->venue_type; + } + + if (!is_zero_ether_addr(hapd->conf->hessid)) { + os_memcpy(pos, hapd->conf->hessid, ETH_ALEN); + pos += ETH_ALEN; + } + + *len = pos - len - 1; +#endif /* CONFIG_INTERWORKING */ + + return pos; +} + + +u8 * hostapd_eid_adv_proto(struct hostapd_data *hapd, u8 *eid) +{ + u8 *pos = eid; +#ifdef CONFIG_INTERWORKING + + /* TODO: Separate configuration for ANQP? */ + if (!hapd->conf->interworking) + return eid; + + *pos++ = WLAN_EID_ADV_PROTO; + *pos++ = 2; + *pos++ = 0x7F; /* Query Response Length Limit | PAME-BI */ + *pos++ = ACCESS_NETWORK_QUERY_PROTOCOL; +#endif /* CONFIG_INTERWORKING */ + + return pos; +} + + +u8 * hostapd_eid_roaming_consortium(struct hostapd_data *hapd, u8 *eid) +{ + u8 *pos = eid; +#ifdef CONFIG_INTERWORKING + u8 *len; + unsigned int i, count; + + if (!hapd->conf->interworking || + hapd->conf->roaming_consortium == NULL || + hapd->conf->roaming_consortium_count == 0) + return eid; + + *pos++ = WLAN_EID_ROAMING_CONSORTIUM; + len = pos++; + + /* Number of ANQP OIs (in addition to the max 3 listed here) */ + if (hapd->conf->roaming_consortium_count > 3 + 255) + *pos++ = 255; + else if (hapd->conf->roaming_consortium_count > 3) + *pos++ = hapd->conf->roaming_consortium_count - 3; + else + *pos++ = 0; + + /* OU #1 and #2 Lengths */ + *pos = hapd->conf->roaming_consortium[0].len; + if (hapd->conf->roaming_consortium_count > 1) + *pos |= hapd->conf->roaming_consortium[1].len << 4; + pos++; + + if (hapd->conf->roaming_consortium_count > 3) + count = 3; + else + count = hapd->conf->roaming_consortium_count; + + for (i = 0; i < count; i++) { + os_memcpy(pos, hapd->conf->roaming_consortium[i].oi, + hapd->conf->roaming_consortium[i].len); + pos += hapd->conf->roaming_consortium[i].len; + } + + *len = pos - len - 1; +#endif /* CONFIG_INTERWORKING */ + + return pos; +} + + +u8 * hostapd_eid_time_adv(struct hostapd_data *hapd, u8 *eid) +{ + if (hapd->conf->time_advertisement != 2) + return eid; + + if (hapd->time_adv == NULL && + hostapd_update_time_adv(hapd) < 0) + return eid; + + if (hapd->time_adv == NULL) + return eid; + + os_memcpy(eid, wpabuf_head(hapd->time_adv), + wpabuf_len(hapd->time_adv)); + eid += wpabuf_len(hapd->time_adv); + + return eid; +} + + +u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid) +{ + size_t len; + + if (hapd->conf->time_advertisement != 2) + return eid; + + len = os_strlen(hapd->conf->time_zone); + + *eid++ = WLAN_EID_TIME_ZONE; + *eid++ = len; + os_memcpy(eid, hapd->conf->time_zone, len); + eid += len; + + return eid; +} + + +int hostapd_update_time_adv(struct hostapd_data *hapd) +{ + const int elen = 2 + 1 + 10 + 5 + 1; + struct os_time t; + struct os_tm tm; + u8 *pos; + + if (hapd->conf->time_advertisement != 2) + return 0; + + if (os_get_time(&t) < 0 || os_gmtime(t.sec, &tm) < 0) + return -1; + + if (!hapd->time_adv) { + hapd->time_adv = wpabuf_alloc(elen); + if (hapd->time_adv == NULL) + return -1; + pos = wpabuf_put(hapd->time_adv, elen); + } else + pos = wpabuf_mhead_u8(hapd->time_adv); + + *pos++ = WLAN_EID_TIME_ADVERTISEMENT; + *pos++ = 1 + 10 + 5 + 1; + + *pos++ = 2; /* UTC time at which the TSF timer is 0 */ + + /* Time Value at TSF 0 */ + /* FIX: need to calculate this based on the current TSF value */ + WPA_PUT_LE16(pos, tm.year); /* Year */ + pos += 2; + *pos++ = tm.month; /* Month */ + *pos++ = tm.day; /* Day of month */ + *pos++ = tm.hour; /* Hours */ + *pos++ = tm.min; /* Minutes */ + *pos++ = tm.sec; /* Seconds */ + WPA_PUT_LE16(pos, 0); /* Milliseconds (not used) */ + pos += 2; + *pos++ = 0; /* Reserved */ + + /* Time Error */ + /* TODO: fill in an estimate on the error */ + *pos++ = 0; + *pos++ = 0; + *pos++ = 0; + *pos++ = 0; + *pos++ = 0; + + *pos++ = hapd->time_update_counter++; + + return 0; +} diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c index 49eba69..153b271 100644 --- a/src/ap/ieee802_1x.c +++ b/src/ap/ieee802_1x.c @@ -20,13 +20,13 @@ #include "crypto/crypto.h" #include "crypto/random.h" #include "common/ieee802_11_defs.h" -#include "common/wpa_ctrl.h" #include "radius/radius.h" #include "radius/radius_client.h" #include "eap_server/eap.h" #include "eap_common/eap_wsc_common.h" #include "eapol_auth/eapol_auth_sm.h" #include "eapol_auth/eapol_auth_sm_i.h" +#include "p2p/p2p.h" #include "hostapd.h" #include "accounting.h" #include "sta_info.h" @@ -36,9 +36,6 @@ #include "ap_config.h" #include "ap_drv_ops.h" #include "ieee802_1x.h" -#ifdef ANDROID_BRCM_P2P_PATCH -#include "p2p/p2p_i.h" -#endif static void ieee802_1x_finished(struct hostapd_data *hapd, @@ -87,53 +84,16 @@ void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd, struct sta_info *sta, int authorized) { int res; -#ifdef ANDROID_BRCM_P2P_PATCH - u8 *dev_addr = NULL; -#endif if (sta->flags & WLAN_STA_PREAUTH) return; if (authorized) { - if (!ap_sta_is_authorized(sta)) { -#if defined(ANDROID_BRCM_P2P_PATCH) && defined(CONFIG_P2P) - if((dev_addr = p2p_group_get_dev_addr(hapd->p2p_group, sta->addr))) - wpa_msg(hapd->msg_ctx, MSG_INFO, - AP_STA_CONNECTED MACSTR " dev_addr="MACSTR, MAC2STR(sta->addr), MAC2STR(dev_addr)); - else -#endif /*ANDROID_BRCM_P2P_PATCH*/ - wpa_msg(hapd->msg_ctx, MSG_INFO, - AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr)); - -#ifdef ANDROID_BRCM_P2P_PATCH - /* Sending the event to parent is required as SSL listens on parent ctrl iface */ - if(hapd->msg_ctx_parent) { - if(dev_addr) - wpa_msg(hapd->msg_ctx_parent, MSG_INFO, - AP_STA_CONNECTED MACSTR " dev_addr="MACSTR, MAC2STR(sta->addr), MAC2STR(dev_addr)); - else - wpa_msg(hapd->msg_ctx_parent, MSG_INFO, - AP_STA_CONNECTED MACSTR , MAC2STR(sta->addr)); - } -#endif /* ANDROID_BRCM_P2P_PATCH */ - } - ap_sta_set_authorized(hapd, sta, 1); res = hostapd_set_authorized(hapd, sta, 1); hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_DEBUG, "authorizing port"); } else { - if (ap_sta_is_authorized(sta) && (sta->flags & WLAN_STA_ASSOC)) { - wpa_msg(hapd->msg_ctx, MSG_INFO, - AP_STA_DISCONNECTED MACSTR, - MAC2STR(sta->addr)); -#ifdef ANDROID_BRCM_P2P_PATCH - if(hapd->msg_ctx_parent) - wpa_msg(hapd->msg_ctx_parent, MSG_INFO, - AP_STA_DISCONNECTED MACSTR, - MAC2STR(sta->addr)); -#endif /* ANDROID_BRCM_P2P_PATCH */ - } ap_sta_set_authorized(hapd, sta, 0); res = hostapd_set_authorized(hapd, sta, 0); hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, @@ -722,7 +682,8 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, wpa_printf(MSG_DEBUG, "IEEE 802.1X: %lu bytes from " MACSTR, (unsigned long) len, MAC2STR(sa)); sta = ap_get_sta(hapd, sa); - if (!sta || !(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_PREAUTH))) { + if (!sta || (!(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_PREAUTH)) && + !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) { wpa_printf(MSG_DEBUG, "IEEE 802.1X data frame from not " "associated/Pre-authenticating STA"); return; @@ -785,14 +746,24 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, return; #ifdef CONFIG_WPS - if (!hapd->conf->ieee802_1x && - ((sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) == - WLAN_STA_MAYBE_WPS)) { - /* - * Delay EAPOL frame transmission until a possible WPS - * STA initiates the handshake with EAPOL-Start. - */ - sta->eapol_sm->flags |= EAPOL_SM_WAIT_START; + if (!hapd->conf->ieee802_1x) { + u32 wflags = sta->flags & (WLAN_STA_WPS | + WLAN_STA_WPS2 | + WLAN_STA_MAYBE_WPS); + if (wflags == WLAN_STA_MAYBE_WPS || + wflags == (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) { + /* + * Delay EAPOL frame transmission until a + * possible WPS STA initiates the handshake + * with EAPOL-Start. Only allow the wait to be + * skipped if the STA is known to support WPS + * 2.0. + */ + wpa_printf(MSG_DEBUG, "WPS: Do not start " + "EAPOL until EAPOL-Start is " + "received"); + sta->eapol_sm->flags |= EAPOL_SM_WAIT_START; + } } #endif /* CONFIG_WPS */ @@ -921,11 +892,14 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta) #ifdef CONFIG_WPS sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START; - if (!hapd->conf->ieee802_1x && !(sta->flags & WLAN_STA_WPS)) { + if (!hapd->conf->ieee802_1x && !(sta->flags & WLAN_STA_WPS2)) { /* - * Delay EAPOL frame transmission until a possible WPS - * initiates the handshake with EAPOL-Start. + * Delay EAPOL frame transmission until a possible WPS STA + * initiates the handshake with EAPOL-Start. Only allow the + * wait to be skipped if the STA is known to support WPS 2.0. */ + wpa_printf(MSG_DEBUG, "WPS: Do not start EAPOL until " + "EAPOL-Start is received"); sta->eapol_sm->flags |= EAPOL_SM_WAIT_START; } #endif /* CONFIG_WPS */ @@ -1443,6 +1417,9 @@ void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta) * request and we cannot continue EAP processing (EAP-Failure * could only be sent if the EAP peer actually replied). */ + wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "EAP Timeout, STA " MACSTR, + MAC2STR(sta->addr)); + sm->eap_if->portEnabled = FALSE; ap_sta_disconnect(hapd, sta, sta->addr, WLAN_REASON_PREV_AUTH_NOT_VALID); @@ -1595,7 +1572,7 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity, { struct hostapd_data *hapd = ctx; const struct hostapd_eap_user *eap_user; - int i, count; + int i; eap_user = hostapd_get_eap_user(hapd->conf, identity, identity_len, phase2); @@ -1604,10 +1581,7 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity, os_memset(user, 0, sizeof(*user)); user->phase2 = phase2; - count = EAP_USER_MAX_METHODS; - if (count > EAP_MAX_METHODS) - count = EAP_MAX_METHODS; - for (i = 0; i < count; i++) { + for (i = 0; i < EAP_MAX_METHODS; i++) { user->methods[i].vendor = eap_user->methods[i].vendor; user->methods[i].method = eap_user->methods[i].method; } @@ -1619,6 +1593,7 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity, os_memcpy(user->password, eap_user->password, eap_user->password_len); user->password_len = eap_user->password_len; + user->password_hash = eap_user->password_hash; } user->force_version = eap_user->force_version; user->ttls_auth = eap_user->ttls_auth; @@ -1795,15 +1770,13 @@ int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta, const u8 *buf, size_t len, int ack) { struct ieee80211_hdr *hdr; - struct ieee802_1x_hdr *xhdr; - struct ieee802_1x_eapol_key *key; u8 *pos; const unsigned char rfc1042_hdr[ETH_ALEN] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; if (sta == NULL) return -1; - if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2 + sizeof(*xhdr)) + if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2) return 0; hdr = (struct ieee80211_hdr *) buf; @@ -1815,16 +1788,30 @@ int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta, return 0; pos += 2; - xhdr = (struct ieee802_1x_hdr *) pos; - pos += sizeof(*xhdr); + return ieee802_1x_eapol_tx_status(hapd, sta, pos, buf + len - pos, + ack); +} + + +int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta, + const u8 *buf, int len, int ack) +{ + const struct ieee802_1x_hdr *xhdr = + (const struct ieee802_1x_hdr *) buf; + const u8 *pos = buf + sizeof(*xhdr); + struct ieee802_1x_eapol_key *key; + if (len < (int) sizeof(*xhdr)) + return 0; wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR " TX status - version=%d " "type=%d length=%d - ack=%d", MAC2STR(sta->addr), xhdr->version, xhdr->type, be_to_host16(xhdr->length), ack); - if (xhdr->type == IEEE802_1X_TYPE_EAPOL_KEY && - pos + sizeof(struct wpa_eapol_key) <= buf + len) { + if (xhdr->type != IEEE802_1X_TYPE_EAPOL_KEY) + return 0; + + if (pos + sizeof(struct wpa_eapol_key) <= buf + len) { const struct wpa_eapol_key *wpa; wpa = (const struct wpa_eapol_key *) pos; if (wpa->type == EAPOL_KEY_TYPE_RSN || @@ -1835,11 +1822,10 @@ int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta, /* EAPOL EAP-Packet packets are eventually re-sent by either Supplicant * or Authenticator state machines, but EAPOL-Key packets are not - * retransmitted in case of failure. Try to re-sent failed EAPOL-Key + * retransmitted in case of failure. Try to re-send failed EAPOL-Key * packets couple of times because otherwise STA keys become * unsynchronized with AP. */ - if (xhdr->type == IEEE802_1X_TYPE_EAPOL_KEY && !ack && - pos + sizeof(*key) <= buf + len) { + if (!ack && pos + sizeof(*key) <= buf + len) { key = (struct ieee802_1x_eapol_key *) pos; hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_DEBUG, "did not Ack EAPOL-Key " @@ -1943,6 +1929,7 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, { int len = 0, ret; struct eapol_state_machine *sm = sta->eapol_sm; + struct os_time t; if (sm == NULL) return 0; @@ -2057,6 +2044,7 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, len += ret; /* dot1xAuthSessionStatsTable */ + os_get_time(&t); ret = os_snprintf(buf + len, buflen - len, /* TODO: dot1xAuthSessionOctetsRx */ /* TODO: dot1xAuthSessionOctetsTx */ @@ -2071,8 +2059,7 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, (wpa_key_mgmt_wpa_ieee8021x( wpa_auth_sta_key_mgmt(sta->wpa_sm))) ? 1 : 2, - (unsigned int) (time(NULL) - - sta->acct_session_start), + (unsigned int) (t.sec - sta->acct_session_start), sm->identity); if (ret < 0 || (size_t) ret >= buflen - len) return len; @@ -2099,22 +2086,25 @@ static void ieee802_1x_finished(struct hostapd_data *hapd, "Added PMKSA cache entry (IEEE 802.1X)"); } -#ifdef CONFIG_WPS - if (!success && (sta->flags & WLAN_STA_WPS)) { + if (!success) { /* * Many devices require deauthentication after WPS provisioning * and some may not be be able to do that themselves, so - * disconnect the client here. + * disconnect the client here. In addition, this may also + * benefit IEEE 802.1X/EAPOL authentication cases, too since + * the EAPOL PAE state machine would remain in HELD state for + * considerable amount of time and some EAP methods, like + * EAP-FAST with anonymous provisioning, may require another + * EAPOL authentication to be started to complete connection. */ - wpa_printf(MSG_DEBUG, "WPS: Force disconnection after " - "EAP-Failure"); + wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "IEEE 802.1X: Force " + "disconnection after EAP-Failure"); /* Add a small sleep to increase likelihood of previously * requested EAP-Failure TX getting out before this should the * driver reorder operations. */ os_sleep(0, 10000); ap_sta_disconnect(hapd, sta, sta->addr, - WLAN_REASON_PREV_AUTH_NOT_VALID); + WLAN_REASON_IEEE_802_1X_AUTH_FAILED); } -#endif /* CONFIG_WPS */ } diff --git a/src/ap/ieee802_1x.h b/src/ap/ieee802_1x.h index 1a4d2eb..267e22a 100644 --- a/src/ap/ieee802_1x.h +++ b/src/ap/ieee802_1x.h @@ -68,6 +68,8 @@ int ieee802_1x_init(struct hostapd_data *hapd); void ieee802_1x_deinit(struct hostapd_data *hapd); int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta, const u8 *buf, size_t len, int ack); +int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta, + const u8 *data, int len, int ack); u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len); u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len, int idx); diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c index e829447..972a723 100644 --- a/src/ap/sta_info.c +++ b/src/ap/sta_info.c @@ -1,6 +1,6 @@ /* * hostapd / Station table - * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> + * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -17,6 +17,7 @@ #include "utils/common.h" #include "utils/eloop.h" #include "common/ieee802_11_defs.h" +#include "common/wpa_ctrl.h" #include "radius/radius.h" #include "radius/radius_client.h" #include "drivers/driver.h" @@ -38,9 +39,12 @@ static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd, struct sta_info *sta); static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx); +static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx); +static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx); #ifdef CONFIG_IEEE80211W static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx); #endif /* CONFIG_IEEE80211W */ +static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta); int ap_for_each_sta(struct hostapd_data *hapd, int (*cb)(struct hostapd_data *hapd, struct sta_info *sta, @@ -198,6 +202,8 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) eloop_cancel_timeout(ap_handle_timer, hapd, sta); eloop_cancel_timeout(ap_handle_session_timer, hapd, sta); + eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta); + eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta); ieee802_1x_free_station(sta); wpa_auth_sta_deinit(sta->wpa_sm); @@ -222,6 +228,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) wpabuf_free(sta->p2p_ie); os_free(sta->ht_capabilities); + os_free(sta->psk); os_free(sta); } @@ -275,31 +282,37 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) int inactive_sec; inactive_sec = hostapd_drv_get_inact_sec(hapd, sta->addr); if (inactive_sec == -1) { - wpa_msg(hapd, MSG_DEBUG, "Check inactivity: Could not " + wpa_msg(hapd->msg_ctx, MSG_DEBUG, + "Check inactivity: Could not " "get station info rom kernel driver for " MACSTR, MAC2STR(sta->addr)); } else if (inactive_sec < hapd->conf->ap_max_inactivity && sta->flags & WLAN_STA_ASSOC) { /* station activity detected; reset timeout state */ - wpa_msg(hapd, MSG_DEBUG, "Station " MACSTR " has been " - "active %is ago", + wpa_msg(hapd->msg_ctx, MSG_DEBUG, + "Station " MACSTR " has been active %is ago", MAC2STR(sta->addr), inactive_sec); sta->timeout_next = STA_NULLFUNC; next_time = hapd->conf->ap_max_inactivity - inactive_sec; } else { - wpa_msg(hapd, MSG_DEBUG, "Station " MACSTR " has been " + wpa_msg(hapd->msg_ctx, MSG_DEBUG, + "Station " MACSTR " has been " "inactive too long: %d sec, max allowed: %d", MAC2STR(sta->addr), inactive_sec, hapd->conf->ap_max_inactivity); + + if (hapd->conf->skip_inactivity_poll) + sta->timeout_next = STA_DISASSOC; } } if ((sta->flags & WLAN_STA_ASSOC) && sta->timeout_next == STA_DISASSOC && - !(sta->flags & WLAN_STA_PENDING_POLL)) { - wpa_msg(hapd, MSG_DEBUG, "Station " MACSTR " has ACKed data " - "poll", MAC2STR(sta->addr)); + !(sta->flags & WLAN_STA_PENDING_POLL) && + !hapd->conf->skip_inactivity_poll) { + wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR + " has ACKed data poll", MAC2STR(sta->addr)); /* data nullfunc frame poll did not produce TX errors; assume * station ACKed it */ sta->timeout_next = STA_NULLFUNC; @@ -314,46 +327,17 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) if (sta->timeout_next == STA_NULLFUNC && (sta->flags & WLAN_STA_ASSOC)) { -#ifndef CONFIG_NATIVE_WINDOWS - /* send data frame to poll STA and check whether this frame - * is ACKed */ - struct ieee80211_hdr hdr; - - wpa_printf(MSG_DEBUG, " Polling STA with data frame"); + wpa_printf(MSG_DEBUG, " Polling STA"); sta->flags |= WLAN_STA_PENDING_POLL; - - os_memset(&hdr, 0, sizeof(hdr)); - if (hapd->driver && - os_strcmp(hapd->driver->name, "hostap") == 0) { - /* - * WLAN_FC_STYPE_NULLFUNC would be more appropriate, - * but it is apparently not retried so TX Exc events - * are not received for it. - */ - hdr.frame_control = - IEEE80211_FC(WLAN_FC_TYPE_DATA, - WLAN_FC_STYPE_DATA); - } else { - hdr.frame_control = - IEEE80211_FC(WLAN_FC_TYPE_DATA, - WLAN_FC_STYPE_NULLFUNC); - } - - hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS); - os_memcpy(hdr.IEEE80211_DA_FROMDS, sta->addr, ETH_ALEN); - os_memcpy(hdr.IEEE80211_BSSID_FROMDS, hapd->own_addr, - ETH_ALEN); - os_memcpy(hdr.IEEE80211_SA_FROMDS, hapd->own_addr, ETH_ALEN); - - if (hostapd_drv_send_mlme(hapd, &hdr, sizeof(hdr)) < 0) - perror("ap_handle_timer: send"); -#endif /* CONFIG_NATIVE_WINDOWS */ + hostapd_drv_poll_client(hapd, hapd->own_addr, sta->addr, + sta->flags & WLAN_STA_WMM); } else if (sta->timeout_next != STA_REMOVE) { int deauth = sta->timeout_next == STA_DEAUTH; - wpa_printf(MSG_DEBUG, "Sending %s info to STA " MACSTR, - deauth ? "deauthentication" : "disassociation", - MAC2STR(sta->addr)); + wpa_dbg(hapd->msg_ctx, MSG_DEBUG, + "Timeout, sending %s info to STA " MACSTR, + deauth ? "deauthentication" : "disassociation", + MAC2STR(sta->addr)); if (deauth) { hostapd_drv_sta_deauth( @@ -373,6 +357,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) hapd, sta); break; case STA_DISASSOC: + ap_sta_set_authorized(hapd, sta, 0); sta->flags &= ~WLAN_STA_ASSOC; ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); if (!sta->acct_terminate_cause) @@ -393,7 +378,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) case STA_REMOVE: hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "deauthenticated due to " - "inactivity"); + "inactivity (timer DEAUTH/REMOVE)"); if (!sta->acct_terminate_cause) sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT; @@ -525,13 +510,23 @@ static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd, } +static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx) +{ + struct hostapd_data *hapd = eloop_ctx; + struct sta_info *sta = timeout_ctx; + + ap_sta_remove(hapd, sta); + mlme_disassociate_indication(hapd, sta, sta->disassoc_reason); +} + + void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta, u16 reason) { wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR, hapd->conf->iface, MAC2STR(sta->addr)); sta->flags &= ~WLAN_STA_ASSOC; - ap_sta_remove(hapd, sta); + ap_sta_set_authorized(hapd, sta, 0); sta->timeout_next = STA_DEAUTH; eloop_cancel_timeout(ap_handle_timer, hapd, sta); eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DISASSOC, 0, @@ -539,7 +534,22 @@ void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta, accounting_sta_stop(hapd, sta); ieee802_1x_free_station(sta); - mlme_disassociate_indication(hapd, sta, reason); + sta->disassoc_reason = reason; + sta->flags |= WLAN_STA_PENDING_DISASSOC_CB; + eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta); + eloop_register_timeout(hapd->iface->drv_flags & + WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0, + ap_sta_disassoc_cb_timeout, hapd, sta); +} + + +static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx) +{ + struct hostapd_data *hapd = eloop_ctx; + struct sta_info *sta = timeout_ctx; + + ap_sta_remove(hapd, sta); + mlme_deauthenticate_indication(hapd, sta, sta->deauth_reason); } @@ -549,7 +559,7 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta, wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR, hapd->conf->iface, MAC2STR(sta->addr)); sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); - ap_sta_remove(hapd, sta); + ap_sta_set_authorized(hapd, sta, 0); sta->timeout_next = STA_REMOVE; eloop_cancel_timeout(ap_handle_timer, hapd, sta); eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0, @@ -557,7 +567,12 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta, accounting_sta_stop(hapd, sta); ieee802_1x_free_station(sta); - mlme_deauthenticate_indication(hapd, sta, reason); + sta->deauth_reason = reason; + sta->flags |= WLAN_STA_PENDING_DEAUTH_CB; + eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta); + eloop_register_timeout(hapd->iface->drv_flags & + WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0, + ap_sta_deauth_cb_timeout, hapd, sta); } @@ -762,17 +777,58 @@ void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta) void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta, int authorized) { + const u8 *dev_addr = NULL; if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED)) return; - if (authorized) +#ifdef CONFIG_P2P + dev_addr = p2p_group_get_dev_addr(hapd->p2p_group, sta->addr); +#endif /* CONFIG_P2P */ + + if (authorized) { + if (dev_addr) + wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED + MACSTR " p2p_dev_addr=" MACSTR, + MAC2STR(sta->addr), MAC2STR(dev_addr)); + else + wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED + MACSTR, MAC2STR(sta->addr)); + if (hapd->msg_ctx_parent && + hapd->msg_ctx_parent != hapd->msg_ctx && dev_addr) + wpa_msg(hapd->msg_ctx_parent, MSG_INFO, + AP_STA_CONNECTED MACSTR " p2p_dev_addr=" + MACSTR, + MAC2STR(sta->addr), MAC2STR(dev_addr)); + else if (hapd->msg_ctx_parent && + hapd->msg_ctx_parent != hapd->msg_ctx) + wpa_msg(hapd->msg_ctx_parent, MSG_INFO, + AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr)); + sta->flags |= WLAN_STA_AUTHORIZED; - else + } else { + if (dev_addr) + wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED + MACSTR " p2p_dev_addr=" MACSTR, + MAC2STR(sta->addr), MAC2STR(dev_addr)); + else + wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED + MACSTR, MAC2STR(sta->addr)); + if (hapd->msg_ctx_parent && + hapd->msg_ctx_parent != hapd->msg_ctx && dev_addr) + wpa_msg(hapd->msg_ctx_parent, MSG_INFO, + AP_STA_DISCONNECTED MACSTR " p2p_dev_addr=" + MACSTR, MAC2STR(sta->addr), MAC2STR(dev_addr)); + else if (hapd->msg_ctx_parent && + hapd->msg_ctx_parent != hapd->msg_ctx) + wpa_msg(hapd->msg_ctx_parent, MSG_INFO, + AP_STA_DISCONNECTED MACSTR, + MAC2STR(sta->addr)); sta->flags &= ~WLAN_STA_AUTHORIZED; + } if (hapd->sta_authorized_cb) hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx, - sta->addr, authorized); + sta->addr, authorized, dev_addr); } @@ -791,6 +847,38 @@ void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta, ap_sta_set_authorized(hapd, sta, 0); sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); eloop_cancel_timeout(ap_handle_timer, hapd, sta); - eloop_register_timeout(0, 0, ap_handle_timer, hapd, sta); + eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0, + ap_handle_timer, hapd, sta); sta->timeout_next = STA_REMOVE; + + sta->deauth_reason = reason; + sta->flags |= WLAN_STA_PENDING_DEAUTH_CB; + eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta); + eloop_register_timeout(hapd->iface->drv_flags & + WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0, + ap_sta_deauth_cb_timeout, hapd, sta); +} + + +void ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta) +{ + if (!(sta->flags & WLAN_STA_PENDING_DEAUTH_CB)) { + wpa_printf(MSG_DEBUG, "Ignore deauth cb for test frame"); + return; + } + sta->flags &= ~WLAN_STA_PENDING_DEAUTH_CB; + eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta); + ap_sta_deauth_cb_timeout(hapd, sta); +} + + +void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta) +{ + if (!(sta->flags & WLAN_STA_PENDING_DISASSOC_CB)) { + wpa_printf(MSG_DEBUG, "Ignore disassoc cb for test frame"); + return; + } + sta->flags &= ~WLAN_STA_PENDING_DISASSOC_CB; + eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta); + ap_sta_disassoc_cb_timeout(hapd, sta); } diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h index 9ec4fe3..daa96bf 100644 --- a/src/ap/sta_info.h +++ b/src/ap/sta_info.h @@ -1,6 +1,6 @@ /* * hostapd / Station table - * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> + * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -32,6 +32,9 @@ #define WLAN_STA_MAYBE_WPS BIT(13) #define WLAN_STA_WDS BIT(14) #define WLAN_STA_ASSOC_REQ_OK BIT(15) +#define WLAN_STA_WPS2 BIT(16) +#define WLAN_STA_PENDING_DISASSOC_CB BIT(29) +#define WLAN_STA_PENDING_DEAUTH_CB BIT(30) #define WLAN_STA_NONERP BIT(31) /* Maximum number of supported rates (from both Supported Rates and Extended @@ -49,6 +52,7 @@ struct sta_info { u16 listen_interval; /* or beacon_int for APs */ u8 supported_rates[WLAN_SUPP_RATES_MAX]; int supported_rates_len; + u8 qosinfo; /* Valid when WLAN_STA_WMM is set */ unsigned int nonerp_set:1; unsigned int no_short_slot_time_set:1; @@ -65,6 +69,9 @@ struct sta_info { STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE } timeout_next; + u16 deauth_reason; + u16 disassoc_reason; + /* IEEE 802.1X related data */ struct eapol_state_machine *eapol_sm; @@ -92,6 +99,7 @@ struct sta_info { struct hostapd_ssid *ssid_probe; /* SSID selection based on ProbeReq */ int vlan_id; + u8 *psk; /* PSK from RADIUS authentication server */ struct ieee80211_ht_capabilities *ht_capabilities; @@ -114,7 +122,7 @@ struct sta_info { * passed since last received frame from the station, a nullfunc data frame is * sent to the station. If this frame is not acknowledged and no other frames * have been received, the station will be disassociated after - * AP_DISASSOC_DELAY seconds. Similarily, the station will be deauthenticated + * AP_DISASSOC_DELAY seconds. Similarly, the station will be deauthenticated * after AP_DEAUTH_DELAY seconds has passed after disassociation. */ #define AP_MAX_INACTIVITY (5 * 60) #define AP_DISASSOC_DELAY (1) @@ -162,4 +170,7 @@ static inline int ap_sta_is_authorized(struct sta_info *sta) return sta->flags & WLAN_STA_AUTHORIZED; } +void ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta); +void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta); + #endif /* STA_INFO_H */ diff --git a/src/ap/tkip_countermeasures.c b/src/ap/tkip_countermeasures.c index 1925217..fac7f4b 100644 --- a/src/ap/tkip_countermeasures.c +++ b/src/ap/tkip_countermeasures.c @@ -1,6 +1,6 @@ /* * hostapd / TKIP countermeasures - * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> + * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -60,9 +60,15 @@ static void ieee80211_tkip_countermeasures_start(struct hostapd_data *hapd) } +void ieee80211_tkip_countermeasures_deinit(struct hostapd_data *hapd) +{ + eloop_cancel_timeout(ieee80211_tkip_countermeasures_stop, hapd, NULL); +} + + void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local) { - time_t now; + struct os_time now; if (addr && local) { struct sta_info *sta = ap_get_sta(hapd, addr); @@ -82,13 +88,13 @@ void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local) } } - time(&now); - if (now > hapd->michael_mic_failure + 60) { + os_get_time(&now); + if (now.sec > hapd->michael_mic_failure + 60) { hapd->michael_mic_failures = 1; } else { hapd->michael_mic_failures++; if (hapd->michael_mic_failures > 1) ieee80211_tkip_countermeasures_start(hapd); } - hapd->michael_mic_failure = now; + hapd->michael_mic_failure = now.sec; } diff --git a/src/ap/tkip_countermeasures.h b/src/ap/tkip_countermeasures.h index 5a1afce..a8ffd16 100644 --- a/src/ap/tkip_countermeasures.h +++ b/src/ap/tkip_countermeasures.h @@ -1,6 +1,6 @@ /* * hostapd / TKIP countermeasures - * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> + * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -16,5 +16,6 @@ #define TKIP_COUNTERMEASURES_H void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local); +void ieee80211_tkip_countermeasures_deinit(struct hostapd_data *hapd); #endif /* TKIP_COUNTERMEASURES_H */ diff --git a/src/ap/utils.c b/src/ap/utils.c index 0ff48ae..09bc32f 100644 --- a/src/ap/utils.c +++ b/src/ap/utils.c @@ -22,6 +22,7 @@ int hostapd_register_probereq_cb(struct hostapd_data *hapd, int (*cb)(void *ctx, const u8 *sa, + const u8 *da, const u8 *bssid, const u8 *ie, size_t ie_len), void *ctx) { diff --git a/src/ap/wmm.c b/src/ap/wmm.c index a6d9b89..d21c82f 100644 --- a/src/ap/wmm.c +++ b/src/ap/wmm.c @@ -72,7 +72,8 @@ u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid) wmm->version = WMM_VERSION; wmm->qos_info = hapd->parameter_set_count & 0xf; - if (hapd->conf->wmm_uapsd) + if (hapd->conf->wmm_uapsd && + (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_UAPSD)) wmm->qos_info |= 0x80; wmm->reserved = 0; @@ -97,9 +98,11 @@ u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid) } -/* This function is called when a station sends an association request with - * WMM info element. The function returns zero on success or non-zero on any - * error in WMM element. eid does not include Element ID and Length octets. */ +/* + * This function is called when a station sends an association request with + * WMM info element. The function returns 1 on success or 0 on any error in WMM + * element. eid does not include Element ID and Length octets. + */ int hostapd_eid_wmm_valid(struct hostapd_data *hapd, const u8 *eid, size_t len) { struct wmm_information_element *wmm; @@ -109,7 +112,7 @@ int hostapd_eid_wmm_valid(struct hostapd_data *hapd, const u8 *eid, size_t len) if (len < sizeof(struct wmm_information_element)) { wpa_printf(MSG_DEBUG, "Too short WMM IE (len=%lu)", (unsigned long) len); - return -1; + return 0; } wmm = (struct wmm_information_element *) eid; @@ -120,10 +123,10 @@ int hostapd_eid_wmm_valid(struct hostapd_data *hapd, const u8 *eid, size_t len) if (wmm->oui_subtype != WMM_OUI_SUBTYPE_INFORMATION_ELEMENT || wmm->version != WMM_VERSION) { wpa_printf(MSG_DEBUG, "Unsupported WMM IE Subtype/Version"); - return -1; + return 0; } - return 0; + return 1; } @@ -153,7 +156,7 @@ static void wmm_send_action(struct hostapd_data *hapd, const u8 *addr, os_memcpy(t, tspec, sizeof(struct wmm_tspec_element)); len = ((u8 *) (t + 1)) - buf; - if (hostapd_drv_send_mlme(hapd, m, len) < 0) + if (hostapd_drv_send_mlme(hapd, m, len, 0) < 0) perror("wmm_send_action: send"); } diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index 0836887..adc69e2 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -1,6 +1,6 @@ /* - * hostapd - IEEE 802.11i-2004 / WPA Authenticator - * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi> + * IEEE 802.11 RSN / WPA Authenticator + * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -52,6 +52,7 @@ static const u32 dot11RSNAConfigGroupUpdateCount = 4; static const u32 dot11RSNAConfigPairwiseUpdateCount = 4; static const u32 eapol_key_timeout_first = 100; /* ms */ static const u32 eapol_key_timeout_subseq = 1000; /* ms */ +static const u32 eapol_key_timeout_first_group = 500; /* ms */ /* TODO: make these configurable */ static const int dot11RSNAConfigPMKLifetime = 43200; @@ -194,6 +195,7 @@ static void wpa_sta_disconnect(struct wpa_authenticator *wpa_auth, { if (wpa_auth->cb.disconnect == NULL) return; + wpa_printf(MSG_DEBUG, "wpa_sta_disconnect STA " MACSTR, MAC2STR(addr)); wpa_auth->cb.disconnect(wpa_auth->cb.ctx, addr, WLAN_REASON_PREV_AUTH_NOT_VALID); } @@ -332,7 +334,7 @@ static int wpa_group_init_gmk_and_counter(struct wpa_authenticator *wpa_auth, static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth, - int vlan_id) + int vlan_id, int delay_init) { struct wpa_group *group; @@ -349,10 +351,6 @@ static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth, wpa_printf(MSG_INFO, "WPA: Not enough entropy in random pool " "for secure operations - update keys later when " "the first station connects"); -#ifdef ANDROID_BRCM_P2P_PATCH - os_free(group); - return NULL; -#endif } /* @@ -369,9 +367,15 @@ static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth, } group->GInit = TRUE; - wpa_group_sm_step(wpa_auth, group); - group->GInit = FALSE; - wpa_group_sm_step(wpa_auth, group); + if (delay_init) { + wpa_printf(MSG_DEBUG, "WPA: Delay group state machine start " + "until Beacon frames have been configured"); + /* Initialization is completed in wpa_init_keys(). */ + } else { + wpa_group_sm_step(wpa_auth, group); + group->GInit = FALSE; + wpa_group_sm_step(wpa_auth, group); + } return group; } @@ -403,7 +407,7 @@ struct wpa_authenticator * wpa_init(const u8 *addr, return NULL; } - wpa_auth->group = wpa_group_init(wpa_auth, 0); + wpa_auth->group = wpa_group_init(wpa_auth, 0, 1); if (wpa_auth->group == NULL) { os_free(wpa_auth->wpa_ie); os_free(wpa_auth); @@ -444,6 +448,19 @@ struct wpa_authenticator * wpa_init(const u8 *addr, } +int wpa_init_keys(struct wpa_authenticator *wpa_auth) +{ + struct wpa_group *group = wpa_auth->group; + + wpa_printf(MSG_DEBUG, "WPA: Start group state machine to set initial " + "keys"); + wpa_group_sm_step(wpa_auth, group); + group->GInit = FALSE; + wpa_group_sm_step(wpa_auth, group); + return 0; +} + + /** * wpa_deinit - Deinitialize WPA authenticator * @wpa_auth: Pointer to WPA authenticator data from wpa_init() @@ -695,6 +712,37 @@ static int ft_check_msg_2_of_4(struct wpa_authenticator *wpa_auth, #endif /* CONFIG_IEEE80211R */ +static void wpa_receive_error_report(struct wpa_authenticator *wpa_auth, + struct wpa_state_machine *sm, int group) +{ + /* Supplicant reported a Michael MIC error */ + wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, + "received EAPOL-Key Error Request " + "(STA detected Michael MIC failure (group=%d))", + group); + + if (group && wpa_auth->conf.wpa_group != WPA_CIPHER_TKIP) { + wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, + "ignore Michael MIC failure report since " + "group cipher is not TKIP"); + } else if (!group && sm->pairwise != WPA_CIPHER_TKIP) { + wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, + "ignore Michael MIC failure report since " + "pairwise cipher is not TKIP"); + } else { + wpa_auth_mic_failure_report(wpa_auth, sm->addr); + sm->dot11RSNAStatsTKIPRemoteMICFailures++; + wpa_auth->dot11RSNAStatsTKIPRemoteMICFailures++; + } + + /* + * Error report is not a request for a new key handshake, but since + * Authenticator may do it, let's change the keys now anyway. + */ + wpa_request_new_ptk(sm); +} + + void wpa_receive(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *sm, u8 *data, size_t data_len) @@ -720,6 +768,9 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, key = (struct wpa_eapol_key *) (hdr + 1); key_info = WPA_GET_BE16(key->key_info); key_data_length = WPA_GET_BE16(key->key_data_length); + wpa_printf(MSG_DEBUG, "WPA: Received EAPOL-Key from " MACSTR + " key_info=0x%x type=%u key_data_length=%u", + MAC2STR(sm->addr), key_info, key->type, key_data_length); if (key_data_length > data_len - sizeof(*hdr) - sizeof(*key)) { wpa_printf(MSG_INFO, "WPA: Invalid EAPOL-Key frame - " "key_data overflow (%d > %lu)", @@ -819,7 +870,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, if (!(key_info & WPA_KEY_INFO_REQUEST) && !wpa_replay_counter_valid(sm, key->replay_counter)) { int i; - wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, + wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, "received EAPOL-Key %s with unexpected " "replay counter", msgtxt); for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) { @@ -1000,17 +1051,9 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, #endif /* CONFIG_PEERKEY */ return; } else if (key_info & WPA_KEY_INFO_ERROR) { - /* Supplicant reported a Michael MIC error */ - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, - "received EAPOL-Key Error Request " - "(STA detected Michael MIC failure)"); - wpa_auth_mic_failure_report(wpa_auth, sm->addr); - sm->dot11RSNAStatsTKIPRemoteMICFailures++; - wpa_auth->dot11RSNAStatsTKIPRemoteMICFailures++; - /* Error report is not a request for a new key - * handshake, but since Authenticator may do it, let's - * change the keys now anyway. */ - wpa_request_new_ptk(sm); + wpa_receive_error_report( + wpa_auth, sm, + !(key_info & WPA_KEY_INFO_KEY_TYPE)); } else if (key_info & WPA_KEY_INFO_KEY_TYPE) { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, "received EAPOL-Key Request for new " @@ -1028,9 +1071,6 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, "received EAPOL-Key Request for GTK " "rekeying"); - /* FIX: why was this triggering PTK rekeying for the - * STA that requested Group Key rekeying?? */ - /* wpa_request_new_ptk(sta->wpa_sm); */ eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL); wpa_rekey_gtk(wpa_auth, NULL); } @@ -1057,6 +1097,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, os_memcpy(sm->last_rx_eapol_key, data, data_len); sm->last_rx_eapol_key_len = data_len; + sm->rx_eapol_key_secure = !!(key_info & WPA_KEY_INFO_SECURE); sm->EAPOLKeyReceived = TRUE; sm->EAPOLKeyPairwise = !!(key_info & WPA_KEY_INFO_KEY_TYPE); sm->EAPOLKeyRequest = !!(key_info & WPA_KEY_INFO_REQUEST); @@ -1293,7 +1334,8 @@ static void wpa_send_eapol(struct wpa_authenticator *wpa_auth, ctr = pairwise ? sm->TimeoutCtr : sm->GTimeoutCtr; if (ctr == 1 && wpa_auth->conf.tx_status) - timeout_ms = eapol_key_timeout_first; + timeout_ms = pairwise ? eapol_key_timeout_first : + eapol_key_timeout_first_group; else timeout_ms = eapol_key_timeout_subseq; if (pairwise && ctr == 1 && !(key_info & WPA_KEY_INFO_MIC)) @@ -1844,6 +1886,20 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) gtk_len = 0; keyidx = 0; _rsc = NULL; + if (sm->rx_eapol_key_secure) { + /* + * It looks like Windows 7 supplicant tries to use + * Secure bit in msg 2/4 after having reported Michael + * MIC failure and it then rejects the 4-way handshake + * if msg 3/4 does not set Secure bit. Work around this + * by setting the Secure bit here even in the case of + * WPA if the supplicant used it first. + */ + wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, + "STA used Secure bit in WPA msg 2/4 - " + "set Secure for 3/4 as workaround"); + secure = 1; + } } kde_len = wpa_ie_len + ieee80211w_kde_len(sm); @@ -2469,6 +2525,7 @@ void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth) group->GN_igtk = tmp; #endif /* CONFIG_IEEE80211W */ wpa_gtk_update(wpa_auth, group); + wpa_group_config_group_keys(wpa_auth, group); } } @@ -2771,7 +2828,7 @@ wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id) wpa_printf(MSG_DEBUG, "WPA: Add group state machine for VLAN-ID %d", vlan_id); - group = wpa_group_init(wpa_auth, vlan_id); + group = wpa_group_init(wpa_auth, vlan_id, 0); if (group == NULL) return NULL; diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index e533a14..ce2751e 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -208,6 +208,7 @@ struct wpa_auth_callbacks { struct wpa_authenticator * wpa_init(const u8 *addr, struct wpa_auth_config *conf, struct wpa_auth_callbacks *cb); +int wpa_init_keys(struct wpa_authenticator *wpa_auth); void wpa_deinit(struct wpa_authenticator *wpa_auth); int wpa_reconfig(struct wpa_authenticator *wpa_auth, struct wpa_auth_config *conf); diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c index 65f5f4c..2d1bbe4 100644 --- a/src/ap/wpa_auth_ft.c +++ b/src/ap/wpa_auth_ft.c @@ -24,33 +24,10 @@ #include "wmm.h" #include "wpa_auth.h" #include "wpa_auth_i.h" -#include "wpa_auth_ie.h" #ifdef CONFIG_IEEE80211R -struct wpa_ft_ies { - const u8 *mdie; - size_t mdie_len; - const u8 *ftie; - size_t ftie_len; - const u8 *r1kh_id; - const u8 *gtk; - size_t gtk_len; - const u8 *r0kh_id; - size_t r0kh_id_len; - const u8 *rsn; - size_t rsn_len; - const u8 *rsn_pmkid; - const u8 *ric; - size_t ric_len; -}; - - -static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, - struct wpa_ft_ies *parse); - - static int wpa_ft_rrb_send(struct wpa_authenticator *wpa_auth, const u8 *dst, const u8 *data, size_t data_len) { @@ -728,143 +705,6 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, } -static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len, - struct wpa_ft_ies *parse) -{ - const u8 *end, *pos; - - parse->ftie = ie; - parse->ftie_len = ie_len; - - pos = ie + sizeof(struct rsn_ftie); - end = ie + ie_len; - - while (pos + 2 <= end && pos + 2 + pos[1] <= end) { - switch (pos[0]) { - case FTIE_SUBELEM_R1KH_ID: - if (pos[1] != FT_R1KH_ID_LEN) { - wpa_printf(MSG_DEBUG, "FT: Invalid R1KH-ID " - "length in FTIE: %d", pos[1]); - return -1; - } - parse->r1kh_id = pos + 2; - break; - case FTIE_SUBELEM_GTK: - parse->gtk = pos + 2; - parse->gtk_len = pos[1]; - break; - case FTIE_SUBELEM_R0KH_ID: - if (pos[1] < 1 || pos[1] > FT_R0KH_ID_MAX_LEN) { - wpa_printf(MSG_DEBUG, "FT: Invalid R0KH-ID " - "length in FTIE: %d", pos[1]); - return -1; - } - parse->r0kh_id = pos + 2; - parse->r0kh_id_len = pos[1]; - break; - } - - pos += 2 + pos[1]; - } - - return 0; -} - - -static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, - struct wpa_ft_ies *parse) -{ - const u8 *end, *pos; - struct wpa_ie_data data; - int ret; - const struct rsn_ftie *ftie; - int prot_ie_count = 0; - - os_memset(parse, 0, sizeof(*parse)); - if (ies == NULL) - return 0; - - pos = ies; - end = ies + ies_len; - while (pos + 2 <= end && pos + 2 + pos[1] <= end) { - switch (pos[0]) { - case WLAN_EID_RSN: - parse->rsn = pos + 2; - parse->rsn_len = pos[1]; - ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2, - parse->rsn_len + 2, - &data); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "FT: Failed to parse " - "RSN IE: %d", ret); - return -1; - } - if (data.num_pmkid == 1 && data.pmkid) - parse->rsn_pmkid = data.pmkid; - break; - case WLAN_EID_MOBILITY_DOMAIN: - parse->mdie = pos + 2; - parse->mdie_len = pos[1]; - break; - case WLAN_EID_FAST_BSS_TRANSITION: - if (pos[1] < sizeof(*ftie)) - return -1; - ftie = (const struct rsn_ftie *) (pos + 2); - prot_ie_count = ftie->mic_control[1]; - if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0) - return -1; - break; - case WLAN_EID_RIC_DATA: - if (parse->ric == NULL) - parse->ric = pos; - } - - pos += 2 + pos[1]; - } - - if (prot_ie_count == 0) - return 0; /* no MIC */ - - /* - * Check that the protected IE count matches with IEs included in the - * frame. - */ - if (parse->rsn) - prot_ie_count--; - if (parse->mdie) - prot_ie_count--; - if (parse->ftie) - prot_ie_count--; - if (prot_ie_count < 0) { - wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in " - "the protected IE count"); - return -1; - } - - if (prot_ie_count == 0 && parse->ric) { - wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not " - "included in protected IE count"); - return -1; - } - - /* Determine the end of the RIC IE(s) */ - pos = parse->ric; - while (pos && pos + 2 <= end && pos + 2 + pos[1] <= end && - prot_ie_count) { - prot_ie_count--; - pos += 2 + pos[1]; - } - parse->ric_len = pos - parse->ric; - if (prot_ie_count) { - wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from " - "frame", (int) prot_ie_count); - return -1; - } - - return 0; -} - - static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth, int vlan_id, enum wpa_alg alg, const u8 *addr, int idx, @@ -1207,7 +1047,7 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, count = 3; if (parse.ric) - count++; + count += ieee802_11_ie_count(parse.ric, parse.ric_len); if (ftie->mic_control[1] != count) { wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC " "Control: received %u expected %u", diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c index 0e3cb31..56bab23 100644 --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c @@ -29,11 +29,13 @@ #include "ap_drv_ops.h" #include "ap_config.h" #include "wpa_auth.h" +#include "wpa_auth_glue.h" static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf, struct wpa_auth_config *wconf) { + os_memset(wconf, 0, sizeof(*wconf)); wconf->wpa = conf->wpa; wconf->wpa_key_mgmt = conf->wpa_key_mgmt; wconf->wpa_pairwise = conf->wpa_pairwise; @@ -184,6 +186,9 @@ static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr, const u8 *prev_psk) { struct hostapd_data *hapd = ctx; + struct sta_info *sta = ap_get_sta(hapd, addr); + if (sta && sta->psk) + return sta->psk; return hostapd_get_psk(hapd->conf, addr, prev_psk); } @@ -384,7 +389,7 @@ static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto, ret = l2_packet_send(hapd->l2, dst, proto, (u8 *) buf, sizeof(*buf) + data_len); os_free(buf); - return -1; + return ret; } @@ -414,7 +419,7 @@ static int hostapd_wpa_auth_send_ft_action(void *ctx, const u8 *dst, os_memcpy(m->bssid, hapd->own_addr, ETH_ALEN); os_memcpy(&m->u, data, data_len); - res = hostapd_drv_send_mlme(hapd, (u8 *) m, mlen); + res = hostapd_drv_send_mlme(hapd, (u8 *) m, mlen, 0); os_free(m); return res; } @@ -547,6 +552,7 @@ void hostapd_reconfig_wpa(struct hostapd_data *hapd) void hostapd_deinit_wpa(struct hostapd_data *hapd) { + ieee80211_tkip_countermeasures_deinit(hapd); rsn_preauth_iface_deinit(hapd); if (hapd->wpa_auth) { wpa_deinit(hapd->wpa_auth); diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h index 67a5c3b..d82192a 100644 --- a/src/ap/wpa_auth_i.h +++ b/src/ap/wpa_auth_i.h @@ -86,6 +86,7 @@ struct wpa_state_machine { unsigned int pending_deinit:1; unsigned int started:1; unsigned int mgmt_frame_prot:1; + unsigned int rx_eapol_key_secure:1; #ifdef CONFIG_IEEE80211R unsigned int ft_completed:1; unsigned int pmk_r1_name_valid:1; diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c index 9d4aa67..4db04bb 100644 --- a/src/ap/wpa_auth_ie.c +++ b/src/ap/wpa_auth_ie.c @@ -253,19 +253,10 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, capab |= WPA_CAPABILITY_PREAUTH; if (conf->peerkey) capab |= WPA_CAPABILITY_PEERKEY_ENABLED; -#ifdef ANDROID_BRCM_P2P_PATCH - /* WAR: we should make an get_wpa_rsnie_cap() to get the cap of peer supp - * Temporally we force tp set replay counter tp 0x3 - * as if wmm is enable in all of supp device - */ - capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2); -#else if (conf->wmm_enabled) { /* 4 PTKSA replay counters when using WMM */ capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2); } -#endif /* ANDROID_BRCM_P2P_PATCH */ - #ifdef CONFIG_IEEE80211W if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { capab |= WPA_CAPABILITY_MFPC; @@ -350,8 +341,7 @@ int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth) pos += res; } #ifdef CONFIG_IEEE80211R - if (wpa_auth->conf.wpa_key_mgmt & - (WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_FT_PSK)) { + if (wpa_key_mgmt_ft(wpa_auth->conf.wpa_key_mgmt)) { res = wpa_write_mdie(&wpa_auth->conf, pos, buf + sizeof(buf) - pos); if (res < 0) diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c index 640e8cd..817012e 100644 --- a/src/ap/wps_hostapd.c +++ b/src/ap/wps_hostapd.c @@ -41,7 +41,8 @@ static int hostapd_wps_upnp_init(struct hostapd_data *hapd, static void hostapd_wps_upnp_deinit(struct hostapd_data *hapd); #endif /* CONFIG_WPS_UPNP */ -static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, +static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, const u8 *da, + const u8 *bssid, const u8 *ie, size_t ie_len); static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx); @@ -140,7 +141,8 @@ static int hostapd_wps_set_ie_cb(void *ctx, struct wpabuf *beacon_ie, hapd->wps_beacon_ie = beacon_ie; wpabuf_free(hapd->wps_probe_resp_ie); hapd->wps_probe_resp_ie = probe_resp_ie; - ieee802_11_set_beacon(hapd); + if (hapd->beacon_set_done) + ieee802_11_set_beacon(hapd); return hostapd_set_ap_wps_ie(hapd); } @@ -184,11 +186,26 @@ static void hostapd_wps_pin_needed_cb(void *ctx, const u8 *uuid_e, } +struct wps_stop_reg_data { + struct hostapd_data *current_hapd; + const u8 *uuid_e; +}; + +static int wps_stop_registrar(struct hostapd_data *hapd, void *ctx) +{ + struct wps_stop_reg_data *data = ctx; + if (hapd != data->current_hapd && hapd->wps != NULL) + wps_registrar_complete(hapd->wps->registrar, data->uuid_e); + return 0; +} + + static void hostapd_wps_reg_success_cb(void *ctx, const u8 *mac_addr, const u8 *uuid_e) { struct hostapd_data *hapd = ctx; char uuid[40]; + struct wps_stop_reg_data data; if (uuid_bin2str(uuid_e, uuid, sizeof(uuid))) return; wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_REG_SUCCESS MACSTR " %s", @@ -196,6 +213,9 @@ static void hostapd_wps_reg_success_cb(void *ctx, const u8 *mac_addr, if (hapd->wps_reg_success_cb) hapd->wps_reg_success_cb(hapd->wps_reg_success_cb_ctx, mac_addr, uuid_e); + data.current_hapd = hapd; + data.uuid_e = uuid_e; + hostapd_wps_for_each(hapd, wps_stop_registrar, &data); } @@ -240,6 +260,20 @@ static void wps_reload_config(void *eloop_data, void *user_ctx) } +static void hapd_new_ap_event(struct hostapd_data *hapd, const u8 *attr, + size_t attr_len) +{ + size_t blen = attr_len * 2 + 1; + char *buf = os_malloc(blen); + if (buf) { + wpa_snprintf_hex(buf, blen, attr, attr_len); + wpa_msg(hapd->msg_ctx, MSG_INFO, + WPS_EVENT_NEW_AP_SETTINGS "%s", buf); + os_free(buf); + } +} + + static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx) { const struct wps_credential *cred = ctx; @@ -269,15 +303,15 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx) if ((hapd->conf->wps_cred_processing == 1 || hapd->conf->wps_cred_processing == 2) && cred->cred_attr) { - size_t blen = cred->cred_attr_len * 2 + 1; - char *_buf = os_malloc(blen); - if (_buf) { - wpa_snprintf_hex(_buf, blen, - cred->cred_attr, cred->cred_attr_len); - wpa_msg(hapd->msg_ctx, MSG_INFO, "%s%s", - WPS_EVENT_NEW_AP_SETTINGS, _buf); - os_free(_buf); - } + hapd_new_ap_event(hapd, cred->cred_attr, cred->cred_attr_len); + } else if (hapd->conf->wps_cred_processing == 1 || + hapd->conf->wps_cred_processing == 2) { + struct wpabuf *attr; + attr = wpabuf_alloc(200); + if (attr && wps_build_credential_wrap(attr, cred) == 0) + hapd_new_ap_event(hapd, wpabuf_head_u8(attr), + wpabuf_len(attr)); + wpabuf_free(attr); } else wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_NEW_AP_SETTINGS); @@ -565,18 +599,22 @@ static void hostapd_wps_event_cb(void *ctx, enum wps_event event, switch (event) { case WPS_EV_M2D: + wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_M2D); break; case WPS_EV_FAIL: hostapd_wps_event_fail(hapd, &data->fail); break; case WPS_EV_SUCCESS: + wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_SUCCESS); break; case WPS_EV_PWD_AUTH_FAIL: hostapd_pwd_auth_fail(hapd, &data->pwd_auth_fail); break; case WPS_EV_PBC_OVERLAP: + wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_OVERLAP); break; case WPS_EV_PBC_TIMEOUT: + wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_TIMEOUT); break; case WPS_EV_ER_AP_ADD: break; @@ -762,8 +800,14 @@ int hostapd_init_wps(struct hostapd_data *hapd, } wps->dev.os_version = WPA_GET_BE32(hapd->conf->os_version); - wps->dev.rf_bands = hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ? - WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */ + + if (conf->wps_rf_bands) { + wps->dev.rf_bands = conf->wps_rf_bands; + } else { + wps->dev.rf_bands = + hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ? + WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */ + } if (conf->wpa & WPA_PROTO_RSN) { if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) @@ -1076,7 +1120,8 @@ error: #endif /* CONFIG_WPS_OOB */ -static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, +static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, const u8 *da, + const u8 *bssid, const u8 *ie, size_t ie_len) { struct hostapd_data *hapd = ctx; @@ -1175,7 +1220,7 @@ static int hostapd_rx_req_put_wlan_response( } #endif /* CONFIG_WPS_STRICT */ - if (!sta) { + if (!sta || !(sta->flags & WLAN_STA_WPS)) { wpa_printf(MSG_DEBUG, "WPS UPnP: No matching STA found"); return 0; } @@ -1240,6 +1285,7 @@ static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx) struct hostapd_data *hapd = eloop_data; wpa_printf(MSG_DEBUG, "WPS: AP PIN timed out"); hostapd_wps_ap_pin_disable(hapd); + wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_PIN_DISABLED); } @@ -1304,7 +1350,7 @@ const char * hostapd_wps_ap_pin_random(struct hostapd_data *hapd, int timeout) struct wps_ap_pin_data data; pin = wps_generate_pin(); - os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%u", pin); + os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%08u", pin); data.timeout = timeout; hostapd_wps_for_each(hapd, wps_ap_pin_set, &data); return hapd->conf->ap_pin; |