diff options
Diffstat (limited to 'src/ap')
44 files changed, 1663 insertions, 384 deletions
diff --git a/src/ap/Makefile b/src/ap/Makefile index adfd3df..98788fe 100644 --- a/src/ap/Makefile +++ b/src/ap/Makefile @@ -1,8 +1,67 @@ -all: - @echo Nothing to be made. +all: libap.a clean: - rm -f *~ *.o *.d *.gcno *.gcda *.gcov + rm -f *~ *.o *.d *.gcno *.gcda *.gcov libap.a install: @echo Nothing to be made. + +include ../lib.rules + +CFLAGS += -DHOSTAPD +CFLAGS += -DNEED_AP_MLME +CFLAGS += -DCONFIG_HS20 +CFLAGS += -DCONFIG_INTERWORKING +CFLAGS += -DCONFIG_IEEE80211R +CFLAGS += -DCONFIG_IEEE80211W +CFLAGS += -DCONFIG_WPS +CFLAGS += -DCONFIG_PROXYARP +CFLAGS += -DCONFIG_IAPP + +LIB_OBJS= \ + accounting.o \ + ap_config.o \ + ap_drv_ops.o \ + ap_list.o \ + ap_mlme.o \ + authsrv.o \ + beacon.o \ + bss_load.o \ + ctrl_iface_ap.o \ + dfs.o \ + dhcp_snoop.o \ + drv_callbacks.o \ + eap_user_db.o \ + gas_serv.o \ + hostapd.o \ + hs20.o \ + hw_features.o \ + iapp.o \ + ieee802_11_auth.o \ + ieee802_11.o \ + ieee802_11_ht.o \ + ieee802_11_shared.o \ + ieee802_11_vht.o \ + ieee802_1x.o \ + ndisc_snoop.o \ + p2p_hostapd.o \ + peerkey_auth.o \ + pmksa_cache_auth.o \ + preauth_auth.o \ + sta_info.o \ + tkip_countermeasures.o \ + utils.o \ + vlan_init.o \ + wmm.o \ + wnm_ap.o \ + wpa_auth.o \ + wpa_auth_ft.o \ + wpa_auth_glue.o \ + wpa_auth_ie.o \ + wps_hostapd.o \ + x_snoop.o + +libap.a: $(LIB_OBJS) + $(AR) crT $@ $? + +-include $(OBJS:%.o=%.d) diff --git a/src/ap/accounting.c b/src/ap/accounting.c index 7c55146..a096de4 100644 --- a/src/ap/accounting.c +++ b/src/ap/accounting.c @@ -459,10 +459,14 @@ int accounting_init(struct hostapd_data *hapd) { struct os_time now; - /* Acct-Session-Id should be unique over reboots. If reliable clock is - * not available, this could be replaced with reboot counter, etc. */ + /* Acct-Session-Id should be unique over reboots. Using a random number + * is preferred. If that is not available, take the current time. Mix + * in microseconds to make this more likely to be unique. */ os_get_time(&now); - hapd->acct_session_id_hi = now.sec; + if (os_get_random((u8 *) &hapd->acct_session_id_hi, + sizeof(hapd->acct_session_id_hi)) < 0) + hapd->acct_session_id_hi = now.sec; + hapd->acct_session_id_hi ^= now.usec; if (radius_client_register(hapd->radius, RADIUS_ACCT, accounting_receive, hapd)) @@ -475,7 +479,7 @@ int accounting_init(struct hostapd_data *hapd) /** - * accounting_deinit: Deinitilize accounting + * accounting_deinit: Deinitialize accounting * @hapd: hostapd BSS data */ void accounting_deinit(struct hostapd_data *hapd) diff --git a/src/ap/acs.c b/src/ap/acs.c index ae7f6c3..03d797f 100644 --- a/src/ap/acs.c +++ b/src/ap/acs.c @@ -479,16 +479,10 @@ static int acs_usable_chan(struct hostapd_channel_data *chan) static int is_in_chanlist(struct hostapd_iface *iface, struct hostapd_channel_data *chan) { - int *entry; - - if (!iface->conf->chanlist) + if (!iface->conf->acs_ch_list.num) return 1; - for (entry = iface->conf->chanlist; *entry != -1; entry++) { - if (*entry == chan->chan) - return 1; - } - return 0; + return freq_range_list_includes(&iface->conf->acs_ch_list, chan->chan); } @@ -900,6 +894,9 @@ static int acs_request_scan(struct hostapd_iface *iface) if (chan->flag & HOSTAPD_CHAN_DISABLED) continue; + if (!is_in_chanlist(iface, chan)) + continue; + *freq++ = chan->freq; } *freq = 0; diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index 76011dc..9a96e50 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -172,6 +172,7 @@ struct hostapd_config * hostapd_config_defaults(void) conf->ap_table_max_size = 255; conf->ap_table_expiration_time = 60; + conf->track_sta_max_age = 180; #ifdef CONFIG_TESTING_OPTIONS conf->ignore_probe_probability = 0.0; @@ -181,6 +182,8 @@ struct hostapd_config * hostapd_config_defaults(void) conf->corrupt_gtk_rekey_mic_probability = 0.0; #endif /* CONFIG_TESTING_OPTIONS */ + conf->acs = 0; + conf->acs_ch_list.num = 0; #ifdef CONFIG_ACS conf->acs_num_scans = 5; #endif /* CONFIG_ACS */ @@ -559,6 +562,13 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf) os_free(conf->server_id); +#ifdef CONFIG_TESTING_OPTIONS + wpabuf_free(conf->own_ie_override); +#endif /* CONFIG_TESTING_OPTIONS */ + + os_free(conf->no_probe_resp_if_seen_on); + os_free(conf->no_auth_if_seen_on); + os_free(conf); } @@ -579,7 +589,7 @@ void hostapd_config_free(struct hostapd_config *conf) os_free(conf->bss); os_free(conf->supported_rates); os_free(conf->basic_rates); - os_free(conf->chanlist); + os_free(conf->acs_ch_list.range); os_free(conf->driver_params); #ifdef CONFIG_ACS os_free(conf->acs_chan_bias); @@ -817,9 +827,9 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss, if (full_config && bss->wps_state && bss->wpa && (!(bss->wpa & 2) || - !(bss->rsn_pairwise & WPA_CIPHER_CCMP))) { + !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)))) { wpa_printf(MSG_INFO, "WPS: WPA/TKIP configuration without " - "WPA2/CCMP forced WPS to be disabled"); + "WPA2/CCMP/GCMP forced WPS to be disabled"); bss->wps_state = 0; } #endif /* CONFIG_WPS */ @@ -841,6 +851,29 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss, } +static int hostapd_config_check_cw(struct hostapd_config *conf, int queue) +{ + int tx_cwmin = conf->tx_queue[queue].cwmin; + int tx_cwmax = conf->tx_queue[queue].cwmax; + int ac_cwmin = conf->wmm_ac_params[queue].cwmin; + int ac_cwmax = conf->wmm_ac_params[queue].cwmax; + + if (tx_cwmin > tx_cwmax) { + wpa_printf(MSG_ERROR, + "Invalid TX queue cwMin/cwMax values. cwMin(%d) greater than cwMax(%d)", + tx_cwmin, tx_cwmax); + return -1; + } + if (ac_cwmin > ac_cwmax) { + wpa_printf(MSG_ERROR, + "Invalid WMM AC cwMin/cwMax values. cwMin(%d) greater than cwMax(%d)", + ac_cwmin, ac_cwmax); + return -1; + } + return 0; +} + + int hostapd_config_check(struct hostapd_config *conf, int full_config) { size_t i; @@ -870,6 +903,11 @@ int hostapd_config_check(struct hostapd_config *conf, int full_config) return -1; } + for (i = 0; i < NUM_TX_QUEUES; i++) { + if (hostapd_config_check_cw(conf, i)) + return -1; + } + for (i = 0; i < conf->num_bss; i++) { if (hostapd_config_check_bss(conf->bss[i], conf, full_config)) return -1; @@ -937,10 +975,11 @@ void hostapd_set_security_params(struct hostapd_bss_config *bss, bss->rsn_pairwise = WPA_CIPHER_CCMP; } else { bss->ssid.security_policy = SECURITY_PLAINTEXT; - bss->wpa_group = WPA_CIPHER_NONE; - bss->wpa_pairwise = WPA_CIPHER_NONE; - bss->rsn_pairwise = WPA_CIPHER_NONE; - if (full_config) + if (full_config) { + bss->wpa_group = WPA_CIPHER_NONE; + bss->wpa_pairwise = WPA_CIPHER_NONE; + bss->rsn_pairwise = WPA_CIPHER_NONE; bss->wpa_key_mgmt = WPA_KEY_MGMT_NONE; + } } } diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 961d2dd..de470a9 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -1,6 +1,6 @@ /* * hostapd / Configuration definitions and helpers functions - * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi> + * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -12,8 +12,10 @@ #include "common/defs.h" #include "ip_addr.h" #include "common/wpa_common.h" +#include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" #include "wps/wps.h" +#include "fst/fst.h" /** * mesh_conf - local MBSS state and settings @@ -31,8 +33,8 @@ struct mesh_conf { u8 mesh_sp_id; /* Authentication Protocol Identifier */ u8 mesh_auth_id; - u8 *ies; - int ie_len; + u8 *rsn_ie; + int rsn_ie_len; #define MESH_CONF_SEC_NONE BIT(0) #define MESH_CONF_SEC_AUTH BIT(1) #define MESH_CONF_SEC_AMPE BIT(2) @@ -57,8 +59,6 @@ struct hostapd_radius_servers; struct ft_remote_r0kh; struct ft_remote_r1kh; -#define HOSTAPD_MAX_SSID_LEN 32 - #define NUM_WEP_KEYS 4 struct hostapd_wep_keys { u8 idx; @@ -78,7 +78,7 @@ typedef enum hostap_security_policy { } secpolicy; struct hostapd_ssid { - u8 ssid[HOSTAPD_MAX_SSID_LEN]; + u8 ssid[SSID_MAX_LEN]; size_t ssid_len; unsigned int ssid_set:1; unsigned int utf8_ssid:1; @@ -114,12 +114,10 @@ struct hostapd_vlan { struct hostapd_vlan *next; int vlan_id; /* VLAN ID or -1 (VLAN_ID_WILDCARD) for wildcard entry */ char ifname[IFNAMSIZ + 1]; + int configured; int dynamic_vlan; #ifdef CONFIG_FULL_DYNAMIC_VLAN -#define DVLAN_CLEAN_BR 0x1 -#define DVLAN_CLEAN_VLAN 0x2 -#define DVLAN_CLEAN_VLAN_PORT 0x4 #define DVLAN_CLEAN_WLAN_PORT 0x8 int clean; #endif /* CONFIG_FULL_DYNAMIC_VLAN */ @@ -332,6 +330,7 @@ struct hostapd_bss_config { char *private_key; char *private_key_passwd; int check_crl; + unsigned int tls_session_lifetime; char *ocsp_stapling_response; char *dh_file; char *openssl_ciphers; @@ -490,6 +489,7 @@ struct hostapd_bss_config { int osen; int proxy_arp; + int na_mcast_to_ucast; #ifdef CONFIG_HS20 int hs20; int disable_dgaf; @@ -510,7 +510,7 @@ struct hostapd_bss_config { char file[256]; } *hs20_icons; size_t hs20_icons_count; - u8 osu_ssid[HOSTAPD_MAX_SSID_LEN]; + u8 osu_ssid[SSID_MAX_LEN]; size_t osu_ssid_len; struct hs20_osu_provider { unsigned int friendly_name_count; @@ -545,6 +545,7 @@ struct hostapd_bss_config { #ifdef CONFIG_TESTING_OPTIONS u8 bss_load_test[5]; u8 bss_load_test_set; + struct wpabuf *own_ie_override; #endif /* CONFIG_TESTING_OPTIONS */ #define MESH_ENABLED BIT(0) @@ -553,6 +554,9 @@ struct hostapd_bss_config { int radio_measurements; int vendor_vht; + + char *no_probe_resp_if_seen_on; + char *no_auth_if_seen_on; }; @@ -568,7 +572,8 @@ struct hostapd_config { int fragm_threshold; u8 send_probe_response; u8 channel; - int *chanlist; + u8 acs; + struct wpa_freq_range_list acs_ch_list; enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */ enum { LONG_PREAMBLE = 0, @@ -584,6 +589,9 @@ struct hostapd_config { int ap_table_max_size; int ap_table_expiration_time; + unsigned int track_sta_max_num; + unsigned int track_sta_max_age; + char country[3]; /* first two octets: country code as described in * ISO/IEC 3166-1. Third octet: * ' ' (ascii 32): all environments @@ -620,6 +628,7 @@ struct hostapd_config { u16 ht_capab; int ieee80211n; int secondary_channel; + int no_pri_sec_switch; int require_ht; int obss_interval; u32 vht_capab; @@ -629,6 +638,10 @@ struct hostapd_config { u8 vht_oper_centr_freq_seg0_idx; u8 vht_oper_centr_freq_seg1_idx; +#ifdef CONFIG_FST + struct fst_iface_cfg fst_cfg; +#endif /* CONFIG_FST */ + #ifdef CONFIG_P2P u8 p2p_go_ctwindow; #endif /* CONFIG_P2P */ diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c index e16306c..6cafcb7 100644 --- a/src/ap/ap_drv_ops.c +++ b/src/ap/ap_drv_ops.c @@ -81,6 +81,22 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd, wpabuf_put_data(proberesp, buf, pos - buf); } +#ifdef CONFIG_FST + if (hapd->iface->fst_ies) { + size_t add = wpabuf_len(hapd->iface->fst_ies); + + if (wpabuf_resize(&beacon, add) < 0) + goto fail; + wpabuf_put_buf(beacon, hapd->iface->fst_ies); + if (wpabuf_resize(&proberesp, add) < 0) + goto fail; + wpabuf_put_buf(proberesp, hapd->iface->fst_ies); + if (wpabuf_resize(&assocresp, add) < 0) + goto fail; + wpabuf_put_buf(assocresp, hapd->iface->fst_ies); + } +#endif /* CONFIG_FST */ + if (hapd->wps_beacon_ie) { if (wpabuf_resize(&beacon, wpabuf_len(hapd->wps_beacon_ie)) < 0) @@ -217,6 +233,15 @@ void hostapd_free_ap_extra_ies(struct hostapd_data *hapd, } +int hostapd_reset_ap_wps_ie(struct hostapd_data *hapd) +{ + if (hapd->driver == NULL || hapd->driver->set_ap_wps_ie == NULL) + return 0; + + return hapd->driver->set_ap_wps_ie(hapd->drv_priv, NULL, NULL, NULL); +} + + int hostapd_set_ap_wps_ie(struct hostapd_data *hapd) { struct wpabuf *beacon, *proberesp, *assocresp; @@ -281,8 +306,14 @@ int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname, params.wpa = hapd->conf->wpa; params.ieee802_1x = hapd->conf->ieee802_1x; params.wpa_group = hapd->conf->wpa_group; - params.wpa_pairwise = hapd->conf->wpa_pairwise | - hapd->conf->rsn_pairwise; + if ((hapd->conf->wpa & (WPA_PROTO_WPA | WPA_PROTO_RSN)) == + (WPA_PROTO_WPA | WPA_PROTO_RSN)) + params.wpa_pairwise = hapd->conf->wpa_pairwise | + hapd->conf->rsn_pairwise; + else if (hapd->conf->wpa & WPA_PROTO_RSN) + params.wpa_pairwise = hapd->conf->rsn_pairwise; + else if (hapd->conf->wpa & WPA_PROTO_WPA) + params.wpa_pairwise = hapd->conf->wpa_pairwise; params.wpa_key_mgmt = hapd->conf->wpa_key_mgmt; params.rsn_preauth = hapd->conf->rsn_preauth; #ifdef CONFIG_IEEE80211W @@ -618,7 +649,7 @@ int hostapd_drv_send_mlme(struct hostapd_data *hapd, { if (hapd->driver == NULL || hapd->driver->send_mlme == NULL) return 0; - return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack); + return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0); } @@ -712,16 +743,100 @@ int hostapd_drv_set_qos_map(struct hostapd_data *hapd, } +static void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd, + struct hostapd_hw_modes *mode, + int acs_ch_list_all, + int **freq_list) +{ + int i; + + for (i = 0; i < mode->num_channels; i++) { + struct hostapd_channel_data *chan = &mode->channels[i]; + + if ((acs_ch_list_all || + freq_range_list_includes(&hapd->iface->conf->acs_ch_list, + chan->chan)) && + !(chan->flag & HOSTAPD_CHAN_DISABLED)) + int_array_add_unique(freq_list, chan->freq); + } +} + + int hostapd_drv_do_acs(struct hostapd_data *hapd) { struct drv_acs_params params; + int ret, i, acs_ch_list_all = 0; + u8 *channels = NULL; + unsigned int num_channels = 0; + struct hostapd_hw_modes *mode; + int *freq_list = NULL; if (hapd->driver == NULL || hapd->driver->do_acs == NULL) return 0; + os_memset(¶ms, 0, sizeof(params)); params.hw_mode = hapd->iface->conf->hw_mode; + + /* + * If no chanlist config parameter is provided, include all enabled + * channels of the selected hw_mode. + */ + if (!hapd->iface->conf->acs_ch_list.num) + acs_ch_list_all = 1; + + mode = hapd->iface->current_mode; + if (mode) { + channels = os_malloc(mode->num_channels); + if (channels == NULL) + return -1; + + for (i = 0; i < mode->num_channels; i++) { + struct hostapd_channel_data *chan = &mode->channels[i]; + if (!acs_ch_list_all && + !freq_range_list_includes( + &hapd->iface->conf->acs_ch_list, + chan->chan)) + continue; + if (!(chan->flag & HOSTAPD_CHAN_DISABLED)) { + channels[num_channels++] = chan->chan; + int_array_add_unique(&freq_list, chan->freq); + } + } + } else { + for (i = 0; i < hapd->iface->num_hw_features; i++) { + mode = &hapd->iface->hw_features[i]; + hostapd_get_hw_mode_any_channels(hapd, mode, + acs_ch_list_all, + &freq_list); + } + } + + params.ch_list = channels; + params.ch_list_len = num_channels; + params.freq_list = freq_list; + params.ht_enabled = !!(hapd->iface->conf->ieee80211n); params.ht40_enabled = !!(hapd->iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET); - return hapd->driver->do_acs(hapd->drv_priv, ¶ms); + params.vht_enabled = !!(hapd->iface->conf->ieee80211ac); + params.ch_width = 20; + if (hapd->iface->conf->ieee80211n && params.ht40_enabled) + params.ch_width = 40; + + /* Note: VHT20 is defined by combination of ht_capab & vht_oper_chwidth + */ + if (hapd->iface->conf->ieee80211ac && params.ht40_enabled) { + if (hapd->iface->conf->vht_oper_chwidth == VHT_CHANWIDTH_80MHZ) + params.ch_width = 80; + else if (hapd->iface->conf->vht_oper_chwidth == + VHT_CHANWIDTH_160MHZ || + hapd->iface->conf->vht_oper_chwidth == + VHT_CHANWIDTH_80P80MHZ) + params.ch_width = 160; + } + + ret = hapd->driver->do_acs(hapd->drv_priv, ¶ms); + os_free(channels); + + return ret; } diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h index 5d07e71..82eaf3f 100644 --- a/src/ap/ap_drv_ops.h +++ b/src/ap/ap_drv_ops.h @@ -24,6 +24,7 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd, void hostapd_free_ap_extra_ies(struct hostapd_data *hapd, struct wpabuf *beacon, struct wpabuf *proberesp, struct wpabuf *assocresp); +int hostapd_reset_ap_wps_ie(struct hostapd_data *hapd); int hostapd_set_ap_wps_ie(struct hostapd_data *hapd); int hostapd_set_authorized(struct hostapd_data *hapd, struct sta_info *sta, int authorized); diff --git a/src/ap/ap_list.c b/src/ap/ap_list.c index 04a56a9..8bf6dde 100644 --- a/src/ap/ap_list.c +++ b/src/ap/ap_list.c @@ -193,14 +193,14 @@ void ap_list_process_beacon(struct hostapd_iface *iface, elems->supp_rates, elems->supp_rates_len, elems->ext_supp_rates, elems->ext_supp_rates_len); - if (elems->erp_info && elems->erp_info_len == 1) + if (elems->erp_info) ap->erp = elems->erp_info[0]; else ap->erp = -1; - if (elems->ds_params && elems->ds_params_len == 1) + if (elems->ds_params) ap->channel = elems->ds_params[0]; - else if (elems->ht_operation && elems->ht_operation_len >= 1) + else if (elems->ht_operation) ap->channel = elems->ht_operation[0]; else if (fi) ap->channel = fi->channel; @@ -248,15 +248,12 @@ void ap_list_process_beacon(struct hostapd_iface *iface, } -static void ap_list_timer(void *eloop_ctx, void *timeout_ctx) +void ap_list_timer(struct hostapd_iface *iface) { - struct hostapd_iface *iface = eloop_ctx; struct os_reltime now; struct ap_info *ap; int set_beacon = 0; - eloop_register_timeout(10, 0, ap_list_timer, iface, NULL); - if (!iface->ap_list) return; @@ -305,13 +302,11 @@ static void ap_list_timer(void *eloop_ctx, void *timeout_ctx) int ap_list_init(struct hostapd_iface *iface) { - eloop_register_timeout(10, 0, ap_list_timer, iface, NULL); return 0; } void ap_list_deinit(struct hostapd_iface *iface) { - eloop_cancel_timeout(ap_list_timer, iface, NULL); hostapd_free_aps(iface); } diff --git a/src/ap/ap_list.h b/src/ap/ap_list.h index 93dc0ed..9e0353c 100644 --- a/src/ap/ap_list.h +++ b/src/ap/ap_list.h @@ -39,6 +39,7 @@ void ap_list_process_beacon(struct hostapd_iface *iface, #ifdef NEED_AP_MLME int ap_list_init(struct hostapd_iface *iface); void ap_list_deinit(struct hostapd_iface *iface); +void ap_list_timer(struct hostapd_iface *iface); #else /* NEED_AP_MLME */ static inline int ap_list_init(struct hostapd_iface *iface) { @@ -48,6 +49,10 @@ static inline int ap_list_init(struct hostapd_iface *iface) static inline void ap_list_deinit(struct hostapd_iface *iface) { } + +static inline void ap_list_timer(struct hostapd_iface *iface) +{ +} #endif /* NEED_AP_MLME */ #endif /* AP_LIST_H */ diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c index bd1778e..934dcfc 100644 --- a/src/ap/authsrv.c +++ b/src/ap/authsrv.c @@ -55,10 +55,11 @@ static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity, { const struct hostapd_eap_user *eap_user; int i; + int rv = -1; eap_user = hostapd_get_eap_user(ctx, identity, identity_len, phase2); if (eap_user == NULL) - return -1; + goto out; if (user == NULL) return 0; @@ -72,7 +73,7 @@ static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity, if (eap_user->password) { user->password = os_malloc(eap_user->password_len); if (user->password == NULL) - return -1; + goto out; os_memcpy(user->password, eap_user->password, eap_user->password_len); user->password_len = eap_user->password_len; @@ -83,8 +84,13 @@ static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity, user->ttls_auth = eap_user->ttls_auth; user->remediation = eap_user->remediation; user->accept_attr = eap_user->accept_attr; + rv = 0; - return 0; +out: + if (rv) + wpa_printf(MSG_DEBUG, "%s: Failed to find user", __func__); + + return rv; } @@ -126,6 +132,7 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd) #endif /* CONFIG_HS20 */ srv.erp = conf->eap_server_erp; srv.erp_domain = conf->erp_domain; + srv.tls_session_lifetime = conf->tls_session_lifetime; hapd->radius_srv = radius_server_init(&srv); if (hapd->radius_srv == NULL) { @@ -145,9 +152,12 @@ int authsrv_init(struct hostapd_data *hapd) if (hapd->conf->eap_server && (hapd->conf->ca_cert || hapd->conf->server_cert || hapd->conf->private_key || hapd->conf->dh_file)) { + struct tls_config conf; struct tls_connection_params params; - hapd->ssl_ctx = tls_init(NULL); + os_memset(&conf, 0, sizeof(conf)); + conf.tls_session_lifetime = hapd->conf->tls_session_lifetime; + hapd->ssl_ctx = tls_init(&conf); if (hapd->ssl_ctx == NULL) { wpa_printf(MSG_ERROR, "Failed to initialize TLS"); authsrv_deinit(hapd); diff --git a/src/ap/beacon.c b/src/ap/beacon.c index e575b65..5fe8fd5 100644 --- a/src/ap/beacon.c +++ b/src/ap/beacon.c @@ -360,7 +360,6 @@ static u8 * hostapd_add_csa_elems(struct hostapd_data *hapd, u8 *pos, 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) { @@ -378,6 +377,10 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, if (hapd->p2p_probe_resp_ie) buflen += wpabuf_len(hapd->p2p_probe_resp_ie); #endif /* CONFIG_P2P */ +#ifdef CONFIG_FST + if (hapd->iface->fst_ies) + buflen += wpabuf_len(hapd->iface->fst_ies); +#endif /* CONFIG_FST */ if (hapd->conf->vendor_elements) buflen += wpabuf_len(hapd->conf->vendor_elements); if (hapd->conf->vendor_vht) { @@ -402,7 +405,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, /* 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)); + host_to_le16(hostapd_own_capab_info(hapd)); pos = resp->u.probe_resp.variable; *pos++ = WLAN_EID_SSID; @@ -450,6 +453,15 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, pos = hostapd_add_csa_elems(hapd, pos, (u8 *)resp, &hapd->cs_c_off_proberesp); + +#ifdef CONFIG_FST + if (hapd->iface->fst_ies) { + os_memcpy(pos, wpabuf_head(hapd->iface->fst_ies), + wpabuf_len(hapd->iface->fst_ies)); + pos += wpabuf_len(hapd->iface->fst_ies); + } +#endif /* CONFIG_FST */ + #ifdef CONFIG_IEEE80211AC if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) { pos = hostapd_eid_vht_capabilities(hapd, pos); @@ -540,6 +552,102 @@ static enum ssid_match_result ssid_match(struct hostapd_data *hapd, } +void sta_track_expire(struct hostapd_iface *iface, int force) +{ + struct os_reltime now; + struct hostapd_sta_info *info; + + if (!iface->num_sta_seen) + return; + + os_get_reltime(&now); + while ((info = dl_list_first(&iface->sta_seen, struct hostapd_sta_info, + list))) { + if (!force && + !os_reltime_expired(&now, &info->last_seen, + iface->conf->track_sta_max_age)) + break; + force = 0; + + wpa_printf(MSG_MSGDUMP, "%s: Expire STA tracking entry for " + MACSTR, iface->bss[0]->conf->iface, + MAC2STR(info->addr)); + dl_list_del(&info->list); + iface->num_sta_seen--; + os_free(info); + } +} + + +static struct hostapd_sta_info * sta_track_get(struct hostapd_iface *iface, + const u8 *addr) +{ + struct hostapd_sta_info *info; + + dl_list_for_each(info, &iface->sta_seen, struct hostapd_sta_info, list) + if (os_memcmp(addr, info->addr, ETH_ALEN) == 0) + return info; + + return NULL; +} + + +void sta_track_add(struct hostapd_iface *iface, const u8 *addr) +{ + struct hostapd_sta_info *info; + + info = sta_track_get(iface, addr); + if (info) { + /* Move the most recent entry to the end of the list */ + dl_list_del(&info->list); + dl_list_add_tail(&iface->sta_seen, &info->list); + os_get_reltime(&info->last_seen); + return; + } + + /* Add a new entry */ + info = os_zalloc(sizeof(*info)); + os_memcpy(info->addr, addr, ETH_ALEN); + os_get_reltime(&info->last_seen); + + if (iface->num_sta_seen >= iface->conf->track_sta_max_num) { + /* Expire oldest entry to make room for a new one */ + sta_track_expire(iface, 1); + } + + wpa_printf(MSG_MSGDUMP, "%s: Add STA tracking entry for " + MACSTR, iface->bss[0]->conf->iface, MAC2STR(addr)); + dl_list_add_tail(&iface->sta_seen, &info->list); + iface->num_sta_seen++; +} + + +struct hostapd_data * +sta_track_seen_on(struct hostapd_iface *iface, const u8 *addr, + const char *ifname) +{ + struct hapd_interfaces *interfaces = iface->interfaces; + size_t i, j; + + for (i = 0; i < interfaces->count; i++) { + struct hostapd_data *hapd = NULL; + + iface = interfaces->iface[i]; + for (j = 0; j < iface->num_bss; j++) { + hapd = iface->bss[j]; + if (os_strcmp(ifname, hapd->conf->iface) == 0) + break; + hapd = NULL; + } + + if (hapd && sta_track_get(iface, addr)) + return hapd; + } + + return NULL; +} + + void handle_probe_req(struct hostapd_data *hapd, const struct ieee80211_mgmt *mgmt, size_t len, int ssi_signal) @@ -548,7 +656,6 @@ void handle_probe_req(struct hostapd_data *hapd, struct ieee802_11_elems elems; const u8 *ie; size_t ie_len; - struct sta_info *sta = NULL; size_t i, resp_len; int noack; enum ssid_match_result res; @@ -556,6 +663,8 @@ void handle_probe_req(struct hostapd_data *hapd, ie = mgmt->u.probe_req.variable; if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)) return; + if (hapd->iconf->track_sta_max_num) + sta_track_add(hapd->iface, mgmt->sa); ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)); for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) @@ -590,7 +699,7 @@ void handle_probe_req(struct hostapd_data *hapd, * is less likely to see them (Probe Request frame sent on a * neighboring, but partially overlapping, channel). */ - if (elems.ds_params && elems.ds_params_len == 1 && + if (elems.ds_params && hapd->iface->current_mode && (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G || hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211B) && @@ -635,8 +744,6 @@ void handle_probe_req(struct hostapd_data *hapd, return; } - sta = ap_get_sta(hapd, mgmt->sa); - #ifdef CONFIG_P2P if ((hapd->conf->p2p & P2P_GROUP_OWNER) && elems.ssid_len == P2P_WILDCARD_SSID_LEN && @@ -649,10 +756,7 @@ void handle_probe_req(struct hostapd_data *hapd, res = ssid_match(hapd, elems.ssid, elems.ssid_len, elems.ssid_list, elems.ssid_list_len); - if (res != NO_SSID_MATCH) { - if (sta) - sta->ssid_probe = &hapd->conf->ssid; - } else { + if (res == NO_SSID_MATCH) { if (!(mgmt->da[0] & 0x01)) { wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for foreign SSID '%s' (DA " MACSTR ")%s", @@ -709,6 +813,18 @@ void handle_probe_req(struct hostapd_data *hapd, /* TODO: verify that supp_rates contains at least one matching rate * with AP configuration */ + if (hapd->conf->no_probe_resp_if_seen_on && + is_multicast_ether_addr(mgmt->da) && + is_multicast_ether_addr(mgmt->bssid) && + sta_track_seen_on(hapd->iface, mgmt->sa, + hapd->conf->no_probe_resp_if_seen_on)) { + wpa_printf(MSG_MSGDUMP, "%s: Ignore Probe Request from " MACSTR + " since STA has been seen on %s", + hapd->conf->iface, MAC2STR(mgmt->sa), + hapd->conf->no_probe_resp_if_seen_on); + return; + } + #ifdef CONFIG_TESTING_OPTIONS if (hapd->iconf->ignore_probe_probability > 0.0 && drand48() < hapd->iconf->ignore_probe_probability) { @@ -719,7 +835,7 @@ void handle_probe_req(struct hostapd_data *hapd, } #endif /* CONFIG_TESTING_OPTIONS */ - resp = hostapd_gen_probe_resp(hapd, sta, mgmt, elems.p2p != NULL, + resp = hostapd_gen_probe_resp(hapd, mgmt, elems.p2p != NULL, &resp_len); if (resp == NULL) return; @@ -774,7 +890,7 @@ static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd, "this"); /* Generate a Probe Response template for the non-P2P case */ - return hostapd_gen_probe_resp(hapd, NULL, NULL, 0, resp_len); + return hostapd_gen_probe_resp(hapd, NULL, 0, resp_len); } #endif /* NEED_AP_MLME */ @@ -804,6 +920,10 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, if (hapd->p2p_beacon_ie) tail_len += wpabuf_len(hapd->p2p_beacon_ie); #endif /* CONFIG_P2P */ +#ifdef CONFIG_FST + if (hapd->iface->fst_ies) + tail_len += wpabuf_len(hapd->iface->fst_ies); +#endif /* CONFIG_FST */ if (hapd->conf->vendor_elements) tail_len += wpabuf_len(hapd->conf->vendor_elements); @@ -833,7 +953,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, host_to_le16(hapd->iconf->beacon_int); /* hardware or low-level driver will setup seq_ctrl and timestamp */ - capab_info = hostapd_own_capab_info(hapd, NULL, 0); + capab_info = hostapd_own_capab_info(hapd); head->u.beacon.capab_info = host_to_le16(capab_info); pos = &head->u.beacon.variable[0]; @@ -902,6 +1022,15 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, tailpos = hostapd_eid_roaming_consortium(hapd, tailpos); tailpos = hostapd_add_csa_elems(hapd, tailpos, tail, &hapd->cs_c_off_beacon); + +#ifdef CONFIG_FST + if (hapd->iface->fst_ies) { + os_memcpy(tailpos, wpabuf_head(hapd->iface->fst_ies), + wpabuf_len(hapd->iface->fst_ies)); + tailpos += wpabuf_len(hapd->iface->fst_ies); + } +#endif /* CONFIG_FST */ + #ifdef CONFIG_IEEE80211AC if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) { tailpos = hostapd_eid_vht_capabilities(hapd, tailpos); @@ -963,8 +1092,14 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, params->basic_rates = hapd->iface->basic_rates; params->ssid = hapd->conf->ssid.ssid; params->ssid_len = hapd->conf->ssid.ssid_len; - params->pairwise_ciphers = hapd->conf->wpa_pairwise | - hapd->conf->rsn_pairwise; + if ((hapd->conf->wpa & (WPA_PROTO_WPA | WPA_PROTO_RSN)) == + (WPA_PROTO_WPA | WPA_PROTO_RSN)) + params->pairwise_ciphers = hapd->conf->wpa_pairwise | + hapd->conf->rsn_pairwise; + else if (hapd->conf->wpa & WPA_PROTO_RSN) + params->pairwise_ciphers = hapd->conf->rsn_pairwise; + else if (hapd->conf->wpa & WPA_PROTO_WPA) + params->pairwise_ciphers = 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; diff --git a/src/ap/beacon.h b/src/ap/beacon.h index 722159a..d98f42e 100644 --- a/src/ap/beacon.h +++ b/src/ap/beacon.h @@ -21,5 +21,10 @@ int ieee802_11_update_beacons(struct hostapd_iface *iface); int ieee802_11_build_ap_params(struct hostapd_data *hapd, struct wpa_driver_ap_params *params); void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params); +void sta_track_add(struct hostapd_iface *iface, const u8 *addr); +void sta_track_expire(struct hostapd_iface *iface, int force); +struct hostapd_data * +sta_track_seen_on(struct hostapd_iface *iface, const u8 *addr, + const char *ifname); #endif /* BEACON_H */ diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c index 41ab988..c98978f 100644 --- a/src/ap/ctrl_iface_ap.c +++ b/src/ap/ctrl_iface_ap.c @@ -12,6 +12,7 @@ #include "common/ieee802_11_defs.h" #include "common/sae.h" #include "eapol_auth/eapol_auth_sm.h" +#include "fst/fst_ctrl_iface.h" #include "hostapd.h" #include "ieee802_1x.h" #include "wpa_auth.h" @@ -153,6 +154,13 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd, } #endif /* CONFIG_SAE */ + if (sta->vlan_id > 0) { + res = os_snprintf(buf + len, buflen - len, "vlan_id=%d\n", + sta->vlan_id); + if (!os_snprintf_error(buflen - len, res)) + len += res; + } + return len; } @@ -199,7 +207,10 @@ int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr, return -1; } - return hostapd_ctrl_iface_sta_mib(hapd, sta, buf, buflen); + ret = hostapd_ctrl_iface_sta_mib(hapd, sta, buf, buflen); + ret += fst_ctrl_iface_mb_info(addr, buf + ret, buflen - ret); + + return ret; } diff --git a/src/ap/dfs.c b/src/ap/dfs.c index da6fd46..715f19b 100644 --- a/src/ap/dfs.c +++ b/src/ap/dfs.c @@ -122,6 +122,20 @@ static int dfs_is_chan_allowed(struct hostapd_channel_data *chan, int n_chans) } +static struct hostapd_channel_data * +dfs_get_chan_data(struct hostapd_hw_modes *mode, int freq, int first_chan_idx) +{ + int i; + + for (i = first_chan_idx; i < mode->num_channels; i++) { + if (mode->channels[i].freq == freq) + return &mode->channels[i]; + } + + return NULL; +} + + static int dfs_chan_range_available(struct hostapd_hw_modes *mode, int first_chan_idx, int num_chans, int skip_radar) @@ -129,15 +143,15 @@ static int dfs_chan_range_available(struct hostapd_hw_modes *mode, struct hostapd_channel_data *first_chan, *chan; int i; - if (first_chan_idx + num_chans >= mode->num_channels) + if (first_chan_idx + num_chans > mode->num_channels) return 0; first_chan = &mode->channels[first_chan_idx]; for (i = 0; i < num_chans; i++) { - chan = &mode->channels[first_chan_idx + i]; - - if (first_chan->freq + i * 20 != chan->freq) + chan = dfs_get_chan_data(mode, first_chan->freq + i * 20, + first_chan_idx); + if (!chan) return 0; if (!dfs_channel_available(chan, skip_radar)) @@ -151,16 +165,10 @@ static int dfs_chan_range_available(struct hostapd_hw_modes *mode, static int is_in_chanlist(struct hostapd_iface *iface, struct hostapd_channel_data *chan) { - int *entry; - - if (!iface->conf->chanlist) + if (!iface->conf->acs_ch_list.num) return 1; - for (entry = iface->conf->chanlist; *entry != -1; entry++) { - if (*entry == chan->chan) - return 1; - } - return 0; + return freq_range_list_includes(&iface->conf->acs_ch_list, chan->chan); } diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c index a0adc67..ca8b75c 100644 --- a/src/ap/drv_callbacks.c +++ b/src/ap/drv_callbacks.c @@ -18,6 +18,7 @@ #include "crypto/random.h" #include "p2p/p2p.h" #include "wps/wps.h" +#include "fst/fst.h" #include "wnm_ap.h" #include "hostapd.h" #include "ieee802_11.h" @@ -42,10 +43,10 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, struct ieee802_11_elems elems; const u8 *ie; size_t ielen; -#ifdef CONFIG_IEEE80211R +#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) u8 buf[sizeof(struct ieee80211_mgmt) + 1024]; u8 *p = buf; -#endif /* CONFIG_IEEE80211R */ +#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */ u16 reason = WLAN_REASON_UNSPECIFIED; u16 status = WLAN_STATUS_SUCCESS; const u8 *p2p_dev_addr = NULL; @@ -58,8 +59,8 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, * running, so better make sure we stop processing such an * event here. */ - wpa_printf(MSG_DEBUG, "hostapd_notif_assoc: Skip event with " - "no address"); + wpa_printf(MSG_DEBUG, + "hostapd_notif_assoc: Skip event with no address"); return -1; } random_add_randomness(addr, ETH_ALEN); @@ -89,8 +90,8 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, } else { ie = NULL; ielen = 0; - wpa_printf(MSG_DEBUG, "STA did not include WPS/RSN/WPA IE in " - "(Re)AssocReq"); + wpa_printf(MSG_DEBUG, + "STA did not include WPS/RSN/WPA IE in (Re)AssocReq"); } sta = ap_get_sta(hapd, addr); @@ -126,8 +127,6 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, #ifdef CONFIG_IEEE80211N #ifdef NEED_AP_MLME if (elems.ht_capabilities && - elems.ht_capabilities_len >= - sizeof(struct ieee80211_ht_capabilities) && (hapd->iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) { struct ieee80211_ht_capabilities *ht_cap = @@ -157,13 +156,20 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, sta->hs20_ie = NULL; #endif /* CONFIG_HS20 */ +#ifdef CONFIG_FST + wpabuf_free(sta->mb_ies); + if (hapd->iface->fst) + sta->mb_ies = mb_ies_by_info(&elems.mb_ies); + else + sta->mb_ies = NULL; +#endif /* CONFIG_FST */ + 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 " - "Request - possible WPS use"); + wpa_printf(MSG_DEBUG, + "STA did not include WPA/RSN IE in (Re)Association Request - possible WPS use"); sta->flags |= WLAN_STA_MAYBE_WPS; goto skip_wpa_check; } @@ -176,13 +182,14 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, 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"); + wpa_printf(MSG_DEBUG, + "WPS: STA supports WPS 2.0"); sta->flags |= WLAN_STA_WPS2; } wpabuf_free(wps); @@ -196,16 +203,17 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, sta->addr, p2p_dev_addr); if (sta->wpa_sm == NULL) { - wpa_printf(MSG_ERROR, "Failed to initialize WPA state " - "machine"); + wpa_printf(MSG_ERROR, + "Failed to initialize WPA state machine"); return -1; } res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, ie, ielen, elems.mdie, elems.mdie_len); if (res != WPA_IE_OK) { - wpa_printf(MSG_DEBUG, "WPA/RSN information element " - "rejected? (res %u)", res); + wpa_printf(MSG_DEBUG, + "WPA/RSN information element rejected? (res %u)", + res); wpa_hexdump(MSG_DEBUG, "IE", ie, ielen); if (res == WPA_INVALID_GROUP) { reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID; @@ -248,14 +256,12 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, if (sta->sa_query_count == 0) ap_sta_start_sa_query(hapd, sta); -#ifdef CONFIG_IEEE80211R status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY; p = hostapd_eid_assoc_comeback_time(hapd, sta, p); hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf); -#endif /* CONFIG_IEEE80211R */ return 0; } @@ -283,6 +289,7 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, } else if (hapd->conf->wps_state) { #ifdef CONFIG_WPS struct wpabuf *wps; + if (req_ies) wps = ieee802_11_vendor_ie_concat(req_ies, req_ies_len, WPS_IE_VENDOR_TYPE); @@ -299,8 +306,8 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, if (wps) { sta->flags |= WLAN_STA_WPS; if (wps_is_20(wps)) { - wpa_printf(MSG_DEBUG, "WPS: STA supports " - "WPS 2.0"); + wpa_printf(MSG_DEBUG, + "WPS: STA supports WPS 2.0"); sta->flags |= WLAN_STA_WPS2; } } else @@ -322,8 +329,8 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr, NULL); if (sta->wpa_sm == NULL) { - wpa_printf(MSG_WARNING, "Failed to initialize WPA " - "state machine"); + wpa_printf(MSG_WARNING, + "Failed to initialize WPA state machine"); return WLAN_STATUS_UNSPECIFIED_FAILURE; } if (wpa_validate_osen(hapd->wpa_auth, sta->wpa_sm, @@ -395,8 +402,8 @@ void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr) * was running, so better make sure we stop processing such an * event here. */ - wpa_printf(MSG_DEBUG, "hostapd_notif_disassoc: Skip event " - "with no address"); + wpa_printf(MSG_DEBUG, + "hostapd_notif_disassoc: Skip event with no address"); return; } @@ -405,8 +412,9 @@ void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr) sta = ap_get_sta(hapd, addr); if (sta == NULL) { - wpa_printf(MSG_DEBUG, "Disassociation notification for " - "unknown STA " MACSTR, MAC2STR(addr)); + wpa_printf(MSG_DEBUG, + "Disassociation notification for unknown STA " + MACSTR, MAC2STR(addr)); return; } @@ -427,8 +435,8 @@ void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr) return; hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, "disconnected due to excessive " - "missing ACKs"); + HOSTAPD_LEVEL_INFO, + "disconnected due to excessive missing ACKs"); hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_DISASSOC_LOW_ACK); if (sta) ap_sta_disassociate(hapd, sta, WLAN_REASON_DISASSOC_LOW_ACK); @@ -452,8 +460,8 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, channel = hostapd_hw_get_channel(hapd, freq); if (!channel) { hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_WARNING, "driver switched to " - "bad channel!"); + HOSTAPD_LEVEL_WARNING, + "driver switched to bad channel!"); return; } @@ -532,10 +540,9 @@ void hostapd_event_connect_failed_reason(struct hostapd_data *hapd, #ifdef CONFIG_ACS static void hostapd_acs_channel_selected(struct hostapd_data *hapd, - u8 pri_channel, u8 sec_channel) + struct acs_selected_channels *acs_res) { - int channel; - int ret; + int ret, i; if (hapd->iconf->channel) { wpa_printf(MSG_INFO, "ACS: Channel was already set to %d", @@ -543,29 +550,73 @@ static void hostapd_acs_channel_selected(struct hostapd_data *hapd, return; } - hapd->iface->freq = hostapd_hw_get_freq(hapd, pri_channel); + if (!hapd->iface->current_mode) { + for (i = 0; i < hapd->iface->num_hw_features; i++) { + struct hostapd_hw_modes *mode = + &hapd->iface->hw_features[i]; - channel = pri_channel; - if (!channel) { + if (mode->mode == acs_res->hw_mode) { + hapd->iface->current_mode = mode; + break; + } + } + if (!hapd->iface->current_mode) { + hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_WARNING, + "driver selected to bad hw_mode"); + return; + } + } + + hapd->iface->freq = hostapd_hw_get_freq(hapd, acs_res->pri_channel); + + if (!acs_res->pri_channel) { hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_WARNING, "driver switched to bad channel"); return; } - hapd->iconf->channel = channel; + hapd->iconf->channel = acs_res->pri_channel; + hapd->iconf->acs = 1; - if (sec_channel == 0) + if (acs_res->sec_channel == 0) hapd->iconf->secondary_channel = 0; - else if (sec_channel < pri_channel) + else if (acs_res->sec_channel < acs_res->pri_channel) hapd->iconf->secondary_channel = -1; - else if (sec_channel > pri_channel) + else if (acs_res->sec_channel > acs_res->pri_channel) hapd->iconf->secondary_channel = 1; else { wpa_printf(MSG_ERROR, "Invalid secondary channel!"); return; } + if (hapd->iface->conf->ieee80211ac) { + /* set defaults for backwards compatibility */ + hapd->iconf->vht_oper_centr_freq_seg1_idx = 0; + hapd->iconf->vht_oper_centr_freq_seg0_idx = 0; + hapd->iconf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT; + if (acs_res->ch_width == 80) { + hapd->iconf->vht_oper_centr_freq_seg0_idx = + acs_res->vht_seg0_center_ch; + hapd->iconf->vht_oper_chwidth = VHT_CHANWIDTH_80MHZ; + } else if (acs_res->ch_width == 160) { + if (acs_res->vht_seg1_center_ch == 0) { + hapd->iconf->vht_oper_centr_freq_seg0_idx = + acs_res->vht_seg0_center_ch; + hapd->iconf->vht_oper_chwidth = + VHT_CHANWIDTH_160MHZ; + } else { + hapd->iconf->vht_oper_centr_freq_seg0_idx = + acs_res->vht_seg0_center_ch; + hapd->iconf->vht_oper_centr_freq_seg1_idx = + acs_res->vht_seg1_center_ch; + hapd->iconf->vht_oper_chwidth = + VHT_CHANWIDTH_80P80MHZ; + } + } + } + ret = hostapd_acs_completed(hapd->iface, 0); if (ret) { wpa_printf(MSG_ERROR, @@ -647,8 +698,8 @@ static void hostapd_notif_auth(struct hostapd_data *hapd, sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr, NULL); if (sta->wpa_sm == NULL) { - wpa_printf(MSG_DEBUG, "FT: Failed to initialize WPA " - "state machine"); + wpa_printf(MSG_DEBUG, + "FT: Failed to initialize WPA state machine"); status = WLAN_STATUS_UNSPECIFIED_FAILURE; goto fail; } @@ -683,7 +734,7 @@ static void hostapd_action_rx(struct hostapd_data *hapd, if (WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION) return; /* handled by the driver */ - wpa_printf(MSG_DEBUG, "RX_ACTION cat %d action plen %d", + wpa_printf(MSG_DEBUG, "RX_ACTION cat %d action plen %d", mgmt->u.action.category, (int) plen); sta = ap_get_sta(hapd, mgmt->sa); @@ -694,6 +745,7 @@ static void hostapd_action_rx(struct hostapd_data *hapd, #ifdef CONFIG_IEEE80211R if (mgmt->u.action.category == WLAN_ACTION_FT) { const u8 *payload = drv_mgmt->frame + 24 + 1; + wpa_ft_action_rx(sta->wpa_sm, payload, plen); } #endif /* CONFIG_IEEE80211R */ @@ -710,6 +762,13 @@ static void hostapd_action_rx(struct hostapd_data *hapd, ieee802_11_rx_wnm_action_ap(hapd, mgmt, drv_mgmt->frame_len); } #endif /* CONFIG_WNM */ +#ifdef CONFIG_FST + if (mgmt->u.action.category == WLAN_ACTION_FST && hapd->iface->fst) { + fst_rx_action(hapd->iface->fst, mgmt, drv_mgmt->frame_len); + return; + } +#endif /* CONFIG_FST */ + } @@ -761,6 +820,7 @@ static int hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt) if (hapd->ext_mgmt_frame_handling) { size_t hex_len = 2 * rx_mgmt->frame_len + 1; char *hex = os_malloc(hex_len); + if (hex) { wpa_snprintf_hex(hex, hex_len, rx_mgmt->frame, rx_mgmt->frame_len); @@ -778,8 +838,7 @@ static int hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt) hapd = get_hapd_bssid(iface, bssid); if (hapd == NULL) { - u16 fc; - fc = le_to_host16(hdr->frame_control); + u16 fc = le_to_host16(hdr->frame_control); /* * Drop frames to unknown BSSIDs except for Beacon frames which @@ -798,6 +857,7 @@ static int hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt) if (hapd == HAPD_BROADCAST) { size_t i; + ret = 0; for (i = 0; i < iface->num_bss; i++) { /* if bss is set, driver will call this function for @@ -824,6 +884,7 @@ static void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf, size_t len, u16 stype, int ok) { struct ieee80211_hdr *hdr; + hdr = (struct ieee80211_hdr *) buf; hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len)); if (hapd == NULL || hapd == HAPD_BROADCAST) @@ -837,6 +898,7 @@ static void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf, static int hostapd_event_new_sta(struct hostapd_data *hapd, const u8 *addr) { struct sta_info *sta = ap_get_sta(hapd, addr); + if (sta) return 0; @@ -863,11 +925,10 @@ static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src, size_t j; for (j = 0; j < iface->num_bss; j++) { - if ((sta = ap_get_sta(iface->bss[j], src))) { - if (sta->flags & WLAN_STA_ASSOC) { - hapd = iface->bss[j]; - break; - } + sta = ap_get_sta(iface->bss[j], src); + if (sta && sta->flags & WLAN_STA_ASSOC) { + hapd = iface->bss[j]; + break; } } @@ -927,7 +988,8 @@ static void hostapd_single_channel_get_survey(struct hostapd_iface *iface, if (!chan || chan->flag & HOSTAPD_CHAN_DISABLED) return; - wpa_printf(MSG_DEBUG, "Single Channel Survey: (freq=%d channel_time=%ld channel_time_busy=%ld)", + wpa_printf(MSG_DEBUG, + "Single Channel Survey: (freq=%d channel_time=%ld channel_time_busy=%ld)", survey->freq, (unsigned long int) survey->channel_time, (unsigned long int) survey->channel_time_busy); @@ -1061,6 +1123,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, 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 && @@ -1248,9 +1311,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, break; #ifdef CONFIG_ACS case EVENT_ACS_CHANNEL_SELECTED: - hostapd_acs_channel_selected( - hapd, data->acs_selected_channels.pri_channel, - data->acs_selected_channels.sec_channel); + hostapd_acs_channel_selected(hapd, + &data->acs_selected_channels); break; #endif /* CONFIG_ACS */ default: diff --git a/src/ap/eap_user_db.c b/src/ap/eap_user_db.c index 559d77f..082d0f5 100644 --- a/src/ap/eap_user_db.c +++ b/src/ap/eap_user_db.c @@ -138,8 +138,12 @@ eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity, char id_str[256], cmd[300]; size_t i; - if (identity_len >= sizeof(id_str)) + if (identity_len >= sizeof(id_str)) { + wpa_printf(MSG_DEBUG, "%s: identity len too big: %d >= %d", + __func__, (int) identity_len, + (int) (sizeof(id_str))); return NULL; + } os_memcpy(id_str, identity, identity_len); id_str[identity_len] = '\0'; for (i = 0; i < identity_len; i++) { @@ -182,7 +186,9 @@ eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity, wpa_printf(MSG_DEBUG, "DB: %s", cmd); if (sqlite3_exec(db, cmd, get_user_cb, &hapd->tmp_eap_user, NULL) != SQLITE_OK) { - wpa_printf(MSG_DEBUG, "DB: Failed to complete SQL operation"); + wpa_printf(MSG_DEBUG, + "DB: Failed to complete SQL operation: %s db: %s", + sqlite3_errmsg(db), hapd->conf->eap_user_sqlite); } else if (hapd->tmp_eap_user.next) user = &hapd->tmp_eap_user; @@ -192,8 +198,10 @@ eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity, wpa_printf(MSG_DEBUG, "DB: %s", cmd); if (sqlite3_exec(db, cmd, get_wildcard_cb, &hapd->tmp_eap_user, NULL) != SQLITE_OK) { - wpa_printf(MSG_DEBUG, "DB: Failed to complete SQL " - "operation"); + wpa_printf(MSG_DEBUG, + "DB: Failed to complete SQL operation: %s db: %s", + sqlite3_errmsg(db), + hapd->conf->eap_user_sqlite); } else if (hapd->tmp_eap_user.next) { user = &hapd->tmp_eap_user; os_free(user->identity); diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index 3e4e16b..c09c17a 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -17,6 +17,7 @@ #include "eap_server/tncs.h" #include "eapol_auth/eapol_auth_sm.h" #include "eapol_auth/eapol_auth_sm_i.h" +#include "fst/fst.h" #include "hostapd.h" #include "authsrv.h" #include "sta_info.h" @@ -179,6 +180,7 @@ int hostapd_reload_config(struct hostapd_iface *iface) hapd = iface->bss[j]; hapd->iconf = newconf; hapd->iconf->channel = oldconf->channel; + hapd->iconf->acs = oldconf->acs; hapd->iconf->secondary_channel = oldconf->secondary_channel; hapd->iconf->ieee80211n = oldconf->ieee80211n; hapd->iconf->ieee80211ac = oldconf->ieee80211ac; @@ -259,6 +261,7 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd) { os_free(hapd->probereq_cb); hapd->probereq_cb = NULL; + hapd->num_probereq_cb = 0; #ifdef CONFIG_P2P wpabuf_free(hapd->p2p_beacon_ie); @@ -353,6 +356,22 @@ static void hostapd_cleanup(struct hostapd_data *hapd) } +static void sta_track_deinit(struct hostapd_iface *iface) +{ + struct hostapd_sta_info *info; + + if (!iface->num_sta_seen) + return; + + while ((info = dl_list_first(&iface->sta_seen, struct hostapd_sta_info, + list))) { + dl_list_del(&info->list); + iface->num_sta_seen--; + os_free(info); + } +} + + static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface) { wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface); @@ -368,6 +387,7 @@ static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface) os_free(iface->basic_rates); iface->basic_rates = NULL; ap_list_deinit(iface); + sta_track_deinit(iface); } @@ -861,7 +881,7 @@ hostapd_das_disconnect(void *ctx, struct radius_das_attrs *attr) static int hostapd_setup_bss(struct hostapd_data *hapd, int first) { struct hostapd_bss_config *conf = hapd->conf; - u8 ssid[HOSTAPD_MAX_SSID_LEN + 1]; + u8 ssid[SSID_MAX_LEN + 1]; int ssid_len, set_ssid; char force_ifname[IFNAMSIZ]; u8 if_addr[ETH_ALEN]; @@ -1363,6 +1383,132 @@ fail: } +#ifdef CONFIG_FST + +static const u8 * fst_hostapd_get_bssid_cb(void *ctx) +{ + struct hostapd_data *hapd = ctx; + + return hapd->own_addr; +} + + +static void fst_hostapd_get_channel_info_cb(void *ctx, + enum hostapd_hw_mode *hw_mode, + u8 *channel) +{ + struct hostapd_data *hapd = ctx; + + *hw_mode = ieee80211_freq_to_chan(hapd->iface->freq, channel); +} + + +static void fst_hostapd_set_ies_cb(void *ctx, const struct wpabuf *fst_ies) +{ + struct hostapd_data *hapd = ctx; + + if (hapd->iface->fst_ies != fst_ies) { + hapd->iface->fst_ies = fst_ies; + if (ieee802_11_set_beacon(hapd)) + wpa_printf(MSG_WARNING, "FST: Cannot set beacon"); + } +} + + +static int fst_hostapd_send_action_cb(void *ctx, const u8 *da, + struct wpabuf *buf) +{ + struct hostapd_data *hapd = ctx; + + return hostapd_drv_send_action(hapd, hapd->iface->freq, 0, da, + wpabuf_head(buf), wpabuf_len(buf)); +} + + +static const struct wpabuf * fst_hostapd_get_mb_ie_cb(void *ctx, const u8 *addr) +{ + struct hostapd_data *hapd = ctx; + struct sta_info *sta = ap_get_sta(hapd, addr); + + return sta ? sta->mb_ies : NULL; +} + + +static void fst_hostapd_update_mb_ie_cb(void *ctx, const u8 *addr, + const u8 *buf, size_t size) +{ + struct hostapd_data *hapd = ctx; + struct sta_info *sta = ap_get_sta(hapd, addr); + + if (sta) { + struct mb_ies_info info; + + if (!mb_ies_info_by_ies(&info, buf, size)) { + wpabuf_free(sta->mb_ies); + sta->mb_ies = mb_ies_by_info(&info); + } + } +} + + +static const u8 * fst_hostapd_get_sta(struct fst_get_peer_ctx **get_ctx, + Boolean mb_only) +{ + struct sta_info *s = (struct sta_info *) *get_ctx; + + if (mb_only) { + for (; s && !s->mb_ies; s = s->next) + ; + } + + if (s) { + *get_ctx = (struct fst_get_peer_ctx *) s->next; + + return s->addr; + } + + *get_ctx = NULL; + return NULL; +} + + +static const u8 * fst_hostapd_get_peer_first(void *ctx, + struct fst_get_peer_ctx **get_ctx, + Boolean mb_only) +{ + struct hostapd_data *hapd = ctx; + + *get_ctx = (struct fst_get_peer_ctx *) hapd->sta_list; + + return fst_hostapd_get_sta(get_ctx, mb_only); +} + + +static const u8 * fst_hostapd_get_peer_next(void *ctx, + struct fst_get_peer_ctx **get_ctx, + Boolean mb_only) +{ + return fst_hostapd_get_sta(get_ctx, mb_only); +} + + +void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd, + struct fst_wpa_obj *iface_obj) +{ + iface_obj->ctx = hapd; + iface_obj->get_bssid = fst_hostapd_get_bssid_cb; + iface_obj->get_channel_info = fst_hostapd_get_channel_info_cb; + iface_obj->set_ies = fst_hostapd_set_ies_cb; + iface_obj->send_action = fst_hostapd_send_action_cb; + iface_obj->get_mb_ie = fst_hostapd_get_mb_ie_cb; + iface_obj->update_mb_ie = fst_hostapd_update_mb_ie_cb; + iface_obj->get_peer_first = fst_hostapd_get_peer_first; + iface_obj->get_peer_next = fst_hostapd_get_peer_next; +} + +#endif /* CONFIG_FST */ + + /** * hostapd_setup_interface_complete - Complete interface setup * @@ -1495,6 +1641,7 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err) hostapd_tx_queue_params(iface); ap_list_init(iface); + dl_list_init(&iface->sta_seen); hostapd_set_acl(hapd); @@ -1528,6 +1675,22 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err) #ifdef NEED_AP_MLME dfs_offload: #endif /* NEED_AP_MLME */ + +#ifdef CONFIG_FST + if (hapd->iconf->fst_cfg.group_id[0]) { + struct fst_wpa_obj iface_obj; + + fst_hostapd_fill_iface_obj(hapd, &iface_obj); + iface->fst = fst_attach(hapd->conf->iface, hapd->own_addr, + &iface_obj, &hapd->iconf->fst_cfg); + if (!iface->fst) { + wpa_printf(MSG_ERROR, "Could not attach to FST %s", + hapd->iconf->fst_cfg.group_id); + goto fail; + } + } +#endif /* CONFIG_FST */ + hostapd_set_state(iface, HAPD_IFACE_ENABLED); wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_ENABLED); if (hapd->setup_complete_cb) @@ -1544,6 +1707,12 @@ fail: wpa_printf(MSG_ERROR, "Interface initialization failed"); hostapd_set_state(iface, HAPD_IFACE_DISABLED); wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED); +#ifdef CONFIG_FST + if (iface->fst) { + fst_detach(iface->fst); + iface->fst = NULL; + } +#endif /* CONFIG_FST */ if (iface->interfaces && iface->interfaces->terminate_on_error) eloop_terminate(); return -1; @@ -1643,6 +1812,13 @@ void hostapd_interface_deinit(struct hostapd_iface *iface) eloop_cancel_timeout(channel_list_update_timeout, iface, NULL); iface->wait_channel_update = 0; +#ifdef CONFIG_FST + if (iface->fst) { + fst_detach(iface->fst); + iface->fst = NULL; + } +#endif /* CONFIG_FST */ + for (j = iface->num_bss - 1; j >= 0; j--) hostapd_bss_deinit(iface->bss[j]); } @@ -2029,7 +2205,7 @@ hostapd_iface_alloc(struct hapd_interfaces *interfaces) static struct hostapd_config * hostapd_config_alloc(struct hapd_interfaces *interfaces, const char *ifname, - const char *ctrl_iface) + const char *ctrl_iface, const char *driver) { struct hostapd_bss_config *bss; struct hostapd_config *conf; @@ -2042,6 +2218,21 @@ hostapd_config_alloc(struct hapd_interfaces *interfaces, const char *ifname, return NULL; } + if (driver) { + int j; + + for (j = 0; wpa_drivers[j]; j++) { + if (os_strcmp(driver, wpa_drivers[j]->name) == 0) { + conf->driver = wpa_drivers[j]; + goto skip; + } + } + + wpa_printf(MSG_ERROR, + "Invalid/unknown driver '%s' - registering the default driver", + driver); + } + conf->driver = wpa_drivers[0]; if (conf->driver == NULL) { wpa_printf(MSG_ERROR, "No driver wrappers registered!"); @@ -2049,6 +2240,7 @@ hostapd_config_alloc(struct hapd_interfaces *interfaces, const char *ifname, return NULL; } +skip: bss = conf->last_bss = conf->bss[0]; os_strlcpy(bss->iface, ifname, sizeof(bss->iface)); @@ -2209,8 +2401,14 @@ int hostapd_add_iface(struct hapd_interfaces *interfaces, char *buf) if (conf && conf->bss) os_strlcpy(conf->bss[0]->iface, buf, sizeof(conf->bss[0]->iface)); - } else - conf = hostapd_config_alloc(interfaces, buf, ptr); + } else { + char *driver = os_strchr(ptr, ' '); + + if (driver) + *driver++ = '\0'; + conf = hostapd_config_alloc(interfaces, buf, ptr, driver); + } + if (conf == NULL || conf->bss == NULL) { wpa_printf(MSG_ERROR, "%s: Failed to allocate memory " "for configuration", __func__); @@ -2722,4 +2920,43 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface, hostapd_enable_iface(iface); } + +struct hostapd_data * hostapd_get_iface(struct hapd_interfaces *interfaces, + const char *ifname) +{ + size_t i, j; + + for (i = 0; i < interfaces->count; i++) { + struct hostapd_iface *iface = interfaces->iface[i]; + + for (j = 0; j < iface->num_bss; j++) { + struct hostapd_data *hapd = iface->bss[j]; + + if (os_strcmp(ifname, hapd->conf->iface) == 0) + return hapd; + } + } + + return NULL; +} + #endif /* NEED_AP_MLME */ + + +void hostapd_periodic_iface(struct hostapd_iface *iface) +{ + size_t i; + + ap_list_timer(iface); + + for (i = 0; i < iface->num_bss; i++) { + struct hostapd_data *hapd = iface->bss[i]; + + if (!hapd->started) + continue; + +#ifndef CONFIG_NO_RADIUS + hostapd_acl_expire(hapd); +#endif /* CONFIG_NO_RADIUS */ + } +} diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index 75cc24e..dcf51f0 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -41,6 +41,7 @@ struct hapd_interfaces { size_t count; int global_ctrl_sock; + struct wpa_ctrl_dst *global_ctrl_dst; char *global_iface_path; char *global_iface_name; #ifndef CONFIG_NATIVE_WINDOWS @@ -49,6 +50,9 @@ struct hapd_interfaces { struct hostapd_iface **iface; size_t terminate_on_error; +#ifndef CONFIG_NO_VLAN + struct dynamic_iface *vlan_priv; +#endif /* CONFIG_NO_VLAN */ }; enum hostapd_chan_status { @@ -265,6 +269,7 @@ struct hostapd_data { /** Key used for generating SAE anti-clogging tokens */ u8 sae_token_key[8]; struct os_reltime last_sae_token_key_update; + int dot11RSNASAERetransPeriod; /* msec */ #endif /* CONFIG_SAE */ #ifdef CONFIG_TESTING_OPTIONS @@ -276,6 +281,12 @@ struct hostapd_data { }; +struct hostapd_sta_info { + struct dl_list list; + u8 addr[ETH_ALEN]; + struct os_reltime last_seen; +}; + /** * struct hostapd_iface - hostapd per-interface data structure */ @@ -305,6 +316,10 @@ struct hostapd_iface { unsigned int wait_channel_update:1; unsigned int cac_started:1; +#ifdef CONFIG_FST + struct fst_iface *fst; + const struct wpabuf *fst_ies; +#endif /* CONFIG_FST */ /* * When set, indicates that the driver will handle the AP @@ -400,6 +415,9 @@ struct hostapd_iface { void (*scan_cb)(struct hostapd_iface *iface); int num_ht40_scan_tries; + + struct dl_list sta_seen; /* struct hostapd_sta_info */ + unsigned int num_sta_seen; }; /* hostapd.c */ @@ -437,6 +455,7 @@ void hostapd_switch_channel_fallback(struct hostapd_iface *iface, const struct hostapd_freq_params *freq_params); void hostapd_cleanup_cs_params(struct hostapd_data *hapd); +void hostapd_periodic_iface(struct hostapd_iface *iface); /* utils.c */ int hostapd_register_probereq_cb(struct hostapd_data *hapd, @@ -464,4 +483,12 @@ const struct hostapd_eap_user * hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity, size_t identity_len, int phase2); +struct hostapd_data * hostapd_get_iface(struct hapd_interfaces *interfaces, + const char *ifname); + +#ifdef CONFIG_FST +void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd, + struct fst_wpa_obj *iface_obj); +#endif /* CONFIG_FST */ + #endif /* HOSTAPD_H */ diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c index 05431d3..fc8786d 100644 --- a/src/ap/hw_features.c +++ b/src/ap/hw_features.c @@ -260,8 +260,14 @@ static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface, res = check_40mhz_5g(iface->current_mode, scan_res, pri_chan, sec_chan); - if (res == 2) - ieee80211n_switch_pri_sec(iface); + if (res == 2) { + if (iface->conf->no_pri_sec_switch) { + wpa_printf(MSG_DEBUG, + "Cannot switch PRI/SEC channels due to local constraint"); + } else { + ieee80211n_switch_pri_sec(iface); + } + } return !!res; } @@ -347,8 +353,13 @@ static void ieee80211n_scan_channels_2g4(struct hostapd_iface *iface, sec_freq = pri_freq + 20; else sec_freq = pri_freq - 20; - affected_start = (pri_freq + sec_freq) / 2 - 25; - affected_end = (pri_freq + sec_freq) / 2 + 25; + /* + * Note: Need to find the PRI channel also in cases where the affected + * channel is the SEC channel of a 40 MHz BSS, so need to include the + * scanning coverage here to be 40 MHz from the center frequency. + */ + affected_start = (pri_freq + sec_freq) / 2 - 40; + affected_end = (pri_freq + sec_freq) / 2 + 40; wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz", affected_start, affected_end); @@ -510,7 +521,11 @@ static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface) return 0; } - if ((conf & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) && + /* + * Driver ACS chosen channel may not be HT40 due to internal driver + * restrictions. + */ + if (!iface->conf->acs && (conf & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) && !(hw & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) { wpa_printf(MSG_ERROR, "Driver does not support configured " "HT capability [HT40*]"); @@ -717,6 +732,15 @@ int hostapd_check_ht_capab(struct hostapd_iface *iface) int ret; if (!iface->conf->ieee80211n) return 0; + + if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211B && + iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G && + (iface->conf->ht_capab & HT_CAP_INFO_DSSS_CCK40MHZ)) { + wpa_printf(MSG_DEBUG, + "Disable HT capability [DSSS_CCK-40] on 5 GHz band"); + iface->conf->ht_capab &= ~HT_CAP_INFO_DSSS_CCK40MHZ; + } + if (!ieee80211n_supported_ht_capab(iface)) return -1; #ifdef CONFIG_IEEE80211AC @@ -740,6 +764,9 @@ static int hostapd_is_usable_chan(struct hostapd_iface *iface, int i; struct hostapd_channel_data *chan; + if (!iface->current_mode) + return 0; + for (i = 0; i < iface->current_mode->num_channels; i++) { chan = &iface->current_mode->channels[i]; if (chan->chan != channel) @@ -801,6 +828,12 @@ hostapd_check_chans(struct hostapd_iface *iface) static void hostapd_notify_bad_chans(struct hostapd_iface *iface) { + if (!iface->current_mode) { + hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_WARNING, + "Hardware does not support configured mode"); + return; + } hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_WARNING, @@ -891,14 +924,18 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface) } if (iface->current_mode == NULL) { - wpa_printf(MSG_ERROR, "Hardware does not support configured " - "mode"); - hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_WARNING, - "Hardware does not support configured mode " - "(%d) (hw_mode in hostapd.conf)", - (int) iface->conf->hw_mode); - return -2; + if (!(iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) || + !(iface->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY)) + { + wpa_printf(MSG_ERROR, + "Hardware does not support configured mode"); + hostapd_logger(iface->bss[0], NULL, + HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_WARNING, + "Hardware does not support configured mode (%d) (hw_mode in hostapd.conf)", + (int) iface->conf->hw_mode); + return -2; + } } switch (hostapd_check_chans(iface)) { diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h index 0f67ab8..ca7f22b 100644 --- a/src/ap/hw_features.h +++ b/src/ap/hw_features.h @@ -36,6 +36,11 @@ static inline int hostapd_get_hw_features(struct hostapd_iface *iface) return -1; } +static inline int hostapd_acs_completed(struct hostapd_iface *iface, int err) +{ + return -1; +} + static inline int hostapd_select_hw_mode(struct hostapd_iface *iface) { return -100; diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index 89911b1..7bb18c0 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -23,6 +23,7 @@ #include "radius/radius_client.h" #include "p2p/p2p.h" #include "wps/wps.h" +#include "fst/fst.h" #include "hostapd.h" #include "beacon.h" #include "ieee802_11_auth.h" @@ -38,6 +39,7 @@ #include "p2p_hostapd.h" #include "ap_drv_ops.h" #include "wnm_ap.h" +#include "hw_features.h" #include "ieee802_11.h" #include "dfs.h" @@ -132,8 +134,7 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid) } -u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta, - int probe) +u16 hostapd_own_capab_info(struct hostapd_data *hapd) { int capab = WLAN_CAPABILITY_ESS; int privacy; @@ -166,20 +167,6 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta, privacy = 1; #endif /* CONFIG_HS20 */ - if (sta) { - int policy, def_klen; - if (probe && sta->ssid_probe) { - policy = sta->ssid_probe->security_policy; - def_klen = sta->ssid_probe->wep.default_len; - } else { - policy = sta->ssid->security_policy; - def_klen = sta->ssid->wep.default_len; - } - privacy = policy != SECURITY_PLAINTEXT; - if (policy == SECURITY_IEEE_802_1X && def_klen == 0) - privacy = 0; - } - if (privacy) capab |= WLAN_CAPABILITY_PRIVACY; @@ -206,6 +193,7 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta, } +#ifndef CONFIG_NO_RC4 static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta, u16 auth_transaction, const u8 *challenge, int iswep) @@ -259,6 +247,7 @@ static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta, return 0; } +#endif /* CONFIG_NO_RC4 */ static void send_auth_reply(struct hostapd_data *hapd, @@ -328,7 +317,6 @@ static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid, #ifdef CONFIG_SAE -#define dot11RSNASAERetransPeriod 40 /* msec */ #define dot11RSNASAESync 5 /* attempts */ @@ -511,12 +499,14 @@ static void auth_sae_retransmit_timer(void *eloop_ctx, void *eloop_data) switch (sta->sae->state) { case SAE_COMMITTED: ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0); - eloop_register_timeout(0, dot11RSNASAERetransPeriod * 1000, + eloop_register_timeout(0, + hapd->dot11RSNASAERetransPeriod * 1000, auth_sae_retransmit_timer, hapd, sta); break; case SAE_CONFIRMED: ret = auth_sae_send_confirm(hapd, sta, hapd->own_addr); - eloop_register_timeout(0, dot11RSNASAERetransPeriod * 1000, + eloop_register_timeout(0, + hapd->dot11RSNASAERetransPeriod * 1000, auth_sae_retransmit_timer, hapd, sta); break; default: @@ -542,7 +532,7 @@ static void sae_set_retransmit_timer(struct hostapd_data *hapd, return; eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta); - eloop_register_timeout(0, dot11RSNASAERetransPeriod * 1000, + eloop_register_timeout(0, hapd->dot11RSNASAERetransPeriod * 1000, auth_sae_retransmit_timer, hapd, sta); } @@ -624,7 +614,7 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta, return WLAN_STATUS_SUCCESS; sta->sae->sync++; - ret = auth_sae_send_commit(hapd, sta, bssid, 1); + ret = auth_sae_send_commit(hapd, sta, bssid, 0); if (ret) return ret; @@ -784,6 +774,12 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta, ((const u8 *) mgmt) + len - mgmt->u.auth.variable, &token, &token_len, hapd->conf->sae_groups); + if (resp == SAE_SILENTLY_DISCARD) { + wpa_printf(MSG_DEBUG, + "SAE: Drop commit message from " MACSTR " due to reflection attack", + MAC2STR(sta->addr)); + return; + } if (token && check_sae_token(hapd, sta->addr, token, token_len) < 0) { wpa_printf(MSG_DEBUG, "SAE: Drop commit message with " @@ -934,6 +930,16 @@ static void handle_auth(struct hostapd_data *hapd, challenge ? " challenge" : "", seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : ""); +#ifdef CONFIG_NO_RC4 + if (auth_alg == WLAN_AUTH_SHARED_KEY) { + wpa_printf(MSG_INFO, + "Unsupported authentication algorithm (%d)", + auth_alg); + resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG; + goto fail; + } +#endif /* CONFIG_NO_RC4 */ + if (hapd->tkip_countermeasures) { resp = WLAN_REASON_MICHAEL_MIC_FAILURE; goto fail; @@ -972,6 +978,61 @@ static void handle_auth(struct hostapd_data *hapd, goto fail; } + if (hapd->conf->no_auth_if_seen_on) { + struct hostapd_data *other; + + other = sta_track_seen_on(hapd->iface, mgmt->sa, + hapd->conf->no_auth_if_seen_on); + if (other) { + u8 *pos; + u32 info; + u8 op_class, channel, phytype; + + wpa_printf(MSG_DEBUG, "%s: Reject authentication from " + MACSTR " since STA has been seen on %s", + hapd->conf->iface, MAC2STR(mgmt->sa), + hapd->conf->no_auth_if_seen_on); + + resp = WLAN_STATUS_REJECTED_WITH_SUGGESTED_BSS_TRANSITION; + pos = &resp_ies[0]; + *pos++ = WLAN_EID_NEIGHBOR_REPORT; + *pos++ = 13; + os_memcpy(pos, other->own_addr, ETH_ALEN); + pos += ETH_ALEN; + info = 0; /* TODO: BSSID Information */ + WPA_PUT_LE32(pos, info); + pos += 4; + if (other->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD) + phytype = 8; /* dmg */ + else if (other->iconf->ieee80211ac) + phytype = 9; /* vht */ + else if (other->iconf->ieee80211n) + phytype = 7; /* ht */ + else if (other->iconf->hw_mode == + HOSTAPD_MODE_IEEE80211A) + phytype = 4; /* ofdm */ + else if (other->iconf->hw_mode == + HOSTAPD_MODE_IEEE80211G) + phytype = 6; /* erp */ + else + phytype = 5; /* hrdsss */ + if (ieee80211_freq_to_channel_ext( + hostapd_hw_get_freq(other, + other->iconf->channel), + other->iconf->secondary_channel, + other->iconf->ieee80211ac, + &op_class, &channel) == NUM_HOSTAPD_MODES) { + op_class = 0; + channel = other->iconf->channel; + } + *pos++ = op_class; + *pos++ = channel; + *pos++ = phytype; + resp_ies_len = pos - &resp_ies[0]; + goto fail; + } + } + res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len, &session_timeout, &acct_interim_interval, &vlan_id, @@ -1081,6 +1142,7 @@ static void handle_auth(struct hostapd_data *hapd, sta->auth_alg = WLAN_AUTH_OPEN; mlme_authenticate_indication(hapd, sta); break; +#ifndef CONFIG_NO_RC4 case WLAN_AUTH_SHARED_KEY: resp = auth_shared_key(hapd, sta, auth_transaction, challenge, fc & WLAN_FC_ISWEP); @@ -1094,6 +1156,7 @@ static void handle_auth(struct hostapd_data *hapd, resp_ies_len = 2 + WLAN_AUTH_CHALLENGE_LEN; } break; +#endif /* CONFIG_NO_RC4 */ #ifdef CONFIG_IEEE80211R case WLAN_AUTH_FT: sta->auth_alg = WLAN_AUTH_FT; @@ -1297,8 +1360,7 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, if (resp != WLAN_STATUS_SUCCESS) return resp; #ifdef CONFIG_IEEE80211N - resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities, - elems.ht_capabilities_len); + resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities); if (resp != WLAN_STATUS_SUCCESS) return resp; if (hapd->iconf->ieee80211n && hapd->iconf->require_ht && @@ -1311,14 +1373,15 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, #endif /* CONFIG_IEEE80211N */ #ifdef CONFIG_IEEE80211AC - resp = copy_sta_vht_capab(hapd, sta, elems.vht_capabilities, - elems.vht_capabilities_len); - if (resp != WLAN_STATUS_SUCCESS) - return resp; + if (hapd->iconf->ieee80211ac) { + resp = copy_sta_vht_capab(hapd, sta, elems.vht_capabilities); + if (resp != WLAN_STATUS_SUCCESS) + return resp; - resp = set_sta_vht_opmode(hapd, sta, elems.vht_opmode_notif); - if (resp != WLAN_STATUS_SUCCESS) - return resp; + resp = set_sta_vht_opmode(hapd, sta, elems.vht_opmode_notif); + if (resp != WLAN_STATUS_SUCCESS) + return resp; + } if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht && !(sta->flags & WLAN_STA_VHT)) { @@ -1546,6 +1609,14 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, sta->hs20_ie = NULL; #endif /* CONFIG_HS20 */ +#ifdef CONFIG_FST + wpabuf_free(sta->mb_ies); + if (hapd->iface->fst) + sta->mb_ies = mb_ies_by_info(&elems.mb_ies); + else + sta->mb_ies = NULL; +#endif /* CONFIG_FST */ + return WLAN_STATUS_SUCCESS; } @@ -1594,7 +1665,7 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, send_len = IEEE80211_HDRLEN; send_len += sizeof(reply->u.assoc_resp); reply->u.assoc_resp.capab_info = - host_to_le16(hostapd_own_capab_info(hapd, sta, 0)); + host_to_le16(hostapd_own_capab_info(hapd)); reply->u.assoc_resp.status_code = host_to_le16(status_code); reply->u.assoc_resp.aid = host_to_le16(sta->aid | BIT(14) | BIT(15)); /* Supported rates */ @@ -1634,6 +1705,14 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, if (sta->qos_map_enabled) p = hostapd_eid_qos_map_set(hapd, p); +#ifdef CONFIG_FST + if (hapd->iface->fst_ies) { + os_memcpy(p, wpabuf_head(hapd->iface->fst_ies), + wpabuf_len(hapd->iface->fst_ies)); + p += wpabuf_len(hapd->iface->fst_ies); + } +#endif /* CONFIG_FST */ + #ifdef CONFIG_IEEE80211AC if (hapd->conf->vendor_vht && (sta->flags & WLAN_STA_VENDOR_VHT)) p = hostapd_eid_vendor_vht(hapd, p); @@ -2112,10 +2191,20 @@ static int handle_action(struct hostapd_data *hapd, ieee802_11_rx_wnm_action_ap(hapd, mgmt, len); return 1; #endif /* CONFIG_WNM */ +#ifdef CONFIG_FST + case WLAN_ACTION_FST: + if (hapd->iface->fst) + fst_rx_action(hapd->iface->fst, mgmt, len); + else + wpa_printf(MSG_DEBUG, + "FST: Ignore FST Action frame - no FST attached"); + return 1; +#endif /* CONFIG_FST */ case WLAN_ACTION_PUBLIC: case WLAN_ACTION_PROTECTED_DUAL: #ifdef CONFIG_IEEE80211N - if (mgmt->u.action.u.public_action.action == + if (len >= IEEE80211_HDRLEN + 2 && + mgmt->u.action.u.public_action.action == WLAN_PA_20_40_BSS_COEX) { wpa_printf(MSG_DEBUG, "HT20/40 coex mgmt frame received from STA " @@ -2248,6 +2337,9 @@ int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, return 0; } + if (hapd->iconf->track_sta_max_num) + sta_track_add(hapd->iface, mgmt->sa); + switch (stype) { case WLAN_FC_STYPE_AUTH: wpa_printf(MSG_DEBUG, "mgmt::auth"); @@ -2335,7 +2427,7 @@ static void hostapd_set_wds_encryption(struct hostapd_data *hapd, char *ifname_wds) { int i; - struct hostapd_ssid *ssid = sta->ssid; + struct hostapd_ssid *ssid = &hapd->conf->ssid; if (hapd->conf->ieee802_1x || hapd->conf->wpa) return; @@ -2473,11 +2565,11 @@ static void handle_assoc_cb(struct hostapd_data *hapd, * so bind it to the selected VLAN interface now, since the * interface selection is not going to change anymore. */ - if (ap_sta_bind_vlan(hapd, sta, 0) < 0) + if (ap_sta_bind_vlan(hapd, sta) < 0) return; } else if (sta->vlan_id) { /* VLAN ID already set (e.g., by PMKSA caching), so bind STA */ - if (ap_sta_bind_vlan(hapd, sta, 0) < 0) + if (ap_sta_bind_vlan(hapd, sta) < 0) return; } diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h index 41c27d9..44c1bff 100644 --- a/src/ap/ieee802_11.h +++ b/src/ap/ieee802_11.h @@ -14,6 +14,7 @@ struct hostapd_data; struct sta_info; struct hostapd_frame_info; struct ieee80211_ht_capabilities; +struct ieee80211_vht_capabilities; struct ieee80211_mgmt; int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, @@ -40,8 +41,7 @@ static inline int ieee802_11_get_mib_sta(struct hostapd_data *hapd, return 0; } #endif /* NEED_AP_MLME */ -u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta, - int probe); +u16 hostapd_own_capab_info(struct hostapd_data *hapd); void ap_ht2040_timeout(void *eloop_data, void *user_data); u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid); u8 * hostapd_eid_qos_map_set(struct hostapd_data *hapd, u8 *eid); @@ -62,7 +62,7 @@ void hostapd_get_vht_capab(struct hostapd_data *hapd, struct ieee80211_vht_capabilities *vht_cap, struct ieee80211_vht_capabilities *neg_vht_cap); u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta, - const u8 *ht_capab, size_t ht_capab_len); + const u8 *ht_capab); u16 copy_sta_vendor_vht(struct hostapd_data *hapd, struct sta_info *sta, const u8 *ie, size_t len); @@ -70,7 +70,7 @@ void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta); void ht40_intolerant_add(struct hostapd_iface *iface, struct sta_info *sta); void ht40_intolerant_remove(struct hostapd_iface *iface, struct sta_info *sta); u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta, - const u8 *vht_capab, size_t vht_capab_len); + const u8 *vht_capab); u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta, const u8 *vht_opmode); void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr, diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c index 56c3ce0..531a67d 100644 --- a/src/ap/ieee802_11_auth.c +++ b/src/ap/ieee802_11_auth.c @@ -399,19 +399,15 @@ static void hostapd_acl_expire_queries(struct hostapd_data *hapd, /** * hostapd_acl_expire - ACL cache expiration callback - * @eloop_ctx: struct hostapd_data * - * @timeout_ctx: Not used + * @hapd: struct hostapd_data * */ -static void hostapd_acl_expire(void *eloop_ctx, void *timeout_ctx) +void hostapd_acl_expire(struct hostapd_data *hapd) { - struct hostapd_data *hapd = eloop_ctx; struct os_reltime now; os_get_reltime(&now); hostapd_acl_expire_cache(hapd, &now); hostapd_acl_expire_queries(hapd, &now); - - eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL); } @@ -561,6 +557,19 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req, if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED && !cache->psk) cache->accepted = HOSTAPD_ACL_REJECT; + + if (cache->vlan_id && + !hostapd_vlan_id_valid(hapd->conf->vlan, cache->vlan_id)) { + hostapd_logger(hapd, query->addr, + HOSTAPD_MODULE_RADIUS, + HOSTAPD_LEVEL_INFO, + "Invalid VLAN ID %d received from RADIUS server", + cache->vlan_id); + cache->vlan_id = 0; + } + if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED && + !cache->vlan_id) + cache->accepted = HOSTAPD_ACL_REJECT; } else cache->accepted = HOSTAPD_ACL_REJECT; cache->next = hapd->acl_cache; @@ -602,8 +611,6 @@ int hostapd_acl_init(struct hostapd_data *hapd) if (radius_client_register(hapd->radius, RADIUS_AUTH, hostapd_acl_recv_radius, hapd)) return -1; - - eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL); #endif /* CONFIG_NO_RADIUS */ return 0; @@ -619,8 +626,6 @@ void hostapd_acl_deinit(struct hostapd_data *hapd) struct hostapd_acl_query_data *query, *prev; #ifndef CONFIG_NO_RADIUS - eloop_cancel_timeout(hostapd_acl_expire, hapd, NULL); - hostapd_acl_cache_free(hapd->acl_cache); #endif /* CONFIG_NO_RADIUS */ diff --git a/src/ap/ieee802_11_auth.h b/src/ap/ieee802_11_auth.h index 2bc1065..b66f244 100644 --- a/src/ap/ieee802_11_auth.h +++ b/src/ap/ieee802_11_auth.h @@ -24,5 +24,6 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr, int hostapd_acl_init(struct hostapd_data *hapd); void hostapd_acl_deinit(struct hostapd_data *hapd); void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk); +void hostapd_acl_expire(struct hostapd_data *hapd); #endif /* IEEE802_11_AUTH_H */ diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c index 4b0653d..11fde2a 100644 --- a/src/ap/ieee802_11_ht.c +++ b/src/ap/ieee802_11_ht.c @@ -209,7 +209,7 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd, struct hostapd_iface *iface = hapd->iface; struct ieee80211_2040_bss_coex_ie *bc_ie; struct ieee80211_2040_intol_chan_report *ic_report; - int is_ht_allowed = 1; + int is_ht40_allowed = 1; int i; const u8 *start = (const u8 *) mgmt; const u8 *data = start + IEEE80211_HDRLEN + 2; @@ -242,7 +242,7 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "20 MHz BSS width request bit is set in BSS coexistence information field"); - is_ht_allowed = 0; + is_ht40_allowed = 0; } if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_40MHZ_INTOL) { @@ -250,7 +250,7 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "40 MHz intolerant bit is set in BSS coexistence information field"); - is_ht_allowed = 0; + is_ht40_allowed = 0; } if (start + len - data >= 3 && @@ -276,13 +276,13 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd, HOSTAPD_LEVEL_DEBUG, "20_40_INTOLERANT channel %d reported", chan); - is_ht_allowed = 0; + is_ht40_allowed = 0; } } - wpa_printf(MSG_DEBUG, "is_ht_allowed=%d num_sta_ht40_intolerant=%d", - is_ht_allowed, iface->num_sta_ht40_intolerant); + wpa_printf(MSG_DEBUG, "is_ht40_allowed=%d num_sta_ht40_intolerant=%d", + is_ht40_allowed, iface->num_sta_ht40_intolerant); - if (!is_ht_allowed && + if (!is_ht40_allowed && (iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX)) { if (iface->conf->secondary_channel) { hostapd_logger(hapd, mgmt->sa, @@ -310,12 +310,15 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd, u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta, - const u8 *ht_capab, size_t ht_capab_len) + const u8 *ht_capab) { - /* Disable HT caps for STAs associated to no-HT BSSes. */ + /* + * Disable HT caps for STAs associated to no-HT BSSes, or for stations + * that did not specify a valid WMM IE in the (Re)Association Request + * frame. + */ if (!ht_capab || - ht_capab_len < sizeof(struct ieee80211_ht_capabilities) || - hapd->conf->disable_11n) { + !(sta->flags & WLAN_STA_WMM) || hapd->conf->disable_11n) { sta->flags &= ~WLAN_STA_HT; os_free(sta->ht_capabilities); sta->ht_capabilities = NULL; diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c index 171538a..5bf1b5d 100644 --- a/src/ap/ieee802_11_vht.c +++ b/src/ap/ieee802_11_vht.c @@ -132,11 +132,10 @@ static int check_valid_vht_mcs(struct hostapd_hw_modes *mode, u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta, - const u8 *vht_capab, size_t vht_capab_len) + const u8 *vht_capab) { /* Disable VHT caps for STAs associated to no-VHT BSSes. */ if (!vht_capab || - vht_capab_len < sizeof(struct ieee80211_vht_capabilities) || hapd->conf->disable_11ac || !check_valid_vht_mcs(hapd->iface->current_mode, vht_capab)) { sta->flags &= ~WLAN_STA_VHT; diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c index 79dc0f9..0f2d428 100644 --- a/src/ap/ieee802_1x.c +++ b/src/ap/ieee802_1x.c @@ -125,6 +125,9 @@ void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd, } +#ifndef CONFIG_FIPS +#ifndef CONFIG_NO_RC4 + static void ieee802_1x_tx_key_one(struct hostapd_data *hapd, struct sta_info *sta, int idx, int broadcast, @@ -204,7 +207,7 @@ static void ieee802_1x_tx_key_one(struct hostapd_data *hapd, } -void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta) +static void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta) { struct eapol_authenticator *eapol = hapd->eapol_auth; struct eapol_state_machine *sm = sta->eapol_sm; @@ -259,6 +262,9 @@ void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta) } } +#endif /* CONFIG_NO_RC4 */ +#endif /* CONFIG_FIPS */ + const char *radius_mode_txt(struct hostapd_data *hapd) { @@ -346,7 +352,8 @@ static int add_common_radius_sta_attr_rsn(struct hostapd_data *hapd, return -1; } - suite = wpa_cipher_to_suite((hapd->conf->wpa & 0x2) ? + suite = wpa_cipher_to_suite(((hapd->conf->wpa & 0x2) || + hapd->conf->osen) ? WPA_PROTO_RSN : WPA_PROTO_WPA, hapd->conf->wpa_group); if (!hostapd_config_get_radius_attr(req_attr, @@ -453,7 +460,7 @@ static int add_common_radius_sta_attr(struct hostapd_data *hapd, } #endif /* CONFIG_IEEE80211R */ - if (hapd->conf->wpa && sta->wpa_sm && + if ((hapd->conf->wpa || hapd->conf->osen) && sta->wpa_sm && add_common_radius_sta_attr_rsn(hapd, req_attr, sta, msg) < 0) return -1; @@ -599,7 +606,7 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd, goto fail; } - if (eap && !radius_msg_add_eap(msg, eap, len)) { + if (!radius_msg_add_eap(msg, eap, len)) { wpa_printf(MSG_INFO, "Could not add EAP-Message"); goto fail; } @@ -1108,8 +1115,6 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta) pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm); if (pmksa) { - int old_vlanid; - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_DEBUG, "PMK from PMKSA cache - skip IEEE 802.1X/EAP"); @@ -1123,11 +1128,8 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta) sta->eapol_sm->authFail = FALSE; if (sta->eapol_sm->eap) eap_sm_notify_cached(sta->eapol_sm->eap); - old_vlanid = sta->vlan_id; pmksa_cache_to_eapol_data(pmksa, sta->eapol_sm); - if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED) - sta->vlan_id = 0; - ap_sta_bind_vlan(hapd, sta, old_vlanid); + ap_sta_bind_vlan(hapd, sta); } else { if (reassoc) { /* @@ -1290,7 +1292,7 @@ static void ieee802_1x_store_radius_class(struct hostapd_data *hapd, struct sta_info *sta, struct radius_msg *msg) { - u8 *class; + u8 *attr_class; size_t class_len; struct eapol_state_machine *sm = sta->eapol_sm; int count, i; @@ -1312,12 +1314,12 @@ static void ieee802_1x_store_radius_class(struct hostapd_data *hapd, nclass_count = 0; - class = NULL; + attr_class = NULL; for (i = 0; i < count; i++) { do { if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CLASS, - &class, &class_len, - class) < 0) { + &attr_class, &class_len, + attr_class) < 0) { i = count; break; } @@ -1327,7 +1329,7 @@ static void ieee802_1x_store_radius_class(struct hostapd_data *hapd, if (nclass[nclass_count].data == NULL) break; - os_memcpy(nclass[nclass_count].data, class, class_len); + os_memcpy(nclass[nclass_count].data, attr_class, class_len); nclass[nclass_count].len = class_len; nclass_count++; } @@ -1590,7 +1592,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req, struct hostapd_data *hapd = data; struct sta_info *sta; u32 session_timeout = 0, termination_action, acct_interim_interval; - int session_timeout_set, old_vlanid = 0; + int session_timeout_set, vlan_id = 0; struct eapol_state_machine *sm; int override_eapReq = 0; struct radius_hdr *hdr = radius_msg_get_hdr(msg); @@ -1657,20 +1659,27 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req, switch (hdr->code) { case RADIUS_CODE_ACCESS_ACCEPT: - if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED) - sta->vlan_id = 0; + if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED) + vlan_id = 0; #ifndef CONFIG_NO_VLAN - else { - old_vlanid = sta->vlan_id; - sta->vlan_id = radius_msg_get_vlanid(msg); - } - if (sta->vlan_id > 0 && - hostapd_vlan_id_valid(hapd->conf->vlan, sta->vlan_id)) { + else + vlan_id = radius_msg_get_vlanid(msg); + if (vlan_id > 0 && + hostapd_vlan_id_valid(hapd->conf->vlan, vlan_id)) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS, HOSTAPD_LEVEL_INFO, - "VLAN ID %d", sta->vlan_id); - } else if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_REQUIRED) { + "VLAN ID %d", vlan_id); + } else if (vlan_id > 0) { + sta->eapol_sm->authFail = TRUE; + hostapd_logger(hapd, sta->addr, + HOSTAPD_MODULE_RADIUS, + HOSTAPD_LEVEL_INFO, + "Invalid VLAN ID %d received from RADIUS server", + vlan_id); + break; + } else if (hapd->conf->ssid.dynamic_vlan == + DYNAMIC_VLAN_REQUIRED) { sta->eapol_sm->authFail = TRUE; hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, @@ -1681,7 +1690,9 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req, } #endif /* CONFIG_NO_VLAN */ - if (ap_sta_bind_vlan(hapd, sta, old_vlanid) < 0) + sta->vlan_id = vlan_id; + if ((sta->flags & WLAN_STA_ASSOC) && + ap_sta_bind_vlan(hapd, sta) < 0) break; sta->session_timeout_set = !!session_timeout_set; @@ -1926,10 +1937,11 @@ 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; + int rv = -1; eap_user = hostapd_get_eap_user(hapd, identity, identity_len, phase2); if (eap_user == NULL) - return -1; + goto out; os_memset(user, 0, sizeof(*user)); user->phase2 = phase2; @@ -1941,7 +1953,7 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity, if (eap_user->password) { user->password = os_malloc(eap_user->password_len); if (user->password == NULL) - return -1; + goto out; os_memcpy(user->password, eap_user->password, eap_user->password_len); user->password_len = eap_user->password_len; @@ -1951,8 +1963,13 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity, user->macacl = eap_user->macacl; user->ttls_auth = eap_user->ttls_auth; user->remediation = eap_user->remediation; + rv = 0; - return 0; +out: + if (rv) + wpa_printf(MSG_DEBUG, "%s: Failed to find user", __func__); + + return rv; } @@ -2012,9 +2029,13 @@ static void _ieee802_1x_abort_auth(void *ctx, void *sta_ctx) static void _ieee802_1x_tx_key(void *ctx, void *sta_ctx) { +#ifndef CONFIG_FIPS +#ifndef CONFIG_NO_RC4 struct hostapd_data *hapd = ctx; struct sta_info *sta = sta_ctx; ieee802_1x_tx_key(hapd, sta); +#endif /* CONFIG_NO_RC4 */ +#endif /* CONFIG_FIPS */ } @@ -2085,6 +2106,7 @@ int ieee802_1x_init(struct hostapd_data *hapd) conf.erp_send_reauth_start = hapd->conf->erp_send_reauth_start; conf.erp_domain = hapd->conf->erp_domain; conf.erp = hapd->conf->eap_server_erp; + conf.tls_session_lifetime = hapd->conf->tls_session_lifetime; conf.pac_opaque_encr_key = hapd->conf->pac_opaque_encr_key; conf.eap_fast_a_id = hapd->conf->eap_fast_a_id; conf.eap_fast_a_id_len = hapd->conf->eap_fast_a_id_len; @@ -2332,9 +2354,9 @@ void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth) } -static const char * bool_txt(Boolean bool) +static const char * bool_txt(Boolean val) { - return bool ? "TRUE" : "FALSE"; + return val ? "TRUE" : "FALSE"; } diff --git a/src/ap/ieee802_1x.h b/src/ap/ieee802_1x.h index de6e0e7..14d6955 100644 --- a/src/ap/ieee802_1x.h +++ b/src/ap/ieee802_1x.h @@ -23,7 +23,6 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta); void ieee802_1x_free_station(struct sta_info *sta); -void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta); void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta); void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd, struct sta_info *sta, int authorized); diff --git a/src/ap/ndisc_snoop.c b/src/ap/ndisc_snoop.c index b0d42dc..4a87721 100644 --- a/src/ap/ndisc_snoop.c +++ b/src/ap/ndisc_snoop.c @@ -81,12 +81,24 @@ static int sta_has_ip6addr(struct sta_info *sta, struct in6_addr *addr) } +static void ucast_to_stas(struct hostapd_data *hapd, const u8 *buf, size_t len) +{ + struct sta_info *sta; + + for (sta = hapd->sta_list; sta; sta = sta->next) { + if (!(sta->flags & WLAN_STA_AUTHORIZED)) + continue; + x_snoop_mcast_to_ucast_convert_send(hapd, sta, (u8 *) buf, len); + } +} + + static void handle_ndisc(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) { struct hostapd_data *hapd = ctx; struct icmpv6_ndmsg *msg; - struct in6_addr *saddr; + struct in6_addr saddr; struct sta_info *sta; int res; char addrtxt[INET6_ADDRSTRLEN + 1]; @@ -101,25 +113,30 @@ static void handle_ndisc(void *ctx, const u8 *src_addr, const u8 *buf, if (msg->opt_type != SOURCE_LL_ADDR) return; - saddr = &msg->ipv6h.ip6_src; - if (!(saddr->s6_addr32[0] == 0 && saddr->s6_addr32[1] == 0 && - saddr->s6_addr32[2] == 0 && saddr->s6_addr32[3] == 0)) { + /* + * IPv6 header may not be 32-bit aligned in the buffer, so use + * a local copy to avoid unaligned reads. + */ + os_memcpy(&saddr, &msg->ipv6h.ip6_src, sizeof(saddr)); + if (!(saddr.s6_addr32[0] == 0 && saddr.s6_addr32[1] == 0 && + saddr.s6_addr32[2] == 0 && saddr.s6_addr32[3] == 0)) { if (len < ETH_HLEN + sizeof(*msg) + ETH_ALEN) return; sta = ap_get_sta(hapd, msg->opt_lladdr); if (!sta) return; - if (sta_has_ip6addr(sta, saddr)) + if (sta_has_ip6addr(sta, &saddr)) return; - if (inet_ntop(AF_INET6, saddr, addrtxt, sizeof(addrtxt)) - == NULL) + if (inet_ntop(AF_INET6, &saddr, addrtxt, + sizeof(addrtxt)) == NULL) addrtxt[0] = '\0'; wpa_printf(MSG_DEBUG, "ndisc_snoop: Learned new IPv6 address %s for " MACSTR, addrtxt, MAC2STR(sta->addr)); - hostapd_drv_br_delete_ip_neigh(hapd, 6, (u8 *) saddr); - res = hostapd_drv_br_add_ip_neigh(hapd, 6, (u8 *) saddr, + hostapd_drv_br_delete_ip_neigh(hapd, 6, (u8 *) &saddr); + res = hostapd_drv_br_add_ip_neigh(hapd, 6, + (u8 *) &saddr, 128, sta->addr); if (res) { wpa_printf(MSG_ERROR, @@ -128,21 +145,17 @@ static void handle_ndisc(void *ctx, const u8 *src_addr, const u8 *buf, return; } - if (sta_ip6addr_add(sta, saddr)) + if (sta_ip6addr_add(sta, &saddr)) return; } break; case ROUTER_ADVERTISEMENT: - if (!hapd->conf->disable_dgaf) - return; - /* fall through */ + if (hapd->conf->disable_dgaf) + ucast_to_stas(hapd, buf, len); + break; case NEIGHBOR_ADVERTISEMENT: - for (sta = hapd->sta_list; sta; sta = sta->next) { - if (!(sta->flags & WLAN_STA_AUTHORIZED)) - continue; - x_snoop_mcast_to_ucast_convert_send(hapd, sta, - (u8 *) buf, len); - } + if (hapd->conf->na_mcast_to_ucast) + ucast_to_stas(hapd, buf, len); break; default: break; diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c index 7e75e1a..d64307c 100644 --- a/src/ap/sta_info.c +++ b/src/ap/sta_info.c @@ -16,6 +16,7 @@ #include "radius/radius.h" #include "radius/radius_client.h" #include "p2p/p2p.h" +#include "fst/fst.h" #include "hostapd.h" #include "accounting.h" #include "ieee802_1x.h" @@ -171,6 +172,19 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) !(sta->flags & WLAN_STA_PREAUTH)) hostapd_drv_sta_remove(hapd, sta->addr); +#ifndef CONFIG_NO_VLAN + if (sta->vlan_id_bound) { + /* + * Need to remove the STA entry before potentially removing the + * VLAN. + */ + if (hapd->iface->driver_ap_teardown && + !(sta->flags & WLAN_STA_PREAUTH)) + hostapd_drv_sta_remove(hapd, sta->addr); + vlan_remove_dynamic(hapd, sta->vlan_id_bound); + } +#endif /* CONFIG_NO_VLAN */ + ap_sta_hash_del(hapd, sta); ap_sta_list_del(hapd, sta); @@ -283,6 +297,9 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) wpabuf_free(sta->wps_ie); wpabuf_free(sta->p2p_ie); wpabuf_free(sta->hs20_ie); +#ifdef CONFIG_FST + wpabuf_free(sta->mb_ies); +#endif /* CONFIG_FST */ os_free(sta->ht_capabilities); os_free(sta->vht_capabilities); @@ -619,7 +636,6 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr) hapd->sta_list = sta; hapd->num_sta++; ap_sta_hash_add(hapd, sta); - sta->ssid = &hapd->conf->ssid; ap_sta_remove_in_other_bss(hapd, sta); sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ; dl_list_init(&sta->ip6addr); @@ -768,26 +784,19 @@ int ap_sta_wps_cancel(struct hostapd_data *hapd, #endif /* CONFIG_WPS */ -int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta, - int old_vlanid) +int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta) { #ifndef CONFIG_NO_VLAN const char *iface; struct hostapd_vlan *vlan = NULL; int ret; - - /* - * Do not proceed furthur if the vlan id remains same. We do not want - * duplicate dynamic vlan entries. - */ - if (sta->vlan_id == old_vlanid) - return 0; + int old_vlanid = sta->vlan_id_bound; iface = hapd->conf->iface; - if (sta->ssid->vlan[0]) - iface = sta->ssid->vlan; + if (hapd->conf->ssid.vlan[0]) + iface = hapd->conf->ssid.vlan; - if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED) + if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED) sta->vlan_id = 0; else if (sta->vlan_id > 0) { struct hostapd_vlan *wildcard_vlan = NULL; @@ -805,6 +814,14 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta, iface = vlan->ifname; } + /* + * Do not increment ref counters if the VLAN ID remains same, but do + * not skip hostapd_drv_set_sta_vlan() as hostapd_drv_sta_remove() might + * have been called before. + */ + if (sta->vlan_id == old_vlanid) + goto skip_counting; + if (sta->vlan_id > 0 && vlan == NULL) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "could not find VLAN for " @@ -825,7 +842,7 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta, } iface = vlan->ifname; - if (vlan_setup_encryption_dyn(hapd, sta->ssid, iface) != 0) { + if (vlan_setup_encryption_dyn(hapd, iface) != 0) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "could not " @@ -838,7 +855,7 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta, HOSTAPD_LEVEL_DEBUG, "added new dynamic VLAN " "interface '%s'", iface); } else if (vlan && vlan->vlan_id == sta->vlan_id) { - if (sta->vlan_id > 0) { + if (vlan->dynamic_vlan > 0) { vlan->dynamic_vlan++; hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, @@ -852,7 +869,7 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta, * configuration for the case where hostapd did not yet know * which keys are to be used when the interface was added. */ - if (vlan_setup_encryption_dyn(hapd, sta->ssid, iface) != 0) { + if (vlan_setup_encryption_dyn(hapd, iface) != 0) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "could not " @@ -862,6 +879,10 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta, } } + /* ref counters have been increased, so mark the station */ + sta->vlan_id_bound = sta->vlan_id; + +skip_counting: hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "binding station to interface " "'%s'", iface); @@ -876,10 +897,10 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta, "entry to vlan_id=%d", sta->vlan_id); } -done: /* During 1x reauth, if the vlan id changes, then remove the old id. */ - if (old_vlanid > 0) + if (old_vlanid > 0 && old_vlanid != sta->vlan_id) vlan_remove_dynamic(hapd, old_vlanid); +done: return ret; #else /* CONFIG_NO_VLAN */ @@ -1043,6 +1064,16 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta, wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO, AP_STA_DISCONNECTED "%s", buf); } + +#ifdef CONFIG_FST + if (hapd->iface->fst) { + if (authorized) + fst_notify_peer_connected(hapd->iface->fst, sta->addr); + else + fst_notify_peer_disconnected(hapd->iface->fst, + sta->addr); + } +#endif /* CONFIG_FST */ } diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h index 57551ab..420d64e 100644 --- a/src/ap/sta_info.h +++ b/src/ap/sta_info.h @@ -117,10 +117,8 @@ struct sta_info { struct wpa_state_machine *wpa_sm; struct rsn_preauth_interface *preauth_iface; - struct hostapd_ssid *ssid; /* SSID selection based on (Re)AssocReq */ - struct hostapd_ssid *ssid_probe; /* SSID selection based on ProbeReq */ - - int vlan_id; + int vlan_id; /* 0: none, >0: VID */ + int vlan_id_bound; /* updated by ap_sta_bind_vlan() */ /* PSKs from RADIUS authentication server */ struct hostapd_sta_wpa_psk_short *psk; @@ -155,6 +153,9 @@ struct sta_info { struct wpabuf *hs20_deauth_req; char *hs20_session_info_url; int hs20_disassoc_timer; +#ifdef CONFIG_FST + struct wpabuf *mb_ies; /* MB IEs from (Re)Association Request */ +#endif /* CONFIG_FST */ struct os_reltime connected_time; @@ -218,8 +219,7 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta, int ap_sta_wps_cancel(struct hostapd_data *hapd, struct sta_info *sta, void *ctx); #endif /* CONFIG_WPS */ -int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta, - int old_vlanid); +int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta); void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta); void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta); int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta); diff --git a/src/ap/utils.c b/src/ap/utils.c index 931968c..fcb371b 100644 --- a/src/ap/utils.c +++ b/src/ap/utils.c @@ -10,6 +10,7 @@ #include "common.h" #include "common/ieee802_11_defs.h" +#include "fst/fst.h" #include "sta_info.h" #include "hostapd.h" @@ -55,10 +56,20 @@ static int prune_associations(struct hostapd_iface *iface, void *ctx) ohapd = iface->bss[j]; if (ohapd == data->hapd) continue; +#ifdef CONFIG_FST + /* Don't prune STAs belong to same FST */ + if (ohapd->iface->fst && + data->hapd->iface->fst && + fst_are_ifaces_aggregated(ohapd->iface->fst, + data->hapd->iface->fst)) + continue; +#endif /* CONFIG_FST */ osta = ap_get_sta(ohapd, data->addr); if (!osta) continue; + wpa_printf(MSG_INFO, "%s: Prune association for " MACSTR, + ohapd->conf->iface, MAC2STR(osta->addr)); ap_sta_disassociate(ohapd, osta, WLAN_REASON_UNSPECIFIED); } diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c index dc65019..fd1c8dd 100644 --- a/src/ap/vlan_init.c +++ b/src/ap/vlan_init.c @@ -9,6 +9,13 @@ */ #include "utils/includes.h" +#ifdef CONFIG_FULL_DYNAMIC_VLAN +#include <net/if.h> +#include <sys/ioctl.h> +#include <linux/sockios.h> +#include <linux/if_vlan.h> +#include <linux/if_bridge.h> +#endif /* CONFIG_FULL_DYNAMIC_VLAN */ #include "utils/common.h" #include "hostapd.h" @@ -20,12 +27,6 @@ #ifdef CONFIG_FULL_DYNAMIC_VLAN -#include <net/if.h> -#include <sys/ioctl.h> -#include <linux/sockios.h> -#include <linux/if_vlan.h> -#include <linux/if_bridge.h> - #include "drivers/priv_netlink.h" #include "utils/eloop.h" @@ -34,6 +35,90 @@ struct full_dynamic_vlan { int s; /* socket on which to listen for new/removed interfaces. */ }; +#define DVLAN_CLEAN_BR 0x1 +#define DVLAN_CLEAN_VLAN 0x2 +#define DVLAN_CLEAN_VLAN_PORT 0x4 + +struct dynamic_iface { + char ifname[IFNAMSIZ + 1]; + int usage; + int clean; + struct dynamic_iface *next; +}; + + +/* Increment ref counter for ifname and add clean flag. + * If not in list, add it only if some flags are given. + */ +static void dyn_iface_get(struct hostapd_data *hapd, const char *ifname, + int clean) +{ + struct dynamic_iface *next, **dynamic_ifaces; + struct hapd_interfaces *interfaces; + + interfaces = hapd->iface->interfaces; + dynamic_ifaces = &interfaces->vlan_priv; + + for (next = *dynamic_ifaces; next; next = next->next) { + if (os_strcmp(ifname, next->ifname) == 0) + break; + } + + if (next) { + next->usage++; + next->clean |= clean; + return; + } + + if (!clean) + return; + + next = os_zalloc(sizeof(*next)); + if (!next) + return; + os_strlcpy(next->ifname, ifname, sizeof(next->ifname)); + next->usage = 1; + next->clean = clean; + next->next = *dynamic_ifaces; + *dynamic_ifaces = next; +} + + +/* Decrement reference counter for given ifname. + * Return clean flag iff reference counter was decreased to zero, else zero + */ +static int dyn_iface_put(struct hostapd_data *hapd, const char *ifname) +{ + struct dynamic_iface *next, *prev = NULL, **dynamic_ifaces; + struct hapd_interfaces *interfaces; + int clean; + + interfaces = hapd->iface->interfaces; + dynamic_ifaces = &interfaces->vlan_priv; + + for (next = *dynamic_ifaces; next; next = next->next) { + if (os_strcmp(ifname, next->ifname) == 0) + break; + prev = next; + } + + if (!next) + return 0; + + next->usage--; + if (next->usage) + return 0; + + if (prev) + prev->next = next->next; + else + *dynamic_ifaces = next->next; + clean = next->clean; + os_free(next); + + return clean; +} + static int ifconfig_helper(const char *if_name, int up) { @@ -481,11 +566,13 @@ static void vlan_newlink(char *ifname, struct hostapd_data *hapd) struct hostapd_vlan *vlan = hapd->conf->vlan; char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface; int vlan_naming = hapd->conf->ssid.vlan_naming; + int clean; wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname); while (vlan) { - if (os_strcmp(ifname, vlan->ifname) == 0) { + if (os_strcmp(ifname, vlan->ifname) == 0 && !vlan->configured) { + vlan->configured = 1; if (hapd->conf->vlan_bridge[0]) { os_snprintf(br_name, sizeof(br_name), "%s%d", @@ -500,8 +587,8 @@ static void vlan_newlink(char *ifname, struct hostapd_data *hapd) "brvlan%d", vlan->vlan_id); } - if (!br_addbr(br_name)) - vlan->clean |= DVLAN_CLEAN_BR; + dyn_iface_get(hapd, br_name, + br_addbr(br_name) ? 0 : DVLAN_CLEAN_BR); ifconfig_up(br_name); @@ -517,13 +604,16 @@ static void vlan_newlink(char *ifname, struct hostapd_data *hapd) sizeof(vlan_ifname), "vlan%d", vlan->vlan_id); + clean = 0; ifconfig_up(tagged_interface); if (!vlan_add(tagged_interface, vlan->vlan_id, vlan_ifname)) - vlan->clean |= DVLAN_CLEAN_VLAN; + clean |= DVLAN_CLEAN_VLAN; if (!br_addif(br_name, vlan_ifname)) - vlan->clean |= DVLAN_CLEAN_VLAN_PORT; + clean |= DVLAN_CLEAN_VLAN_PORT; + + dyn_iface_get(hapd, vlan_ifname, clean); ifconfig_up(vlan_ifname); } @@ -547,13 +637,15 @@ static void vlan_dellink(char *ifname, struct hostapd_data *hapd) struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan; char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface; int vlan_naming = hapd->conf->ssid.vlan_naming; + int clean; wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname); first = prev = vlan; while (vlan) { - if (os_strcmp(ifname, vlan->ifname) == 0) { + if (os_strcmp(ifname, vlan->ifname) == 0 && + vlan->configured) { if (hapd->conf->vlan_bridge[0]) { os_snprintf(br_name, sizeof(br_name), "%s%d", hapd->conf->vlan_bridge, @@ -581,20 +673,27 @@ static void vlan_dellink(char *ifname, struct hostapd_data *hapd) os_snprintf(vlan_ifname, sizeof(vlan_ifname), "vlan%d", vlan->vlan_id); - if (vlan->clean & DVLAN_CLEAN_VLAN_PORT) + + clean = dyn_iface_put(hapd, vlan_ifname); + + if (clean & DVLAN_CLEAN_VLAN_PORT) br_delif(br_name, vlan_ifname); - ifconfig_down(vlan_ifname); - if (vlan->clean & DVLAN_CLEAN_VLAN) + if (clean & DVLAN_CLEAN_VLAN) { + ifconfig_down(vlan_ifname); vlan_rem(vlan_ifname); + } } - if ((vlan->clean & DVLAN_CLEAN_BR) && + clean = dyn_iface_put(hapd, br_name); + if ((clean & DVLAN_CLEAN_BR) && br_getnumports(br_name) == 0) { ifconfig_down(br_name); br_delbr(br_name); } + } + if (os_strcmp(ifname, vlan->ifname) == 0) { if (vlan == first) { hapd->conf->vlan = vlan->next; } else { @@ -651,6 +750,11 @@ vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del, if (!ifname[0]) return; + if (del && if_nametoindex(ifname)) { + /* interface still exists, race condition -> + * iface has just been recreated */ + return; + } wpa_printf(MSG_DEBUG, "VLAN: RTM_%sLINK: ifi_index=%d ifname=%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)", @@ -778,8 +882,7 @@ static void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv) #endif /* CONFIG_FULL_DYNAMIC_VLAN */ -int vlan_setup_encryption_dyn(struct hostapd_data *hapd, - struct hostapd_ssid *mssid, const char *dyn_vlan) +int vlan_setup_encryption_dyn(struct hostapd_data *hapd, const char *dyn_vlan) { int i; @@ -789,10 +892,11 @@ int vlan_setup_encryption_dyn(struct hostapd_data *hapd, /* Static WEP keys are set here; IEEE 802.1X and WPA uses their own * functions for setting up dynamic broadcast keys. */ for (i = 0; i < 4; i++) { - if (mssid->wep.key[i] && + if (hapd->conf->ssid.wep.key[i] && hostapd_drv_set_key(dyn_vlan, hapd, WPA_ALG_WEP, NULL, i, - i == mssid->wep.idx, NULL, 0, - mssid->wep.key[i], mssid->wep.len[i])) + i == hapd->conf->ssid.wep.idx, NULL, 0, + hapd->conf->ssid.wep.key[i], + hapd->conf->ssid.wep.len[i])) { wpa_printf(MSG_ERROR, "VLAN: Could not set WEP " "encryption for dynamic VLAN"); @@ -953,7 +1057,8 @@ int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id) if (vlan_id <= 0 || vlan_id > MAX_VLAN_ID) return 1; - wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d)", __func__, vlan_id); + wpa_printf(MSG_DEBUG, "VLAN: %s(ifname=%s vlan_id=%d)", + __func__, hapd->conf->iface, vlan_id); vlan = hapd->conf->vlan; while (vlan) { @@ -967,8 +1072,12 @@ int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id) if (vlan == NULL) return 1; - if (vlan->dynamic_vlan == 0) + if (vlan->dynamic_vlan == 0) { hostapd_vlan_if_remove(hapd, vlan->ifname); +#ifdef CONFIG_FULL_DYNAMIC_VLAN + vlan_dellink(vlan->ifname, hapd); +#endif /* CONFIG_FULL_DYNAMIC_VLAN */ + } return 0; } diff --git a/src/ap/vlan_init.h b/src/ap/vlan_init.h index 781eaac..fc39443 100644 --- a/src/ap/vlan_init.h +++ b/src/ap/vlan_init.h @@ -18,7 +18,6 @@ struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd, int vlan_id); int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id); int vlan_setup_encryption_dyn(struct hostapd_data *hapd, - struct hostapd_ssid *mssid, const char *dyn_vlan); #else /* CONFIG_NO_VLAN */ static inline int vlan_init(struct hostapd_data *hapd) @@ -43,7 +42,6 @@ static inline int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id) } static inline int vlan_setup_encryption_dyn(struct hostapd_data *hapd, - struct hostapd_ssid *mssid, const char *dyn_vlan) { return -1; diff --git a/src/ap/vlan_util.c b/src/ap/vlan_util.c index cc54051..d4e0efb 100644 --- a/src/ap/vlan_util.c +++ b/src/ap/vlan_util.c @@ -31,7 +31,7 @@ */ int vlan_add(const char *if_name, int vid, const char *vlan_if_name) { - int ret = -1; + int err, ret = -1; struct nl_sock *handle = NULL; struct nl_cache *cache = NULL; struct rtnl_link *rlink = NULL; @@ -58,14 +58,18 @@ int vlan_add(const char *if_name, int vid, const char *vlan_if_name) goto vlan_add_error; } - if (nl_connect(handle, NETLINK_ROUTE) < 0) { - wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink"); + err = nl_connect(handle, NETLINK_ROUTE); + if (err < 0) { + wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink: %s", + nl_geterror(err)); goto vlan_add_error; } - if (rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache) < 0) { + err = rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache); + if (err < 0) { cache = NULL; - wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache"); + wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache: %s", + nl_geterror(err)); goto vlan_add_error; } @@ -92,23 +96,29 @@ int vlan_add(const char *if_name, int vid, const char *vlan_if_name) goto vlan_add_error; } - if (rtnl_link_set_type(rlink, "vlan") < 0) { - wpa_printf(MSG_ERROR, "VLAN: failed to set link type"); + err = rtnl_link_set_type(rlink, "vlan"); + if (err < 0) { + wpa_printf(MSG_ERROR, "VLAN: failed to set link type: %s", + nl_geterror(err)); goto vlan_add_error; } rtnl_link_set_link(rlink, if_idx); rtnl_link_set_name(rlink, vlan_if_name); - if (rtnl_link_vlan_set_id(rlink, vid) < 0) { - wpa_printf(MSG_ERROR, "VLAN: failed to set link vlan id"); + err = rtnl_link_vlan_set_id(rlink, vid); + if (err < 0) { + wpa_printf(MSG_ERROR, "VLAN: failed to set link vlan id: %s", + nl_geterror(err)); goto vlan_add_error; } - if (rtnl_link_add(handle, rlink, NLM_F_CREATE) < 0) { + err = rtnl_link_add(handle, rlink, NLM_F_CREATE); + if (err < 0) { wpa_printf(MSG_ERROR, "VLAN: failed to create link %s for " - "vlan %d on %s (%d)", - vlan_if_name, vid, if_name, if_idx); + "vlan %d on %s (%d): %s", + vlan_if_name, vid, if_name, if_idx, + nl_geterror(err)); goto vlan_add_error; } @@ -127,7 +137,7 @@ vlan_add_error: int vlan_rem(const char *if_name) { - int ret = -1; + int err, ret = -1; struct nl_sock *handle = NULL; struct nl_cache *cache = NULL; struct rtnl_link *rlink = NULL; @@ -140,14 +150,18 @@ int vlan_rem(const char *if_name) goto vlan_rem_error; } - if (nl_connect(handle, NETLINK_ROUTE) < 0) { - wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink"); + err = nl_connect(handle, NETLINK_ROUTE); + if (err < 0) { + wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink: %s", + nl_geterror(err)); goto vlan_rem_error; } - if (rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache) < 0) { + err = rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache); + if (err < 0) { cache = NULL; - wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache"); + wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache: %s", + nl_geterror(err)); goto vlan_rem_error; } @@ -158,9 +172,10 @@ int vlan_rem(const char *if_name) goto vlan_rem_error; } - if (rtnl_link_delete(handle, rlink) < 0) { - wpa_printf(MSG_ERROR, "VLAN: failed to remove link %s", - if_name); + err = rtnl_link_delete(handle, rlink); + if (err < 0) { + wpa_printf(MSG_ERROR, "VLAN: failed to remove link %s: %s", + if_name, nl_geterror(err)); goto vlan_rem_error; } diff --git a/src/ap/wmm.c b/src/ap/wmm.c index 6d4177c..314e244 100644 --- a/src/ap/wmm.c +++ b/src/ap/wmm.c @@ -274,6 +274,9 @@ void hostapd_wmm_action(struct hostapd_data *hapd, return; } + if (left < 0) + return; /* not a valid WMM Action frame */ + /* extract the tspec info element */ if (ieee802_11_parse_elems(pos, left, &elems, 1) == ParseFailed) { hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index 9c5f609..2760a3f 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -45,6 +45,12 @@ static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth, struct wpa_group *group); static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce, const u8 *pmk, struct wpa_ptk *ptk); +static void wpa_group_free(struct wpa_authenticator *wpa_auth, + struct wpa_group *group); +static void wpa_group_get(struct wpa_authenticator *wpa_auth, + struct wpa_group *group); +static void wpa_group_put(struct wpa_authenticator *wpa_auth, + struct wpa_group *group); static const u32 dot11RSNAConfigGroupUpdateCount = 4; static const u32 dot11RSNAConfigPairwiseUpdateCount = 4; @@ -67,6 +73,14 @@ static inline int wpa_auth_mic_failure_report( } +static inline void wpa_auth_psk_failure_report( + struct wpa_authenticator *wpa_auth, const u8 *addr) +{ + if (wpa_auth->cb.psk_failure_report) + wpa_auth->cb.psk_failure_report(wpa_auth->cb.ctx, addr); +} + + static inline void wpa_auth_set_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr, wpa_eapol_variable var, int value) @@ -254,15 +268,22 @@ static void wpa_rekey_gmk(void *eloop_ctx, void *timeout_ctx) static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx) { struct wpa_authenticator *wpa_auth = eloop_ctx; - struct wpa_group *group; + struct wpa_group *group, *next; wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "rekeying GTK"); - for (group = wpa_auth->group; group; group = group->next) { + group = wpa_auth->group; + while (group) { + wpa_group_get(wpa_auth, group); + group->GTKReKey = TRUE; do { group->changed = FALSE; wpa_group_sm_step(wpa_auth, group); } while (group->changed); + + next = group->next; + wpa_group_put(wpa_auth, group); + group = next; } if (wpa_auth->conf.wpa_group_rekey) { @@ -565,6 +586,7 @@ wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr, sm->wpa_auth = wpa_auth; sm->group = wpa_auth->group; + wpa_group_get(sm->wpa_auth, sm->group); return sm; } @@ -643,6 +665,7 @@ static void wpa_free_sta_sm(struct wpa_state_machine *sm) #endif /* CONFIG_IEEE80211R */ os_free(sm->last_rx_eapol_key); os_free(sm->wpa_ie); + wpa_group_put(sm->wpa_auth, sm->group); os_free(sm); } @@ -1517,6 +1540,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, else WPA_PUT_BE16(key->key_data_length, key_data_len); +#ifndef CONFIG_NO_RC4 } else if (sm->PTK.kek_len == 16) { u8 ek[32]; os_memcpy(key->key_iv, @@ -1532,6 +1556,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, else WPA_PUT_BE16(key->key_data_length, key_data_len); +#endif /* CONFIG_NO_RC4 */ } else { os_free(hdr); os_free(buf); @@ -1646,7 +1671,7 @@ void wpa_remove_ptk(struct wpa_state_machine *sm) } -int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event) +int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event) { int remove_ptk = 1; @@ -1734,6 +1759,14 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event) wpa_remove_ptk(sm); } + if (sm->in_step_loop) { + /* + * wpa_sm_step() is already running - avoid recursive call to + * it by making the existing loop process the new update. + */ + sm->changed = TRUE; + return 0; + } return wpa_sm_step(sm); } @@ -1818,9 +1851,13 @@ static void wpa_group_ensure_init(struct wpa_authenticator *wpa_auth, group->reject_4way_hs_for_entropy = FALSE; } - wpa_group_init_gmk_and_counter(wpa_auth, group); - wpa_gtk_update(wpa_auth, group); - wpa_group_config_group_keys(wpa_auth, group); + if (wpa_group_init_gmk_and_counter(wpa_auth, group) < 0 || + wpa_gtk_update(wpa_auth, group) < 0 || + wpa_group_config_group_keys(wpa_auth, group) < 0) { + wpa_printf(MSG_INFO, "WPA: GMK/GTK setup failed"); + group->first_sta_seen = FALSE; + group->reject_4way_hs_for_entropy = TRUE; + } } @@ -1985,7 +2022,7 @@ static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce, SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) { struct wpa_ptk PTK; - int ok = 0; + int ok = 0, psk_found = 0; const u8 *pmk = NULL; SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk); @@ -2001,6 +2038,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) sm->p2p_dev_addr, pmk); if (pmk == NULL) break; + psk_found = 1; } else pmk = sm->PMK; @@ -2020,6 +2058,8 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) if (!ok) { wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, "invalid MIC in msg 2/4 of 4-Way Handshake"); + if (psk_found) + wpa_auth_psk_failure_report(sm->wpa_auth, sm->addr); return; } @@ -2983,9 +3023,9 @@ void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth) } -static const char * wpa_bool_txt(int bool) +static const char * wpa_bool_txt(int val) { - return bool ? "TRUE" : "FALSE"; + return val ? "TRUE" : "FALSE"; } @@ -3270,6 +3310,63 @@ void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth, } +/* + * Remove and free the group from wpa_authenticator. This is triggered by a + * callback to make sure nobody is currently iterating the group list while it + * gets modified. + */ +static void wpa_group_free(struct wpa_authenticator *wpa_auth, + struct wpa_group *group) +{ + struct wpa_group *prev = wpa_auth->group; + + wpa_printf(MSG_DEBUG, "WPA: Remove group state machine for VLAN-ID %d", + group->vlan_id); + + while (prev) { + if (prev->next == group) { + /* This never frees the special first group as needed */ + prev->next = group->next; + os_free(group); + break; + } + prev = prev->next; + } + +} + + +/* Increase the reference counter for group */ +static void wpa_group_get(struct wpa_authenticator *wpa_auth, + struct wpa_group *group) +{ + /* Skip the special first group */ + if (wpa_auth->group == group) + return; + + group->references++; +} + + +/* Decrease the reference counter and maybe free the group */ +static void wpa_group_put(struct wpa_authenticator *wpa_auth, + struct wpa_group *group) +{ + /* Skip the special first group */ + if (wpa_auth->group == group) + return; + + group->references--; + if (group->references) + return; + wpa_group_free(wpa_auth, group); +} + + +/* + * Add a group that has its references counter set to zero. Caller needs to + * call wpa_group_get() on the return value to mark the entry in use. + */ static struct wpa_group * wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id) { @@ -3320,7 +3417,10 @@ int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id) wpa_printf(MSG_DEBUG, "WPA: Moving STA " MACSTR " to use group state " "machine for VLAN ID %d", MAC2STR(sm->addr), vlan_id); + wpa_group_get(sm->wpa_auth, group); + wpa_group_put(sm->wpa_auth, sm->group); sm->group = group; + return 0; } diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index 2788e65..fd04f16 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -1,6 +1,6 @@ /* * hostapd - IEEE 802.11i-2004 / WPA Authenticator - * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -12,6 +12,9 @@ #include "common/defs.h" #include "common/eapol_common.h" #include "common/wpa_common.h" +#include "common/ieee802_11_defs.h" + +#define MAX_OWN_IE_OVERRIDE 256 #ifdef _MSC_VER #pragma pack(push, 1) @@ -146,8 +149,7 @@ struct wpa_auth_config { int group_mgmt_cipher; #endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_IEEE80211R -#define SSID_LEN 32 - u8 ssid[SSID_LEN]; + u8 ssid[SSID_MAX_LEN]; size_t ssid_len; u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN]; u8 r0_key_holder[FT_R0KH_ID_MAX_LEN]; @@ -164,6 +166,8 @@ struct wpa_auth_config { int ap_mlme; #ifdef CONFIG_TESTING_OPTIONS double corrupt_gtk_rekey_mic_probability; + u8 own_ie_override[MAX_OWN_IE_OVERRIDE]; + size_t own_ie_override_len; #endif /* CONFIG_TESTING_OPTIONS */ #ifdef CONFIG_P2P u8 ip_addr_go[4]; @@ -189,6 +193,7 @@ struct wpa_auth_callbacks { const char *txt); void (*disconnect)(void *ctx, const u8 *addr, u16 reason); int (*mic_failure_report)(void *ctx, const u8 *addr); + void (*psk_failure_report)(void *ctx, const u8 *addr); void (*set_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var, int value); int (*get_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var); @@ -251,12 +256,12 @@ void wpa_auth_sta_deinit(struct wpa_state_machine *sm); void wpa_receive(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *sm, u8 *data, size_t data_len); -typedef enum { +enum wpa_event { WPA_AUTH, WPA_ASSOC, WPA_DISASSOC, WPA_DEAUTH, WPA_REAUTH, WPA_REAUTH_EAPOL, WPA_ASSOC_FT -} wpa_event; +}; void wpa_remove_ptk(struct wpa_state_machine *sm); -int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event); +int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event); void wpa_auth_sm_notify(struct wpa_state_machine *sm); void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth); int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen); diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c index ef3249a..eeaffbf 100644 --- a/src/ap/wpa_auth_ft.c +++ b/src/ap/wpa_auth_ft.c @@ -534,10 +534,8 @@ static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm, return pos; } -#ifdef NEED_AP_MLME - if (parse.wmm_tspec && sm->wpa_auth->conf.ap_mlme) { + if (parse.wmm_tspec) { struct wmm_tspec_element *tspec; - int res; if (parse.wmm_tspec_len + 2 < (int) sizeof(*tspec)) { wpa_printf(MSG_DEBUG, "FT: Too short WMM TSPEC IE " @@ -555,7 +553,13 @@ static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm, } tspec = (struct wmm_tspec_element *) pos; os_memcpy(tspec, parse.wmm_tspec - 2, sizeof(*tspec)); - res = wmm_process_tspec(tspec); + } + +#ifdef NEED_AP_MLME + if (parse.wmm_tspec && sm->wpa_auth->conf.ap_mlme) { + int res; + + res = wmm_process_tspec((struct wmm_tspec_element *) pos); wpa_printf(MSG_DEBUG, "FT: ADDTS processing result: %d", res); if (res == WMM_ADDTS_STATUS_INVALID_PARAMETERS) rdie->status_code = @@ -566,20 +570,17 @@ static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm, else { /* TSPEC accepted; include updated TSPEC in response */ rdie->descr_count = 1; - pos += sizeof(*tspec); + pos += sizeof(struct wmm_tspec_element); } return pos; } #endif /* NEED_AP_MLME */ if (parse.wmm_tspec && !sm->wpa_auth->conf.ap_mlme) { - struct wmm_tspec_element *tspec; int res; - tspec = (struct wmm_tspec_element *) pos; - os_memcpy(tspec, parse.wmm_tspec - 2, sizeof(*tspec)); res = wpa_ft_add_tspec(sm->wpa_auth, sm->addr, pos, - sizeof(*tspec)); + sizeof(struct wmm_tspec_element)); if (res >= 0) { if (res) rdie->status_code = host_to_le16(res); @@ -587,7 +588,7 @@ static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm, /* TSPEC accepted; include updated TSPEC in * response */ rdie->descr_count = 1; - pos += sizeof(*tspec); + pos += sizeof(struct wmm_tspec_element); } return pos; } diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c index 7f83207..f98cc50 100644 --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c @@ -11,6 +11,7 @@ #include "utils/common.h" #include "common/ieee802_11_defs.h" #include "common/sae.h" +#include "common/wpa_ctrl.h" #include "eapol_auth/eapol_auth_sm.h" #include "eapol_auth/eapol_auth_sm_i.h" #include "eap_server/eap.h" @@ -53,8 +54,8 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf, #endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_IEEE80211R wconf->ssid_len = conf->ssid.ssid_len; - if (wconf->ssid_len > SSID_LEN) - wconf->ssid_len = SSID_LEN; + if (wconf->ssid_len > SSID_MAX_LEN) + wconf->ssid_len = SSID_MAX_LEN; os_memcpy(wconf->ssid, conf->ssid.ssid, wconf->ssid_len); os_memcpy(wconf->mobility_domain, conf->mobility_domain, MOBILITY_DOMAIN_ID_LEN); @@ -91,6 +92,13 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf, #ifdef CONFIG_TESTING_OPTIONS wconf->corrupt_gtk_rekey_mic_probability = iconf->corrupt_gtk_rekey_mic_probability; + if (conf->own_ie_override && + wpabuf_len(conf->own_ie_override) <= MAX_OWN_IE_OVERRIDE) { + wconf->own_ie_override_len = wpabuf_len(conf->own_ie_override); + os_memcpy(wconf->own_ie_override, + wpabuf_head(conf->own_ie_override), + wconf->own_ie_override_len); + } #endif /* CONFIG_TESTING_OPTIONS */ #ifdef CONFIG_P2P os_memcpy(wconf->ip_addr_go, conf->ip_addr_go, 4); @@ -144,6 +152,14 @@ static int hostapd_wpa_auth_mic_failure_report(void *ctx, const u8 *addr) } +static void hostapd_wpa_auth_psk_failure_report(void *ctx, const u8 *addr) +{ + struct hostapd_data *hapd = ctx; + wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_POSSIBLE_PSK_MISMATCH MACSTR, + MAC2STR(addr)); +} + + static void hostapd_wpa_auth_set_eapol(void *ctx, const u8 *addr, wpa_eapol_variable var, int value) { @@ -579,6 +595,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd) cb.logger = hostapd_wpa_auth_logger; cb.disconnect = hostapd_wpa_auth_disconnect; cb.mic_failure_report = hostapd_wpa_auth_mic_failure_report; + cb.psk_failure_report = hostapd_wpa_auth_psk_failure_report; cb.set_eapol = hostapd_wpa_auth_set_eapol; cb.get_eapol = hostapd_wpa_auth_get_eapol; cb.get_psk = hostapd_wpa_auth_get_psk; @@ -620,7 +637,8 @@ int hostapd_setup_wpa(struct hostapd_data *hapd) } #ifdef CONFIG_IEEE80211R - if (!hostapd_drv_none(hapd)) { + if (!hostapd_drv_none(hapd) && hapd->conf->ft_over_ds && + wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt)) { hapd->l2 = l2_packet_init(hapd->conf->bridge[0] ? hapd->conf->bridge : hapd->conf->iface, NULL, ETH_P_RRB, diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h index 7b2cd3e..57b098f 100644 --- a/src/ap/wpa_auth_i.h +++ b/src/ap/wpa_auth_i.h @@ -169,6 +169,8 @@ struct wpa_group { u8 IGTK[2][WPA_IGTK_MAX_LEN]; int GN_igtk, GM_igtk; #endif /* CONFIG_IEEE80211W */ + /* Number of references except those in struct wpa_group->next */ + unsigned int references; }; diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c index f287297..eafb828 100644 --- a/src/ap/wpa_auth_ie.c +++ b/src/ap/wpa_auth_ie.c @@ -261,7 +261,8 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, } #ifdef CONFIG_IEEE80211W - if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { + if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION && + conf->group_mgmt_cipher != WPA_CIPHER_AES_128_CMAC) { if (pos + 2 + 4 > buf + len) return -1; if (pmkid == NULL) { @@ -377,6 +378,23 @@ int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth) u8 *pos, buf[128]; int res; +#ifdef CONFIG_TESTING_OPTIONS + if (wpa_auth->conf.own_ie_override_len) { + wpa_hexdump(MSG_DEBUG, "WPA: Forced own IE(s) for testing", + wpa_auth->conf.own_ie_override, + wpa_auth->conf.own_ie_override_len); + os_free(wpa_auth->wpa_ie); + wpa_auth->wpa_ie = + os_malloc(wpa_auth->conf.own_ie_override_len); + if (wpa_auth->wpa_ie == NULL) + return -1; + os_memcpy(wpa_auth->wpa_ie, wpa_auth->conf.own_ie_override, + wpa_auth->conf.own_ie_override_len); + wpa_auth->wpa_ie_len = wpa_auth->conf.own_ie_override_len; + return 0; + } +#endif /* CONFIG_TESTING_OPTIONS */ + pos = buf; if (wpa_auth->conf.wpa == WPA_PROTO_OSEN) { diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c index b0e8b0b..cde31e6 100644 --- a/src/ap/wps_hostapd.c +++ b/src/ap/wps_hostapd.c @@ -324,7 +324,7 @@ static int hapd_wps_reconfig_in_memory(struct hostapd_data *hapd, wpa_printf(MSG_DEBUG, "WPS: Updating in-memory configuration"); bss->wps_state = 2; - if (cred->ssid_len <= HOSTAPD_MAX_SSID_LEN) { + if (cred->ssid_len <= SSID_MAX_LEN) { os_memcpy(bss->ssid.ssid, cred->ssid, cred->ssid_len); bss->ssid.ssid_len = cred->ssid_len; bss->ssid.ssid_set = 1; @@ -347,8 +347,12 @@ static int hapd_wps_reconfig_in_memory(struct hostapd_data *hapd, bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK; bss->wpa_pairwise = 0; - if (cred->encr_type & WPS_ENCR_AES) - bss->wpa_pairwise |= WPA_CIPHER_CCMP; + if (cred->encr_type & WPS_ENCR_AES) { + if (hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD) + bss->wpa_pairwise |= WPA_CIPHER_GCMP; + else + bss->wpa_pairwise |= WPA_CIPHER_CCMP; + } if (cred->encr_type & WPS_ENCR_TKIP) bss->wpa_pairwise |= WPA_CIPHER_TKIP; bss->rsn_pairwise = bss->wpa_pairwise; @@ -448,6 +452,11 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx) os_free(hapd->wps->network_key); hapd->wps->network_key = NULL; hapd->wps->network_key_len = 0; + } else if ((cred->auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK)) && + (cred->key_len < 8 || cred->key_len > 2 * PMK_LEN)) { + wpa_printf(MSG_INFO, "WPS: Invalid key length %lu for WPA/WPA2", + (unsigned long) cred->key_len); + return -1; } else { if (hapd->wps->network_key == NULL || hapd->wps->network_key_len < cred->key_len) { @@ -530,7 +539,11 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx) fprintf(nconf, "wpa_pairwise="); prefix = ""; if (cred->encr_type & WPS_ENCR_AES) { - fprintf(nconf, "CCMP"); + if (hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD) + fprintf(nconf, "GCMP"); + else + fprintf(nconf, "CCMP"); + prefix = " "; } if (cred->encr_type & WPS_ENCR_TKIP) { @@ -844,7 +857,9 @@ static int hostapd_wps_rf_band_cb(void *ctx) struct hostapd_data *hapd = ctx; return hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ? - WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */ + WPS_RF_50GHZ : + hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD ? + WPS_RF_60GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */ } @@ -856,8 +871,10 @@ static void hostapd_wps_clear_ies(struct hostapd_data *hapd, int deinit_only) wpabuf_free(hapd->wps_probe_resp_ie); hapd->wps_probe_resp_ie = NULL; - if (deinit_only) + if (deinit_only) { + hostapd_reset_ap_wps_ie(hapd); return; + } hostapd_set_ap_wps_ie(hapd); } @@ -1039,7 +1056,9 @@ int hostapd_init_wps(struct hostapd_data *hapd, } else { wps->dev.rf_bands = hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ? - WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */ + WPS_RF_50GHZ : + hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD ? + WPS_RF_60GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */ } if (conf->wpa & WPA_PROTO_RSN) { @@ -1285,30 +1304,53 @@ int hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *addr, } +struct wps_button_pushed_ctx { + const u8 *p2p_dev_addr; + unsigned int count; +}; + static int wps_button_pushed(struct hostapd_data *hapd, void *ctx) { - const u8 *p2p_dev_addr = ctx; - if (hapd->wps == NULL) - return -1; - return wps_registrar_button_pushed(hapd->wps->registrar, p2p_dev_addr); + struct wps_button_pushed_ctx *data = ctx; + + if (hapd->wps) { + data->count++; + return wps_registrar_button_pushed(hapd->wps->registrar, + data->p2p_dev_addr); + } + + return 0; } int hostapd_wps_button_pushed(struct hostapd_data *hapd, const u8 *p2p_dev_addr) { - return hostapd_wps_for_each(hapd, wps_button_pushed, - (void *) p2p_dev_addr); + struct wps_button_pushed_ctx ctx; + int ret; + + os_memset(&ctx, 0, sizeof(ctx)); + ctx.p2p_dev_addr = p2p_dev_addr; + ret = hostapd_wps_for_each(hapd, wps_button_pushed, &ctx); + if (ret == 0 && !ctx.count) + ret = -1; + return ret; } +struct wps_cancel_ctx { + unsigned int count; +}; + static int wps_cancel(struct hostapd_data *hapd, void *ctx) { - if (hapd->wps == NULL) - return -1; + struct wps_cancel_ctx *data = ctx; - wps_registrar_wps_cancel(hapd->wps->registrar); - ap_for_each_sta(hapd, ap_sta_wps_cancel, NULL); + if (hapd->wps) { + data->count++; + wps_registrar_wps_cancel(hapd->wps->registrar); + ap_for_each_sta(hapd, ap_sta_wps_cancel, NULL); + } return 0; } @@ -1316,7 +1358,14 @@ static int wps_cancel(struct hostapd_data *hapd, void *ctx) int hostapd_wps_cancel(struct hostapd_data *hapd) { - return hostapd_wps_for_each(hapd, wps_cancel, NULL); + struct wps_cancel_ctx ctx; + int ret; + + os_memset(&ctx, 0, sizeof(ctx)); + ret = hostapd_wps_for_each(hapd, wps_cancel, &ctx); + if (ret == 0 && !ctx.count) + ret = -1; + return ret; } @@ -1546,6 +1595,10 @@ struct wps_ap_pin_data { static int wps_ap_pin_set(struct hostapd_data *hapd, void *ctx) { struct wps_ap_pin_data *data = ctx; + + if (!hapd->wps) + return 0; + os_free(hapd->conf->ap_pin); hapd->conf->ap_pin = os_strdup(data->pin_txt); #ifdef CONFIG_WPS_UPNP diff --git a/src/ap/x_snoop.c b/src/ap/x_snoop.c index 8f77015..aef9a53 100644 --- a/src/ap/x_snoop.c +++ b/src/ap/x_snoop.c @@ -51,6 +51,14 @@ int x_snoop_init(struct hostapd_data *hapd) return -1; } +#ifdef CONFIG_IPV6 + if (hostapd_drv_br_set_net_param(hapd, DRV_BR_MULTICAST_SNOOPING, 1)) { + wpa_printf(MSG_DEBUG, + "x_snoop: Failed to enable multicast snooping on the bridge"); + return -1; + } +#endif /* CONFIG_IPV6 */ + return 0; } |