* Copyright (c) 2005-2006, Devicescape Software, Inc.
* Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
-#include "drivers/driver.h"
+#include "common/hw_features_common.h"
#include "wps/wps_defs.h"
#include "p2p/p2p.h"
#include "hostapd.h"
#include "ap_drv_ops.h"
#include "beacon.h"
#include "hs20.h"
+#include "dfs.h"
#ifdef NEED_AP_MLME
+static u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
+ size_t len)
+{
+ if (!hapd->conf->radio_measurements || len < 2 + 4)
+ return eid;
+
+ *eid++ = WLAN_EID_RRM_ENABLED_CAPABILITIES;
+ *eid++ = 5;
+ *eid++ = (hapd->conf->radio_measurements & BIT(0)) ?
+ WLAN_RRM_CAPS_NEIGHBOR_REPORT : 0x00;
+ *eid++ = 0x00;
+ *eid++ = 0x00;
+ *eid++ = 0x00;
+ *eid++ = 0x00;
+ return eid;
+}
+
+
static u8 * hostapd_eid_bss_load(struct hostapd_data *hapd, u8 *eid, size_t len)
{
+ if (len < 2 + 5)
+ return eid;
+
#ifdef CONFIG_TESTING_OPTIONS
if (hapd->conf->bss_load_test_set) {
- if (2 + 5 > len)
- return eid;
*eid++ = WLAN_EID_BSS_LOAD;
*eid++ = 5;
os_memcpy(eid, hapd->conf->bss_load_test, 5);
eid += 5;
+ return eid;
}
#endif /* CONFIG_TESTING_OPTIONS */
+ if (hapd->conf->bss_load_update_period) {
+ *eid++ = WLAN_EID_BSS_LOAD;
+ *eid++ = 5;
+ WPA_PUT_LE16(eid, hapd->num_sta);
+ eid += 2;
+ *eid++ = hapd->iface->channel_utilization;
+ WPA_PUT_LE16(eid, 0); /* no available admission capabity */
+ eid += 2;
+ }
return eid;
}
}
+static u8 * hostapd_eid_pwr_constraint(struct hostapd_data *hapd, u8 *eid)
+{
+ u8 *pos = eid;
+ u8 local_pwr_constraint = 0;
+ int dfs;
+
+ if (hapd->iface->current_mode == NULL ||
+ hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A)
+ return eid;
+
+ /* Let host drivers add this IE if DFS support is offloaded */
+ if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
+ return eid;
+
+ /*
+ * There is no DFS support and power constraint was not directly
+ * requested by config option.
+ */
+ if (!hapd->iconf->ieee80211h &&
+ hapd->iconf->local_pwr_constraint == -1)
+ return eid;
+
+ /* Check if DFS is required by regulatory. */
+ dfs = hostapd_is_dfs_required(hapd->iface);
+ if (dfs < 0) {
+ wpa_printf(MSG_WARNING, "Failed to check if DFS is required; ret=%d",
+ dfs);
+ dfs = 0;
+ }
+
+ if (dfs == 0 && hapd->iconf->local_pwr_constraint == -1)
+ return eid;
+
+ /*
+ * ieee80211h (DFS) is enabled so Power Constraint element shall
+ * be added when running on DFS channel whenever local_pwr_constraint
+ * is configured or not. In order to meet regulations when TPC is not
+ * implemented using a transmit power that is below the legal maximum
+ * (including any mitigation factor) should help. In this case,
+ * indicate 3 dB below maximum allowed transmit power.
+ */
+ if (hapd->iconf->local_pwr_constraint == -1)
+ local_pwr_constraint = 3;
+
+ /*
+ * A STA that is not an AP shall use a transmit power less than or
+ * equal to the local maximum transmit power level for the channel.
+ * The local maximum transmit power can be calculated from the formula:
+ * local max TX pwr = max TX pwr - local pwr constraint
+ * Where max TX pwr is maximum transmit power level specified for
+ * channel in Country element and local pwr constraint is specified
+ * for channel in this Power Constraint element.
+ */
+
+ /* Element ID */
+ *pos++ = WLAN_EID_PWR_CONSTRAINT;
+ /* Length */
+ *pos++ = 1;
+ /* Local Power Constraint */
+ if (local_pwr_constraint)
+ *pos++ = local_pwr_constraint;
+ else
+ *pos++ = hapd->iconf->local_pwr_constraint;
+
+ return pos;
+}
+
+
static u8 * hostapd_eid_country_add(u8 *pos, u8 *end, int chan_spacing,
struct hostapd_channel_data *start,
struct hostapd_channel_data *prev)
continue; /* can use same entry */
}
- if (start) {
+ if (start && prev) {
pos = hostapd_eid_country_add(pos, end, chan_spacing,
start, prev);
start = NULL;
{
u8 chan;
- if (!hapd->iface->cs_freq)
+ if (!hapd->cs_freq_params.freq)
return eid;
- if (ieee80211_freq_to_chan(hapd->iface->cs_freq, &chan) ==
+ if (ieee80211_freq_to_chan(hapd->cs_freq_params.freq, &chan) ==
NUM_HOSTAPD_MODES)
return eid;
*eid++ = WLAN_EID_CHANNEL_SWITCH;
*eid++ = 3;
- *eid++ = hapd->iface->cs_block_tx;
+ *eid++ = hapd->cs_block_tx;
*eid++ = chan;
- *eid++ = hapd->iface->cs_count;
+ *eid++ = hapd->cs_count;
return eid;
}
+static u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid)
+{
+ u8 sec_ch;
+
+ if (!hapd->cs_freq_params.sec_channel_offset)
+ return eid;
+
+ if (hapd->cs_freq_params.sec_channel_offset == -1)
+ sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW;
+ else if (hapd->cs_freq_params.sec_channel_offset == 1)
+ sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE;
+ else
+ return eid;
+
+ *eid++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET;
+ *eid++ = 1;
+ *eid++ = sec_ch;
+
+ return eid;
+}
+
+
+static u8 * hostapd_add_csa_elems(struct hostapd_data *hapd, u8 *pos,
+ u8 *start, unsigned int *csa_counter_off)
+{
+ u8 *old_pos = pos;
+
+ if (!csa_counter_off)
+ return pos;
+
+ *csa_counter_off = 0;
+ pos = hostapd_eid_csa(hapd, pos);
+
+ if (pos != old_pos) {
+ /* save an offset to the counter - should be last byte */
+ *csa_counter_off = pos - start - 1;
+ pos = hostapd_eid_secondary_channel(hapd, pos);
+ }
+
+ return 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)
{
struct ieee80211_mgmt *resp;
- u8 *pos, *epos, *old_pos;
+ u8 *pos, *epos;
size_t buflen;
#define MAX_PROBERESP_LEN 768
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) {
+ buflen += 5 + 2 + sizeof(struct ieee80211_vht_capabilities) +
+ 2 + sizeof(struct ieee80211_vht_operation);
+ }
resp = os_zalloc(buflen);
if (resp == NULL)
return NULL;
/* 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;
pos = hostapd_eid_country(hapd, pos, epos - pos);
+ /* Power Constraint element */
+ pos = hostapd_eid_pwr_constraint(hapd, pos);
+
/* ERP Information element */
pos = hostapd_eid_erp_info(hapd, pos);
pos = hostapd_eid_bss_load(hapd, pos, epos - pos);
+ pos = hostapd_eid_rm_enabled_capab(hapd, pos, epos - pos);
+
#ifdef CONFIG_IEEE80211N
pos = hostapd_eid_ht_capabilities(hapd, pos);
pos = hostapd_eid_ht_operation(hapd, pos);
pos = hostapd_eid_adv_proto(hapd, pos);
pos = hostapd_eid_roaming_consortium(hapd, pos);
- old_pos = pos;
- pos = hostapd_eid_csa(hapd, pos);
+ pos = hostapd_add_csa_elems(hapd, pos, (u8 *)resp,
+ &hapd->cs_c_off_proberesp);
- /* save an offset to the counter - should be last byte */
- hapd->iface->cs_c_off_proberesp = (pos != old_pos) ?
- pos - (u8 *) resp - 1 : 0;
+#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
- pos = hostapd_eid_vht_capabilities(hapd, pos);
- pos = hostapd_eid_vht_operation(hapd, pos);
+ if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
+ pos = hostapd_eid_vht_capabilities(hapd, pos);
+ pos = hostapd_eid_vht_operation(hapd, pos);
+ }
+ if (hapd->conf->vendor_vht)
+ pos = hostapd_eid_vendor_vht(hapd, pos);
#endif /* CONFIG_IEEE80211AC */
/* Wi-Fi Alliance WMM */
#ifdef CONFIG_HS20
pos = hostapd_eid_hs20_indication(hapd, pos);
+ pos = hostapd_eid_osen(hapd, pos);
#endif /* CONFIG_HS20 */
if (hapd->conf->vendor_elements) {
}
+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;
+}
+
+
+static 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++;
+}
+
+
void handle_probe_req(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len,
int ssi_signal)
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;
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++)
return;
}
+ /*
+ * No need to reply if the Probe Request frame was sent on an adjacent
+ * channel. IEEE Std 802.11-2012 describes this as a requirement for an
+ * AP with dot11RadioMeasurementActivated set to true, but strictly
+ * speaking does not allow such ignoring of Probe Request frames if
+ * dot11RadioMeasurementActivated is false. Anyway, this can help reduce
+ * number of unnecessary Probe Response frames for cases where the STA
+ * is less likely to see them (Probe Request frame sent on a
+ * neighboring, but partially overlapping, channel).
+ */
+ if (elems.ds_params &&
+ hapd->iface->current_mode &&
+ (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G ||
+ hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211B) &&
+ hapd->iconf->channel != elems.ds_params[0]) {
+ wpa_printf(MSG_DEBUG,
+ "Ignore Probe Request due to DS Params mismatch: chan=%u != ds.chan=%u",
+ hapd->iconf->channel, elems.ds_params[0]);
+ return;
+ }
+
#ifdef CONFIG_P2P
if (hapd->p2p && elems.wps_ie) {
struct wpabuf *wps;
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 &&
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)) {
- char ssid_txt[33];
- ieee802_11_print_ssid(ssid_txt, elems.ssid,
- elems.ssid_len);
wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
" for foreign SSID '%s' (DA " MACSTR ")%s",
- MAC2STR(mgmt->sa), ssid_txt,
+ MAC2STR(mgmt->sa),
+ wpa_ssid_txt(elems.ssid, elems.ssid_len),
MAC2STR(mgmt->da),
elems.ssid_list ? " (SSID list)" : "");
}
}
#ifdef CONFIG_INTERWORKING
- if (elems.interworking && elems.interworking_len >= 1) {
+ if (hapd->conf->interworking &&
+ elems.interworking && elems.interworking_len >= 1) {
u8 ant = elems.interworking[0] & 0x0f;
if (ant != INTERWORKING_ANT_WILDCARD &&
ant != hapd->conf->access_network_type) {
}
}
- if (elems.interworking &&
+ if (hapd->conf->interworking && elems.interworking &&
(elems.interworking_len == 7 || elems.interworking_len == 9)) {
const u8 *hessid;
if (elems.interworking_len == 7)
* with AP configuration */
#ifdef CONFIG_TESTING_OPTIONS
- if (hapd->iconf->ignore_probe_probability > 0.0d &&
+ if (hapd->iconf->ignore_probe_probability > 0.0 &&
drand48() < hapd->iconf->ignore_probe_probability) {
wpa_printf(MSG_INFO,
"TESTING: ignoring probe request from " MACSTR,
}
#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;
"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 */
size_t resp_len = 0;
#ifdef NEED_AP_MLME
u16 capab_info;
- u8 *pos, *tailpos, *old_pos;
+ u8 *pos, *tailpos;
#define BEACON_HEAD_BUF_SIZE 256
#define BEACON_TAIL_BUF_SIZE 512
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);
+
+#ifdef CONFIG_IEEE80211AC
+ if (hapd->conf->vendor_vht) {
+ tail_len += 5 + 2 + sizeof(struct ieee80211_vht_capabilities) +
+ 2 + sizeof(struct ieee80211_vht_operation);
+ }
+#endif /* CONFIG_IEEE80211AC */
+
tailpos = tail = os_malloc(tail_len);
if (head == NULL || tail == NULL) {
wpa_printf(MSG_ERROR, "Failed to set beacon data");
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];
tailpos = hostapd_eid_country(hapd, tailpos,
tail + BEACON_TAIL_BUF_SIZE - tailpos);
+ /* Power Constraint element */
+ tailpos = hostapd_eid_pwr_constraint(hapd, tailpos);
+
/* ERP Information element */
tailpos = hostapd_eid_erp_info(hapd, tailpos);
tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE -
tailpos);
+ tailpos = hostapd_eid_rm_enabled_capab(hapd, tailpos,
+ tail + BEACON_TAIL_BUF_SIZE -
+ tailpos);
+
tailpos = hostapd_eid_bss_load(hapd, tailpos,
tail + BEACON_TAIL_BUF_SIZE - tailpos);
tailpos = hostapd_eid_interworking(hapd, tailpos);
tailpos = hostapd_eid_adv_proto(hapd, tailpos);
tailpos = hostapd_eid_roaming_consortium(hapd, tailpos);
- old_pos = tailpos;
- tailpos = hostapd_eid_csa(hapd, tailpos);
- hapd->iface->cs_c_off_beacon = (old_pos != tailpos) ?
- tailpos - tail - 1 : 0;
+ 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
- tailpos = hostapd_eid_vht_capabilities(hapd, tailpos);
- tailpos = hostapd_eid_vht_operation(hapd, tailpos);
+ if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
+ tailpos = hostapd_eid_vht_capabilities(hapd, tailpos);
+ tailpos = hostapd_eid_vht_operation(hapd, tailpos);
+ }
+ if (hapd->conf->vendor_vht)
+ tailpos = hostapd_eid_vendor_vht(hapd, tailpos);
#endif /* CONFIG_IEEE80211AC */
/* Wi-Fi Alliance WMM */
#ifdef CONFIG_HS20
tailpos = hostapd_eid_hs20_indication(hapd, tailpos);
+ tailpos = hostapd_eid_osen(hapd, tailpos);
#endif /* CONFIG_HS20 */
if (hapd->conf->vendor_elements) {
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->rsn_pairwise ?
- hapd->conf->rsn_pairwise : hapd->conf->wpa_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;
break;
}
params->isolate = hapd->conf->isolate;
+ params->smps_mode = hapd->iconf->ht_capab & HT_CAP_INFO_SMPS_MASK;
#ifdef NEED_AP_MLME
params->cts_protect = !!(ieee802_11_erp_info(hapd) &
ERP_INFO_USE_PROTECTION);
params->hessid = hapd->conf->hessid;
params->access_network_type = hapd->conf->access_network_type;
params->ap_max_inactivity = hapd->conf->ap_max_inactivity;
+#ifdef CONFIG_P2P
+ params->p2p_go_ctwindow = hapd->iconf->p2p_go_ctwindow;
+#endif /* CONFIG_P2P */
#ifdef CONFIG_HS20
params->disable_dgaf = hapd->conf->disable_dgaf;
+ if (hapd->conf->osen) {
+ params->privacy = 1;
+ params->osen = 1;
+ }
#endif /* CONFIG_HS20 */
return 0;
}
}
-void ieee802_11_set_beacon(struct hostapd_data *hapd)
+int ieee802_11_set_beacon(struct hostapd_data *hapd)
{
struct wpa_driver_ap_params params;
+ struct hostapd_freq_params freq;
+ struct hostapd_iface *iface = hapd->iface;
+ struct hostapd_config *iconf = iface->conf;
struct wpabuf *beacon, *proberesp, *assocresp;
+ int res, ret = -1;
- if (hapd->iface->csa_in_progress) {
+ if (hapd->csa_in_progress) {
wpa_printf(MSG_ERROR, "Cannot set beacons during CSA period");
- return;
+ return -1;
}
hapd->beacon_set_done = 1;
if (ieee802_11_build_ap_params(hapd, ¶ms) < 0)
- return;
+ return -1;
if (hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp) <
0)
params.beacon_ies = beacon;
params.proberesp_ies = proberesp;
params.assocresp_ies = assocresp;
-
- if (hostapd_drv_set_ap(hapd, ¶ms))
- wpa_printf(MSG_ERROR, "Failed to set beacon parameters");
+ params.reenable = hapd->reenable_beacon;
+ hapd->reenable_beacon = 0;
+
+ if (iface->current_mode &&
+ hostapd_set_freq_params(&freq, iconf->hw_mode, iface->freq,
+ iconf->channel, iconf->ieee80211n,
+ iconf->ieee80211ac,
+ iconf->secondary_channel,
+ iconf->vht_oper_chwidth,
+ iconf->vht_oper_centr_freq_seg0_idx,
+ iconf->vht_oper_centr_freq_seg1_idx,
+ iface->current_mode->vht_capab) == 0)
+ params.freq = &freq;
+
+ res = hostapd_drv_set_ap(hapd, ¶ms);
hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
+ if (res)
+ wpa_printf(MSG_ERROR, "Failed to set beacon parameters");
+ else
+ ret = 0;
fail:
ieee802_11_free_ap_params(¶ms);
+ return ret;
}
-void ieee802_11_set_beacons(struct hostapd_iface *iface)
+int ieee802_11_set_beacons(struct hostapd_iface *iface)
{
size_t i;
- for (i = 0; i < iface->num_bss; i++)
- ieee802_11_set_beacon(iface->bss[i]);
+ int ret = 0;
+
+ for (i = 0; i < iface->num_bss; i++) {
+ if (iface->bss[i]->started &&
+ ieee802_11_set_beacon(iface->bss[i]) < 0)
+ ret = -1;
+ }
+
+ return ret;
}
/* only update beacons if started */
-void ieee802_11_update_beacons(struct hostapd_iface *iface)
+int ieee802_11_update_beacons(struct hostapd_iface *iface)
{
size_t i;
- for (i = 0; i < iface->num_bss; i++)
- if (iface->bss[i]->beacon_set_done)
- ieee802_11_set_beacon(iface->bss[i]);
+ int ret = 0;
+
+ for (i = 0; i < iface->num_bss; i++) {
+ if (iface->bss[i]->beacon_set_done && iface->bss[i]->started &&
+ ieee802_11_set_beacon(iface->bss[i]) < 0)
+ ret = -1;
+ }
+
+ return ret;
}
#endif /* CONFIG_NATIVE_WINDOWS */