Cumulative patch from commit d4f1a347ceca31fd9cf14070fd000235d5f4e9c1
d4f1a34 Allow AP mode configuration with VHT enabled on 2.4 GHz
bb337dd DFS: Do not use cf1 to override freq for 20 MHz channels
0dfd2c6 Document AP mode startup functions
fee947b hostapd: Use correct wpa_printf verbosity level for message
2fe210c hostapd: Fix multi-BSS configuration file parsing regression
e4ba031 hostapd: Use start_ctrl_iface() from hostapd_add_iface()
bf7f09b Fix AP mode QoS Map configuration to be per-BSS
dc036d9 DFS: Convert hostapd_data use to hostapd_iface
2db938e hostapd: Fill in phyname automatically
5ae6449 hostapd: Add ctrl_iface STATUS command
afadaff Optimize 40 MHz HT co-ex scan on AP
7d6d737 hostapd: Add AP-ENABLED/DISABLED ctrl_iface events
e1c5faf hostapd: Track interface state
f0793bf hostapd: Wait for channel list update after country code change
ae134e1 hostapd: Add ctrl_iface events for ACS
ad08e14 hostapd: Move ctrl_iface initialization to happen earlier
c20cb02 hostapd: Remove hostapd_interface_init2()
4a5deb9 hostapd: Simplify interface initialization
186c905 DFS: Add control interface events for various DFS events
ddf5517 hostapd: Add control interface test commands for radar detection
884f1a3 nl80211: Verify radar event attributes exist before using them
71cdf6b hostapd: Fix ENABLE failure to not remove interface
18ca733 SAE: Fix group selection
65015b2 Replace unnecessary UTF-8 characters with ASCII versions
61323e7 Convert perror/printf calls to wpa_printf
3f134b4 hostapd: Accept RELOG from global control interface
b253e6f hostapd: Use wpa_printf() for hostapd_logger() to stdout
c092d83 P2P: Clear pending group formation data on group removal
9100b66 P2P: Debug print reason for specific SSID for scan
2aec4f3 Allow add-BSS operation to re-use existing netdev
5592065 hostapd: Allow a single BSS to be removed from an interface
2e2fff3 hostapd: Allow a single BSS to be added to an interface
a1fb569 hostapd: Make hostapd_interface_init_bss() available externally
66936c6 hostapd: Make hostapd_init() available externally
390e489 hostapd: Allow the first BSS in a multi-BSS setup to be removed
834ee56 nl80211: Make wpa_driver_nl80211_data::first_bss pointer
748c0ac nl80211: Fix monitor interface reference counting
08e55eb nl80211: Add a debug print for DEL_BEACON
33b0b33 hostapd: Fix error path in hostapd_add_iface()
770ecdf ACS: Do not get stuck while failing to do a subsequent scan
813d4ba DFS: Add support for multi-BSS
954e71d DFS: Reset cac_started properly
6a398dd DFS: Sanitize channel availability checks
32595da DFS: Fix HT40/VHT calculation
0648c3b hostapd: Add -T Linux tracing option
392e68e Set GTK rekey offload information after initial group key handshake
bbc706a nl80211: Add debug prints for NL80211_CMD_SET_STATION
731ca63 Update regulatory change to all virtual interface for the phy
6f2db2f hostapd: Validate configuration parameters on RELOAD command
eff0fd1 hostapd: Move generic configuration functions into src/ap
5afaa06 hostapd: Allow per-BSS (vif) configuration files
ebd79f0 hostapd: Make hostapd_config::bss array of pointers
a781e21 hostapd: Force PSK to be derived again on BSS reload
9f104b0 hostapd: Reuse hostapd_clear_old() for RELOAD command
Change-Id: I7fbb26cbd4a2960af66a4373c0e6bbe5390a4940
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/accounting.c b/src/ap/accounting.c
index 9540531..a1f67f0 100644
--- a/src/ap/accounting.c
+++ b/src/ap/accounting.c
@@ -44,7 +44,7 @@
msg = radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST,
radius_client_get_id(hapd->radius));
if (msg == NULL) {
- printf("Could not create net RADIUS packet\n");
+ wpa_printf(MSG_INFO, "Could not create new RADIUS packet");
return NULL;
}
@@ -55,7 +55,7 @@
sta->acct_session_id_hi, sta->acct_session_id_lo);
if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
(u8 *) buf, os_strlen(buf))) {
- printf("Could not add Acct-Session-Id\n");
+ wpa_printf(MSG_INFO, "Could not add Acct-Session-Id");
goto fail;
}
} else {
@@ -64,7 +64,7 @@
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_STATUS_TYPE,
status_type)) {
- printf("Could not add Acct-Status-Type\n");
+ wpa_printf(MSG_INFO, "Could not add Acct-Status-Type");
goto fail;
}
@@ -74,7 +74,7 @@
hapd->conf->ieee802_1x ?
RADIUS_ACCT_AUTHENTIC_RADIUS :
RADIUS_ACCT_AUTHENTIC_LOCAL)) {
- printf("Could not add Acct-Authentic\n");
+ wpa_printf(MSG_INFO, "Could not add Acct-Authentic");
goto fail;
}
@@ -99,7 +99,7 @@
if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, val,
len)) {
- printf("Could not add User-Name\n");
+ wpa_printf(MSG_INFO, "Could not add User-Name");
goto fail;
}
}
@@ -117,7 +117,7 @@
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CLASS,
val, len)) {
- printf("Could not add Class\n");
+ wpa_printf(MSG_INFO, "Could not add Class");
goto fail;
}
}
@@ -254,14 +254,14 @@
stop ? RADIUS_ACCT_STATUS_TYPE_STOP :
RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE);
if (!msg) {
- printf("Could not create RADIUS Accounting message\n");
+ wpa_printf(MSG_INFO, "Could not create RADIUS Accounting message");
return;
}
os_get_time(&now);
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_SESSION_TIME,
now.sec - sta->acct_session_start)) {
- printf("Could not add Acct-Session-Time\n");
+ wpa_printf(MSG_INFO, "Could not add Acct-Session-Time");
goto fail;
}
@@ -269,19 +269,19 @@
if (!radius_msg_add_attr_int32(msg,
RADIUS_ATTR_ACCT_INPUT_PACKETS,
data.rx_packets)) {
- printf("Could not add Acct-Input-Packets\n");
+ wpa_printf(MSG_INFO, "Could not add Acct-Input-Packets");
goto fail;
}
if (!radius_msg_add_attr_int32(msg,
RADIUS_ATTR_ACCT_OUTPUT_PACKETS,
data.tx_packets)) {
- printf("Could not add Acct-Output-Packets\n");
+ wpa_printf(MSG_INFO, "Could not add Acct-Output-Packets");
goto fail;
}
if (!radius_msg_add_attr_int32(msg,
RADIUS_ATTR_ACCT_INPUT_OCTETS,
data.rx_bytes)) {
- printf("Could not add Acct-Input-Octets\n");
+ wpa_printf(MSG_INFO, "Could not add Acct-Input-Octets");
goto fail;
}
gigawords = sta->acct_input_gigawords;
@@ -292,13 +292,13 @@
!radius_msg_add_attr_int32(
msg, RADIUS_ATTR_ACCT_INPUT_GIGAWORDS,
gigawords)) {
- printf("Could not add Acct-Input-Gigawords\n");
+ wpa_printf(MSG_INFO, "Could not add Acct-Input-Gigawords");
goto fail;
}
if (!radius_msg_add_attr_int32(msg,
RADIUS_ATTR_ACCT_OUTPUT_OCTETS,
data.tx_bytes)) {
- printf("Could not add Acct-Output-Octets\n");
+ wpa_printf(MSG_INFO, "Could not add Acct-Output-Octets");
goto fail;
}
gigawords = sta->acct_output_gigawords;
@@ -309,14 +309,14 @@
!radius_msg_add_attr_int32(
msg, RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS,
gigawords)) {
- printf("Could not add Acct-Output-Gigawords\n");
+ wpa_printf(MSG_INFO, "Could not add Acct-Output-Gigawords");
goto fail;
}
}
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
now.sec)) {
- printf("Could not add Event-Timestamp\n");
+ wpa_printf(MSG_INFO, "Could not add Event-Timestamp");
goto fail;
}
@@ -326,7 +326,7 @@
if (stop && cause &&
!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
cause)) {
- printf("Could not add Acct-Terminate-Cause\n");
+ wpa_printf(MSG_INFO, "Could not add Acct-Terminate-Cause");
goto fail;
}
@@ -400,13 +400,12 @@
void *data)
{
if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCOUNTING_RESPONSE) {
- printf("Unknown RADIUS message code\n");
+ wpa_printf(MSG_INFO, "Unknown RADIUS message code");
return RADIUS_RX_UNKNOWN;
}
if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
- printf("Incoming RADIUS packet did not have correct "
- "Authenticator - dropped\n");
+ wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have correct Authenticator - dropped");
return RADIUS_RX_INVALID_AUTHENTICATOR;
}
@@ -432,7 +431,7 @@
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
RADIUS_ACCT_TERMINATE_CAUSE_NAS_REBOOT))
{
- printf("Could not add Acct-Terminate-Cause\n");
+ wpa_printf(MSG_INFO, "Could not add Acct-Terminate-Cause");
radius_msg_free(msg);
return;
}
diff --git a/src/ap/acs.c b/src/ap/acs.c
index 019b334..9ef221e 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -13,6 +13,7 @@
#include "utils/common.h"
#include "utils/list.h"
#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
#include "drivers/driver.h"
#include "hostapd.h"
#include "ap_drv_ops.h"
@@ -729,14 +730,17 @@
err = acs_request_scan(iface);
if (err) {
wpa_printf(MSG_ERROR, "ACS: Failed to request scan");
- acs_fail(iface);
- return;
+ goto fail;
}
return;
}
acs_study(iface);
+ return;
+fail:
+ hostapd_acs_completed(iface, 1);
+ acs_fail(iface);
}
@@ -791,5 +795,8 @@
if (err < 0)
return HOSTAPD_CHAN_INVALID;
+ hostapd_set_state(iface, HAPD_IFACE_ACS);
+ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_STARTED);
+
return HOSTAPD_CHAN_ACS;
}
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index caf75c4..65a6f12 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -130,6 +130,13 @@
os_free(bss);
return NULL;
}
+ conf->bss = os_calloc(1, sizeof(struct hostapd_bss_config *));
+ if (conf->bss == NULL) {
+ os_free(conf);
+ os_free(bss);
+ return NULL;
+ }
+ conf->bss[0] = bss;
bss->radius = os_zalloc(sizeof(*bss->radius));
if (bss->radius == NULL) {
@@ -141,7 +148,6 @@
hostapd_config_defaults_bss(bss);
conf->num_bss = 1;
- conf->bss = bss;
conf->beacon_int = 100;
conf->rts_threshold = -1; /* use driver default: 2347 */
@@ -397,7 +403,7 @@
}
-static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
+void hostapd_config_free_bss(struct hostapd_bss_config *conf)
{
struct hostapd_wpa_psk *psk, *prev;
struct hostapd_eap_user *user, *prev_user;
@@ -432,10 +438,12 @@
os_free(conf->accept_mac);
os_free(conf->deny_mac);
os_free(conf->nas_identifier);
- hostapd_config_free_radius(conf->radius->auth_servers,
- conf->radius->num_auth_servers);
- hostapd_config_free_radius(conf->radius->acct_servers,
- conf->radius->num_acct_servers);
+ if (conf->radius) {
+ hostapd_config_free_radius(conf->radius->auth_servers,
+ conf->radius->num_auth_servers);
+ hostapd_config_free_radius(conf->radius->acct_servers,
+ conf->radius->num_acct_servers);
+ }
hostapd_config_free_radius_attr(conf->radius_auth_req_attr);
hostapd_config_free_radius_attr(conf->radius_acct_req_attr);
os_free(conf->rsn_preauth_interfaces);
@@ -525,6 +533,8 @@
os_free(conf->sae_groups);
os_free(conf->server_id);
+
+ os_free(conf);
}
@@ -540,7 +550,7 @@
return;
for (i = 0; i < conf->num_bss; i++)
- hostapd_config_free_bss(&conf->bss[i]);
+ hostapd_config_free_bss(conf->bss[i]);
os_free(conf->bss);
os_free(conf->supported_rates);
os_free(conf->basic_rates);
@@ -658,3 +668,209 @@
return NULL;
}
+
+
+static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
+ struct hostapd_config *conf)
+{
+ if (bss->ieee802_1x && !bss->eap_server &&
+ !bss->radius->auth_servers) {
+ wpa_printf(MSG_ERROR, "Invalid IEEE 802.1X configuration (no "
+ "EAP authenticator configured).");
+ return -1;
+ }
+
+ if (bss->wpa) {
+ int wep, i;
+
+ wep = bss->default_wep_key_len > 0 ||
+ bss->individual_wep_key_len > 0;
+ for (i = 0; i < NUM_WEP_KEYS; i++) {
+ if (bss->ssid.wep.keys_set) {
+ wep = 1;
+ break;
+ }
+ }
+
+ if (wep) {
+ wpa_printf(MSG_ERROR, "WEP configuration in a WPA network is not supported");
+ return -1;
+ }
+ }
+
+ if (bss->wpa && bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
+ bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
+ wpa_printf(MSG_ERROR, "WPA-PSK using RADIUS enabled, but no "
+ "RADIUS checking (macaddr_acl=2) enabled.");
+ return -1;
+ }
+
+ if (bss->wpa && (bss->wpa_key_mgmt & WPA_KEY_MGMT_PSK) &&
+ bss->ssid.wpa_psk == NULL && bss->ssid.wpa_passphrase == NULL &&
+ bss->ssid.wpa_psk_file == NULL &&
+ (bss->wpa_psk_radius != PSK_RADIUS_REQUIRED ||
+ bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH)) {
+ wpa_printf(MSG_ERROR, "WPA-PSK enabled, but PSK or passphrase "
+ "is not configured.");
+ return -1;
+ }
+
+ if (hostapd_mac_comp_empty(bss->bssid) != 0) {
+ size_t i;
+
+ for (i = 0; i < conf->num_bss; i++) {
+ if (conf->bss[i] != bss &&
+ (hostapd_mac_comp(conf->bss[i]->bssid,
+ bss->bssid) == 0)) {
+ wpa_printf(MSG_ERROR, "Duplicate BSSID " MACSTR
+ " on interface '%s' and '%s'.",
+ MAC2STR(bss->bssid),
+ conf->bss[i]->iface, bss->iface);
+ return -1;
+ }
+ }
+ }
+
+#ifdef CONFIG_IEEE80211R
+ if (wpa_key_mgmt_ft(bss->wpa_key_mgmt) &&
+ (bss->nas_identifier == NULL ||
+ os_strlen(bss->nas_identifier) < 1 ||
+ os_strlen(bss->nas_identifier) > FT_R0KH_ID_MAX_LEN)) {
+ wpa_printf(MSG_ERROR, "FT (IEEE 802.11r) requires "
+ "nas_identifier to be configured as a 1..48 octet "
+ "string");
+ return -1;
+ }
+#endif /* CONFIG_IEEE80211R */
+
+#ifdef CONFIG_IEEE80211N
+ if (conf->ieee80211n && conf->hw_mode == HOSTAPD_MODE_IEEE80211B) {
+ bss->disable_11n = 1;
+ wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) in 11b mode is not "
+ "allowed, disabling HT capabilites");
+ }
+
+ if (conf->ieee80211n &&
+ bss->ssid.security_policy == SECURITY_STATIC_WEP) {
+ bss->disable_11n = 1;
+ wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WEP is not "
+ "allowed, disabling HT capabilities");
+ }
+
+ if (conf->ieee80211n && bss->wpa &&
+ !(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
+ !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP))) {
+ bss->disable_11n = 1;
+ wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WPA/WPA2 "
+ "requires CCMP/GCMP to be enabled, disabling HT "
+ "capabilities");
+ }
+#endif /* CONFIG_IEEE80211N */
+
+#ifdef CONFIG_WPS2
+ if (bss->wps_state && bss->ignore_broadcast_ssid) {
+ wpa_printf(MSG_INFO, "WPS: ignore_broadcast_ssid "
+ "configuration forced WPS to be disabled");
+ bss->wps_state = 0;
+ }
+
+ if (bss->wps_state && bss->ssid.wep.keys_set && bss->wpa == 0) {
+ wpa_printf(MSG_INFO, "WPS: WEP configuration forced WPS to be "
+ "disabled");
+ bss->wps_state = 0;
+ }
+
+ if (bss->wps_state && bss->wpa &&
+ (!(bss->wpa & 2) ||
+ !(bss->rsn_pairwise & WPA_CIPHER_CCMP))) {
+ wpa_printf(MSG_INFO, "WPS: WPA/TKIP configuration without "
+ "WPA2/CCMP forced WPS to be disabled");
+ bss->wps_state = 0;
+ }
+#endif /* CONFIG_WPS2 */
+
+#ifdef CONFIG_HS20
+ if (bss->hs20 &&
+ (!(bss->wpa & 2) ||
+ !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)))) {
+ wpa_printf(MSG_ERROR, "HS 2.0: WPA2-Enterprise/CCMP "
+ "configuration is required for Hotspot 2.0 "
+ "functionality");
+ return -1;
+ }
+#endif /* CONFIG_HS20 */
+
+ return 0;
+}
+
+
+int hostapd_config_check(struct hostapd_config *conf)
+{
+ size_t i;
+
+ if (conf->ieee80211d && (!conf->country[0] || !conf->country[1])) {
+ wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11d without "
+ "setting the country_code");
+ return -1;
+ }
+
+ if (conf->ieee80211h && !conf->ieee80211d) {
+ wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11h without "
+ "IEEE 802.11d enabled");
+ return -1;
+ }
+
+ for (i = 0; i < conf->num_bss; i++) {
+ if (hostapd_config_check_bss(conf->bss[i], conf))
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void hostapd_set_security_params(struct hostapd_bss_config *bss)
+{
+ if (bss->individual_wep_key_len == 0) {
+ /* individual keys are not use; can use key idx0 for
+ * broadcast keys */
+ bss->broadcast_key_idx_min = 0;
+ }
+
+ if ((bss->wpa & 2) && bss->rsn_pairwise == 0)
+ bss->rsn_pairwise = bss->wpa_pairwise;
+ bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa, bss->wpa_pairwise,
+ bss->rsn_pairwise);
+
+ bss->radius->auth_server = bss->radius->auth_servers;
+ bss->radius->acct_server = bss->radius->acct_servers;
+
+ if (bss->wpa && bss->ieee802_1x) {
+ bss->ssid.security_policy = SECURITY_WPA;
+ } else if (bss->wpa) {
+ bss->ssid.security_policy = SECURITY_WPA_PSK;
+ } else if (bss->ieee802_1x) {
+ int cipher = WPA_CIPHER_NONE;
+ bss->ssid.security_policy = SECURITY_IEEE_802_1X;
+ bss->ssid.wep.default_len = bss->default_wep_key_len;
+ if (bss->default_wep_key_len)
+ cipher = bss->default_wep_key_len >= 13 ?
+ WPA_CIPHER_WEP104 : WPA_CIPHER_WEP40;
+ bss->wpa_group = cipher;
+ bss->wpa_pairwise = cipher;
+ bss->rsn_pairwise = cipher;
+ } else if (bss->ssid.wep.keys_set) {
+ int cipher = WPA_CIPHER_WEP40;
+ if (bss->ssid.wep.len[0] >= 13)
+ cipher = WPA_CIPHER_WEP104;
+ bss->ssid.security_policy = SECURITY_STATIC_WEP;
+ bss->wpa_group = cipher;
+ bss->wpa_pairwise = cipher;
+ bss->rsn_pairwise = cipher;
+ } 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;
+ }
+}
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 4f6a739..8b73724 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -53,6 +53,8 @@
size_t ssid_len;
unsigned int ssid_set:1;
unsigned int utf8_ssid:1;
+ unsigned int wpa_passphrase_set:1;
+ unsigned int wpa_psk_set:1;
char vlan[IFNAMSIZ + 1];
secpolicy security_policy;
@@ -479,7 +481,7 @@
* struct hostapd_config - Per-radio interface configuration
*/
struct hostapd_config {
- struct hostapd_bss_config *bss, *last_bss;
+ struct hostapd_bss_config **bss, *last_bss;
size_t num_bss;
u16 beacon_int;
@@ -553,6 +555,7 @@
int hostapd_mac_comp_empty(const void *a);
struct hostapd_config * hostapd_config_defaults(void);
void hostapd_config_defaults_bss(struct hostapd_bss_config *bss);
+void hostapd_config_free_bss(struct hostapd_bss_config *conf);
void hostapd_config_free(struct hostapd_config *conf);
int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries,
const u8 *addr, int *vlan_id);
@@ -568,5 +571,7 @@
int vlan_id);
struct hostapd_radius_attr *
hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type);
+int hostapd_config_check(struct hostapd_config *conf);
+void hostapd_set_security_params(struct hostapd_bss_config *bss);
#endif /* HOSTAPD_CONFIG_H */
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 72f582d..0dc0600 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -286,7 +286,7 @@
char force_ifname[IFNAMSIZ];
u8 if_addr[ETH_ALEN];
return hostapd_if_add(hapd, WPA_IF_AP_VLAN, ifname, hapd->own_addr,
- NULL, NULL, force_ifname, if_addr, NULL);
+ NULL, NULL, force_ifname, if_addr, NULL, 0);
}
@@ -417,20 +417,21 @@
int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
const char *ifname, const u8 *addr, void *bss_ctx,
void **drv_priv, char *force_ifname, u8 *if_addr,
- const char *bridge)
+ const char *bridge, int use_existing)
{
if (hapd->driver == NULL || hapd->driver->if_add == NULL)
return -1;
return hapd->driver->if_add(hapd->drv_priv, type, ifname, addr,
bss_ctx, drv_priv, force_ifname, if_addr,
- bridge);
+ bridge, use_existing);
}
int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
const char *ifname)
{
- if (hapd->driver == NULL || hapd->driver->if_remove == NULL)
+ if (hapd->driver == NULL || hapd->drv_priv == NULL ||
+ hapd->driver->if_remove == NULL)
return -1;
return hapd->driver->if_remove(hapd->drv_priv, type, ifname);
}
@@ -490,7 +491,8 @@
case VHT_CHANWIDTH_USE_HT:
if (center_segment1)
return -1;
- if (5000 + center_segment0 * 5 != data->center_freq1)
+ if (5000 + center_segment0 * 5 != data->center_freq1 &&
+ 2407 + center_segment0 * 5 != data->center_freq1)
return -1;
break;
case VHT_CHANWIDTH_80P80MHZ:
@@ -730,18 +732,20 @@
len, 0);
}
-int hostapd_start_dfs_cac(struct hostapd_data *hapd, int mode, int freq,
+
+int hostapd_start_dfs_cac(struct hostapd_iface *iface, int mode, int freq,
int channel, int ht_enabled, int vht_enabled,
int sec_channel_offset, int vht_oper_chwidth,
int center_segment0, int center_segment1)
{
+ struct hostapd_data *hapd = iface->bss[0];
struct hostapd_freq_params data;
int res;
if (!hapd->driver || !hapd->driver->start_dfs_cac)
return 0;
- if (!hapd->iface->conf->ieee80211h) {
+ if (!iface->conf->ieee80211h) {
wpa_printf(MSG_ERROR, "Can't start DFS CAC, DFS functionality "
"is not enabled");
return -1;
@@ -751,12 +755,12 @@
vht_enabled, sec_channel_offset,
vht_oper_chwidth, center_segment0,
center_segment1,
- hapd->iface->current_mode->vht_capab))
+ iface->current_mode->vht_capab))
return -1;
res = hapd->driver->start_dfs_cac(hapd->drv_priv, &data);
if (!res)
- hapd->cac_started = 1;
+ iface->cac_started = 1;
return res;
}
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 8a2b4dc..ce2bb91 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -1,6 +1,6 @@
/*
* hostapd - Driver operations
- * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -48,7 +48,7 @@
int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
const char *ifname, const u8 *addr, void *bss_ctx,
void **drv_priv, char *force_ifname, u8 *if_addr,
- const char *bridge);
+ const char *bridge, int use_existing);
int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
const char *ifname);
int hostapd_set_ieee8021x(struct hostapd_data *hapd,
@@ -101,7 +101,7 @@
int reassoc, u16 status, const u8 *ie, size_t len);
int hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr,
u8 *tspec_ie, size_t tspec_ielen);
-int hostapd_start_dfs_cac(struct hostapd_data *hapd, int mode, int freq,
+int hostapd_start_dfs_cac(struct hostapd_iface *iface, int mode, int freq,
int channel, int ht_enabled, int vht_enabled,
int sec_channel_offset, int vht_oper_chwidth,
int center_segment0, int center_segment1);
@@ -242,4 +242,19 @@
return hapd->driver->get_survey(hapd->drv_priv, freq);
}
+static inline int hostapd_get_country(struct hostapd_data *hapd, char *alpha2)
+{
+ if (hapd->driver == NULL || hapd->driver->get_country == NULL)
+ return -1;
+ return hapd->driver->get_country(hapd->drv_priv, alpha2);
+}
+
+static inline const char * hostapd_drv_get_radio_name(struct hostapd_data *hapd)
+{
+ if (hapd->driver == NULL || hapd->drv_priv == NULL ||
+ hapd->driver->get_radio_name == NULL)
+ return NULL;
+ return hapd->driver->get_radio_name(hapd->drv_priv);
+}
+
#endif /* AP_DRV_OPS */
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 360001f..6c8b78f 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -540,7 +540,7 @@
is_broadcast_ether_addr(mgmt->da));
if (hostapd_drv_send_mlme(hapd, resp, resp_len, noack) < 0)
- perror("handle_probe_req: send");
+ wpa_printf(MSG_INFO, "handle_probe_req: send failed");
os_free(resp);
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 1cb7e73..5d99566 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -1,6 +1,6 @@
/*
* Control interface for shared AP commands
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -303,3 +303,80 @@
return 0;
}
+
+
+int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
+ size_t buflen)
+{
+ struct hostapd_iface *iface = hapd->iface;
+ int len = 0, ret;
+ size_t i;
+
+ ret = os_snprintf(buf + len, buflen - len,
+ "state=%s\n"
+ "phy=%s\n"
+ "freq=%d\n"
+ "num_sta_non_erp=%d\n"
+ "num_sta_no_short_slot_time=%d\n"
+ "num_sta_no_short_preamble=%d\n"
+ "olbc=%d\n"
+ "num_sta_ht_no_gf=%d\n"
+ "num_sta_no_ht=%d\n"
+ "num_sta_ht_20_mhz=%d\n"
+ "olbc_ht=%d\n"
+ "ht_op_mode=0x%x\n",
+ hostapd_state_text(iface->state),
+ iface->phy,
+ iface->freq,
+ iface->num_sta_non_erp,
+ iface->num_sta_no_short_slot_time,
+ iface->num_sta_no_short_preamble,
+ iface->olbc,
+ iface->num_sta_ht_no_gf,
+ iface->num_sta_no_ht,
+ iface->num_sta_ht_20mhz,
+ iface->olbc_ht,
+ iface->ht_op_mode);
+ if (ret < 0 || (size_t) ret >= buflen - len)
+ return len;
+ len += ret;
+
+ ret = os_snprintf(buf + len, buflen - len,
+ "channel=%u\n"
+ "secondary_channel=%d\n"
+ "ieee80211n=%d\n"
+ "ieee80211ac=%d\n"
+ "vht_oper_chwidth=%d\n"
+ "vht_oper_centr_freq_seg0_idx=%d\n"
+ "vht_oper_centr_freq_seg1_idx=%d\n",
+ iface->conf->channel,
+ iface->conf->secondary_channel,
+ iface->conf->ieee80211n,
+ iface->conf->ieee80211ac,
+ iface->conf->vht_oper_chwidth,
+ iface->conf->vht_oper_centr_freq_seg0_idx,
+ iface->conf->vht_oper_centr_freq_seg1_idx);
+ if (ret < 0 || (size_t) ret >= buflen - len)
+ return len;
+ len += ret;
+
+ for (i = 0; i < iface->num_bss; i++) {
+ struct hostapd_data *bss = iface->bss[i];
+ ret = os_snprintf(buf + len, buflen - len,
+ "bss[%d]=%s\n"
+ "bssid[%d]=" MACSTR "\n"
+ "ssid[%d]=%s\n"
+ "num_sta[%d]=%d\n",
+ (int) i, bss->conf->iface,
+ (int) i, MAC2STR(bss->own_addr),
+ (int) i,
+ wpa_ssid_txt(bss->conf->ssid.ssid,
+ bss->conf->ssid.ssid_len),
+ (int) i, bss->num_sta);
+ if (ret < 0 || (size_t) ret >= buflen - len)
+ return len;
+ len += ret;
+ }
+
+ return len;
+}
diff --git a/src/ap/ctrl_iface_ap.h b/src/ap/ctrl_iface_ap.h
index e83f894..a22a2a7 100644
--- a/src/ap/ctrl_iface_ap.h
+++ b/src/ap/ctrl_iface_ap.h
@@ -1,6 +1,6 @@
/*
* Control interface for shared AP commands
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -19,5 +19,7 @@
const char *txtaddr);
int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
const char *txtaddr);
+int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
+ size_t buflen);
#endif /* CTRL_IFACE_AP_H */
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index a30861f..0a909f4 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -11,21 +11,22 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
#include "hostapd.h"
#include "ap_drv_ops.h"
#include "drivers/driver.h"
#include "dfs.h"
-static int dfs_get_used_n_chans(struct hostapd_data *hapd)
+static int dfs_get_used_n_chans(struct hostapd_iface *iface)
{
int n_chans = 1;
- if (hapd->iconf->ieee80211n && hapd->iconf->secondary_channel)
+ if (iface->conf->ieee80211n && iface->conf->secondary_channel)
n_chans = 2;
- if (hapd->iconf->ieee80211ac) {
- switch (hapd->iconf->vht_oper_chwidth) {
+ if (iface->conf->ieee80211ac) {
+ switch (iface->conf->vht_oper_chwidth) {
case VHT_CHANWIDTH_USE_HT:
break;
case VHT_CHANWIDTH_80MHZ:
@@ -94,42 +95,62 @@
}
-static int dfs_find_channel(struct hostapd_data *hapd,
+static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
+ int first_chan_idx, int num_chans)
+{
+ struct hostapd_channel_data *first_chan, *chan;
+ int i;
+
+ 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)
+ return 0;
+
+ if (!dfs_channel_available(chan))
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/*
+ * The function assumes HT40+ operation.
+ * Make sure to adjust the following variables after calling this:
+ * - hapd->secondary_channel
+ * - hapd->vht_oper_centr_freq_seg0_idx
+ * - hapd->vht_oper_centr_freq_seg1_idx
+ */
+static int dfs_find_channel(struct hostapd_iface *iface,
struct hostapd_channel_data **ret_chan,
int idx)
{
struct hostapd_hw_modes *mode;
- struct hostapd_channel_data *chan, *next_chan;
- int i, j, channel_idx = 0, n_chans;
+ struct hostapd_channel_data *chan;
+ int i, channel_idx = 0, n_chans;
- mode = hapd->iface->current_mode;
- n_chans = dfs_get_used_n_chans(hapd);
+ mode = iface->current_mode;
+ n_chans = dfs_get_used_n_chans(iface);
wpa_printf(MSG_DEBUG, "DFS new chan checking %d channels", n_chans);
for (i = 0; i < mode->num_channels; i++) {
chan = &mode->channels[i];
- /* Skip not available channels */
- if (!dfs_channel_available(chan))
+ /* Skip HT40/VHT incompatible channels */
+ if (iface->conf->ieee80211n &&
+ iface->conf->secondary_channel &&
+ !dfs_is_chan_allowed(chan, n_chans))
continue;
- /* Skip HT40/VHT uncompatible channels */
- if (hapd->iconf->ieee80211n &&
- hapd->iconf->secondary_channel) {
- if (!dfs_is_chan_allowed(chan, n_chans))
- continue;
-
- for (j = 1; j < n_chans; j++) {
- next_chan = &mode->channels[i + j];
- if (!dfs_channel_available(next_chan))
- break;
- }
- if (j != n_chans)
- continue;
-
- /* Set HT40+ */
- hapd->iconf->secondary_channel = 1;
- }
+ /* Skip incompatible chandefs */
+ if (!dfs_chan_range_available(mode, i, n_chans))
+ continue;
if (ret_chan && idx == channel_idx) {
wpa_printf(MSG_DEBUG, "Selected ch. #%d", chan->chan);
@@ -143,67 +164,69 @@
}
-static void dfs_adjust_vht_center_freq(struct hostapd_data *hapd,
- struct hostapd_channel_data *chan)
+static void dfs_adjust_vht_center_freq(struct hostapd_iface *iface,
+ struct hostapd_channel_data *chan,
+ u8 *vht_oper_centr_freq_seg0_idx,
+ u8 *vht_oper_centr_freq_seg1_idx)
{
- if (!hapd->iconf->ieee80211ac)
+ if (!iface->conf->ieee80211ac)
return;
if (!chan)
return;
- switch (hapd->iconf->vht_oper_chwidth) {
+ *vht_oper_centr_freq_seg1_idx = 0;
+
+ switch (iface->conf->vht_oper_chwidth) {
case VHT_CHANWIDTH_USE_HT:
- if (hapd->iconf->secondary_channel == 1)
- hapd->iconf->vht_oper_centr_freq_seg0_idx =
- chan->chan + 2;
- else if (hapd->iconf->secondary_channel == -1)
- hapd->iconf->vht_oper_centr_freq_seg0_idx =
- chan->chan - 2;
+ if (iface->conf->secondary_channel == 1)
+ *vht_oper_centr_freq_seg0_idx = chan->chan + 2;
+ else if (iface->conf->secondary_channel == -1)
+ *vht_oper_centr_freq_seg0_idx = chan->chan - 2;
else
- hapd->iconf->vht_oper_centr_freq_seg0_idx = chan->chan;
+ *vht_oper_centr_freq_seg0_idx = chan->chan;
break;
case VHT_CHANWIDTH_80MHZ:
- hapd->iconf->vht_oper_centr_freq_seg0_idx = chan->chan + 6;
+ *vht_oper_centr_freq_seg0_idx = chan->chan + 6;
break;
case VHT_CHANWIDTH_160MHZ:
- hapd->iconf->vht_oper_centr_freq_seg0_idx =
- chan->chan + 14;
+ *vht_oper_centr_freq_seg0_idx = chan->chan + 14;
break;
default:
wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now");
break;
}
- wpa_printf(MSG_DEBUG, "DFS adjusting VHT center frequency: %d",
- hapd->iconf->vht_oper_centr_freq_seg0_idx);
+ wpa_printf(MSG_DEBUG, "DFS adjusting VHT center frequency: %d, %d",
+ *vht_oper_centr_freq_seg0_idx,
+ *vht_oper_centr_freq_seg1_idx);
}
/* Return start channel idx we will use for mode->channels[idx] */
-static int dfs_get_start_chan_idx(struct hostapd_data *hapd)
+static int dfs_get_start_chan_idx(struct hostapd_iface *iface)
{
struct hostapd_hw_modes *mode;
struct hostapd_channel_data *chan;
- int channel_no = hapd->iconf->channel;
+ int channel_no = iface->conf->channel;
int res = -1, i;
/* HT40- */
- if (hapd->iconf->ieee80211n && hapd->iconf->secondary_channel == -1)
+ if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1)
channel_no -= 4;
/* VHT */
- if (hapd->iconf->ieee80211ac) {
- switch (hapd->iconf->vht_oper_chwidth) {
+ if (iface->conf->ieee80211ac) {
+ switch (iface->conf->vht_oper_chwidth) {
case VHT_CHANWIDTH_USE_HT:
break;
case VHT_CHANWIDTH_80MHZ:
channel_no =
- hapd->iconf->vht_oper_centr_freq_seg0_idx - 6;
+ iface->conf->vht_oper_centr_freq_seg0_idx - 6;
break;
case VHT_CHANWIDTH_160MHZ:
channel_no =
- hapd->iconf->vht_oper_centr_freq_seg0_idx - 14;
+ iface->conf->vht_oper_centr_freq_seg0_idx - 14;
break;
default:
wpa_printf(MSG_INFO,
@@ -214,7 +237,7 @@
}
/* Get idx */
- mode = hapd->iface->current_mode;
+ mode = iface->current_mode;
for (i = 0; i < mode->num_channels; i++) {
chan = &mode->channels[i];
if (chan->chan == channel_no) {
@@ -231,14 +254,14 @@
/* At least one channel have radar flag */
-static int dfs_check_chans_radar(struct hostapd_data *hapd, int start_chan_idx,
- int n_chans)
+static int dfs_check_chans_radar(struct hostapd_iface *iface,
+ int start_chan_idx, int n_chans)
{
struct hostapd_channel_data *channel;
struct hostapd_hw_modes *mode;
int i, res = 0;
- mode = hapd->iface->current_mode;
+ mode = iface->current_mode;
for (i = 0; i < n_chans; i++) {
channel = &mode->channels[start_chan_idx + i];
@@ -251,14 +274,14 @@
/* All channels available */
-static int dfs_check_chans_available(struct hostapd_data *hapd,
+static int dfs_check_chans_available(struct hostapd_iface *iface,
int start_chan_idx, int n_chans)
{
struct hostapd_channel_data *channel;
struct hostapd_hw_modes *mode;
int i;
- mode = hapd->iface->current_mode;
+ mode = iface->current_mode;
for(i = 0; i < n_chans; i++) {
channel = &mode->channels[start_chan_idx + i];
@@ -272,7 +295,7 @@
/* At least one channel unavailable */
-static int dfs_check_chans_unavailable(struct hostapd_data *hapd,
+static int dfs_check_chans_unavailable(struct hostapd_iface *iface,
int start_chan_idx,
int n_chans)
{
@@ -280,7 +303,7 @@
struct hostapd_hw_modes *mode;
int i, res = 0;
- mode = hapd->iface->current_mode;
+ mode = iface->current_mode;
for(i = 0; i < n_chans; i++) {
channel = &mode->channels[start_chan_idx + i];
@@ -295,51 +318,63 @@
}
-static struct hostapd_channel_data * dfs_get_valid_channel(
- struct hostapd_data *hapd)
+static struct hostapd_channel_data *
+dfs_get_valid_channel(struct hostapd_iface *iface,
+ int *secondary_channel,
+ u8 *vht_oper_centr_freq_seg0_idx,
+ u8 *vht_oper_centr_freq_seg1_idx)
{
struct hostapd_hw_modes *mode;
struct hostapd_channel_data *chan = NULL;
- int channel_idx, new_channel_idx;
+ int num_available_chandefs;
+ int chan_idx;
u32 _rand;
wpa_printf(MSG_DEBUG, "DFS: Selecting random channel");
- if (hapd->iface->current_mode == NULL)
+ if (iface->current_mode == NULL)
return NULL;
- mode = hapd->iface->current_mode;
+ mode = iface->current_mode;
if (mode->mode != HOSTAPD_MODE_IEEE80211A)
return NULL;
- /* get random available channel */
- channel_idx = dfs_find_channel(hapd, NULL, 0);
- if (channel_idx > 0) {
- os_get_random((u8 *) &_rand, sizeof(_rand));
- new_channel_idx = _rand % channel_idx;
- dfs_find_channel(hapd, &chan, new_channel_idx);
- }
+ /* Get the count first */
+ num_available_chandefs = dfs_find_channel(iface, NULL, 0);
+ if (num_available_chandefs == 0)
+ return NULL;
- /* VHT */
- dfs_adjust_vht_center_freq(hapd, chan);
+ os_get_random((u8 *) &_rand, sizeof(_rand));
+ chan_idx = _rand % num_available_chandefs;
+ dfs_find_channel(iface, &chan, chan_idx);
+
+ /* dfs_find_channel() calculations assume HT40+ */
+ if (iface->conf->secondary_channel)
+ *secondary_channel = 1;
+ else
+ *secondary_channel = 0;
+
+ dfs_adjust_vht_center_freq(iface, chan,
+ vht_oper_centr_freq_seg0_idx,
+ vht_oper_centr_freq_seg1_idx);
return chan;
}
-static int set_dfs_state_freq(struct hostapd_data *hapd, int freq, u32 state)
+static int set_dfs_state_freq(struct hostapd_iface *iface, int freq, u32 state)
{
struct hostapd_hw_modes *mode;
struct hostapd_channel_data *chan = NULL;
int i;
- mode = hapd->iface->current_mode;
+ mode = iface->current_mode;
if (mode == NULL)
return 0;
wpa_printf(MSG_DEBUG, "set_dfs_state 0x%X for %d MHz", state, freq);
- for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
- chan = &hapd->iface->current_mode->channels[i];
+ for (i = 0; i < iface->current_mode->num_channels; i++) {
+ chan = &iface->current_mode->channels[i];
if (chan->freq == freq) {
if (chan->flag & HOSTAPD_CHAN_RADAR) {
chan->flag &= ~HOSTAPD_CHAN_DFS_MASK;
@@ -353,7 +388,7 @@
}
-static int set_dfs_state(struct hostapd_data *hapd, int freq, int ht_enabled,
+static int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled,
int chan_offset, int chan_width, int cf1,
int cf2, u32 state)
{
@@ -362,7 +397,7 @@
int frequency = freq;
int ret = 0;
- mode = hapd->iface->current_mode;
+ mode = iface->current_mode;
if (mode == NULL)
return 0;
@@ -376,7 +411,8 @@
case CHAN_WIDTH_20_NOHT:
case CHAN_WIDTH_20:
n_chans = 1;
- frequency = cf1;
+ if (frequency == 0)
+ frequency = cf1;
break;
case CHAN_WIDTH_40:
n_chans = 2;
@@ -399,7 +435,7 @@
wpa_printf(MSG_DEBUG, "DFS freq: %dMHz, n_chans: %d", frequency,
n_chans);
for (i = 0; i < n_chans; i++) {
- ret += set_dfs_state_freq(hapd, frequency, state);
+ ret += set_dfs_state_freq(iface, frequency, state);
frequency = frequency + 20;
}
@@ -407,7 +443,7 @@
}
-static int dfs_are_channels_overlapped(struct hostapd_data *hapd, int freq,
+static int dfs_are_channels_overlapped(struct hostapd_iface *iface, int freq,
int chan_width, int cf1, int cf2)
{
int start_chan_idx;
@@ -418,12 +454,12 @@
int res = 0;
/* Our configuration */
- mode = hapd->iface->current_mode;
- start_chan_idx = dfs_get_start_chan_idx(hapd);
- n_chans = dfs_get_used_n_chans(hapd);
+ mode = iface->current_mode;
+ start_chan_idx = dfs_get_start_chan_idx(iface);
+ n_chans = dfs_get_used_n_chans(iface);
/* Check we are on DFS channel(s) */
- if (!dfs_check_chans_radar(hapd, start_chan_idx, n_chans))
+ if (!dfs_check_chans_radar(iface, start_chan_idx, n_chans))
return 0;
/* Reported via radar event */
@@ -431,7 +467,8 @@
case CHAN_WIDTH_20_NOHT:
case CHAN_WIDTH_20:
radar_n_chans = 1;
- frequency = cf1;
+ if (frequency == 0)
+ frequency = cf1;
break;
case CHAN_WIDTH_40:
radar_n_chans = 2;
@@ -477,22 +514,24 @@
* 0 - channel/ap setup will be continued after CAC
* -1 - hit critical error
*/
-int hostapd_handle_dfs(struct hostapd_data *hapd)
+int hostapd_handle_dfs(struct hostapd_iface *iface)
{
struct hostapd_channel_data *channel;
int res, n_chans, start_chan_idx;
+ iface->cac_started = 0;
+
do {
/* Get start (first) channel for current configuration */
- start_chan_idx = dfs_get_start_chan_idx(hapd);
+ start_chan_idx = dfs_get_start_chan_idx(iface);
if (start_chan_idx == -1)
return -1;
/* Get number of used channels, depend on width */
- n_chans = dfs_get_used_n_chans(hapd);
+ n_chans = dfs_get_used_n_chans(iface);
/* Check if any of configured channels require DFS */
- res = dfs_check_chans_radar(hapd, start_chan_idx, n_chans);
+ res = dfs_check_chans_radar(iface, start_chan_idx, n_chans);
wpa_printf(MSG_DEBUG,
"DFS %d channels required radar detection",
res);
@@ -500,7 +539,7 @@
return 1;
/* Check if all channels are DFS available */
- res = dfs_check_chans_available(hapd, start_chan_idx, n_chans);
+ res = dfs_check_chans_available(iface, start_chan_idx, n_chans);
wpa_printf(MSG_DEBUG,
"DFS all channels available, (SKIP CAC): %s",
res ? "yes" : "no");
@@ -508,32 +547,44 @@
return 1;
/* Check if any of configured channels is unavailable */
- res = dfs_check_chans_unavailable(hapd, start_chan_idx,
+ res = dfs_check_chans_unavailable(iface, start_chan_idx,
n_chans);
wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s",
res, res ? "yes": "no");
if (res) {
- channel = dfs_get_valid_channel(hapd);
+ int sec;
+ u8 cf1, cf2;
+
+ channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2);
if (!channel) {
wpa_printf(MSG_ERROR, "could not get valid channel");
return -1;
}
- hapd->iconf->channel = channel->chan;
- hapd->iface->freq = channel->freq;
+
+ iface->freq = channel->freq;
+ iface->conf->channel = channel->chan;
+ iface->conf->secondary_channel = sec;
+ iface->conf->vht_oper_centr_freq_seg0_idx = cf1;
+ iface->conf->vht_oper_centr_freq_seg1_idx = cf2;
}
} while (res);
/* Finally start CAC */
- wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", hapd->iface->freq);
- if (hostapd_start_dfs_cac(hapd, hapd->iconf->hw_mode,
- hapd->iface->freq,
- hapd->iconf->channel,
- hapd->iconf->ieee80211n,
- hapd->iconf->ieee80211ac,
- hapd->iconf->secondary_channel,
- hapd->iconf->vht_oper_chwidth,
- hapd->iconf->vht_oper_centr_freq_seg0_idx,
- hapd->iconf->vht_oper_centr_freq_seg1_idx)) {
+ hostapd_set_state(iface, HAPD_IFACE_DFS);
+ wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq);
+ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
+ "freq=%d chan=%d sec_chan=%d",
+ iface->freq,
+ iface->conf->channel, iface->conf->secondary_channel);
+ if (hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
+ iface->freq,
+ iface->conf->channel,
+ iface->conf->ieee80211n,
+ iface->conf->ieee80211ac,
+ iface->conf->secondary_channel,
+ iface->conf->vht_oper_chwidth,
+ iface->conf->vht_oper_centr_freq_seg0_idx,
+ iface->conf->vht_oper_centr_freq_seg1_idx)) {
wpa_printf(MSG_DEBUG, "DFS start_dfs_cac() failed");
return -1;
}
@@ -542,81 +593,119 @@
}
-int hostapd_dfs_complete_cac(struct hostapd_data *hapd, int success, int freq,
+int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
int ht_enabled, int chan_offset, int chan_width,
int cf1, int cf2)
{
+ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_COMPLETED
+ "success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
+ success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
+
if (success) {
/* Complete iface/ap configuration */
- set_dfs_state(hapd, freq, ht_enabled, chan_offset,
+ set_dfs_state(iface, freq, ht_enabled, chan_offset,
chan_width, cf1, cf2,
HOSTAPD_CHAN_DFS_AVAILABLE);
- hapd->cac_started = 0;
- hostapd_setup_interface_complete(hapd->iface, 0);
+ iface->cac_started = 0;
+ hostapd_setup_interface_complete(iface, 0);
}
return 0;
}
-static int hostapd_dfs_start_channel_switch(struct hostapd_data *hapd)
+static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
{
struct hostapd_channel_data *channel;
int err = 1;
+ int secondary_channel;
+ u8 vht_oper_centr_freq_seg0_idx;
+ u8 vht_oper_centr_freq_seg1_idx;
wpa_printf(MSG_DEBUG, "%s called", __func__);
- channel = dfs_get_valid_channel(hapd);
+ channel = dfs_get_valid_channel(iface, &secondary_channel,
+ &vht_oper_centr_freq_seg0_idx,
+ &vht_oper_centr_freq_seg1_idx);
if (channel) {
- hapd->iconf->channel = channel->chan;
- hapd->iface->freq = channel->freq;
+ wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
+ channel->chan);
+ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
+ "freq=%d chan=%d sec_chan=%d", channel->freq,
+ channel->chan, secondary_channel);
+
+ iface->freq = channel->freq;
+ iface->conf->channel = channel->chan;
+ iface->conf->secondary_channel = secondary_channel;
+ iface->conf->vht_oper_centr_freq_seg0_idx =
+ vht_oper_centr_freq_seg0_idx;
+ iface->conf->vht_oper_centr_freq_seg1_idx =
+ vht_oper_centr_freq_seg1_idx;
err = 0;
- }
-
- if (!hapd->cac_started) {
- wpa_printf(MSG_DEBUG, "DFS radar detected");
- hapd->driver->stop_ap(hapd->drv_priv);
} else {
- wpa_printf(MSG_DEBUG, "DFS radar detected during CAC");
- hapd->cac_started = 0;
+ wpa_printf(MSG_ERROR, "No valid channel available");
}
- hostapd_setup_interface_complete(hapd->iface, err);
+ if (iface->cac_started) {
+ wpa_printf(MSG_DEBUG, "DFS radar detected during CAC");
+ iface->cac_started = 0;
+ /* FIXME: Wait for channel(s) to become available if no channel
+ * has been found */
+ hostapd_setup_interface_complete(iface, err);
+ return err;
+ }
+
+ if (err) {
+ /* FIXME: Wait for channel(s) to become available */
+ hostapd_disable_iface(iface);
+ return err;
+ }
+
+ wpa_printf(MSG_DEBUG, "DFS radar detected");
+ hostapd_disable_iface(iface);
+ hostapd_enable_iface(iface);
return 0;
}
-int hostapd_dfs_radar_detected(struct hostapd_data *hapd, int freq,
+int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
int ht_enabled, int chan_offset, int chan_width,
int cf1, int cf2)
{
int res;
- if (!hapd->iconf->ieee80211h)
+ if (!iface->conf->ieee80211h)
return 0;
+ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED
+ "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
+ freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
+
/* mark radar frequency as invalid */
- res = set_dfs_state(hapd, freq, ht_enabled, chan_offset,
+ res = set_dfs_state(iface, freq, ht_enabled, chan_offset,
chan_width, cf1, cf2,
HOSTAPD_CHAN_DFS_UNAVAILABLE);
/* Skip if reported radar event not overlapped our channels */
- res = dfs_are_channels_overlapped(hapd, freq, chan_width, cf1, cf2);
+ res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2);
if (!res)
return 0;
/* radar detected while operating, switch the channel. */
- res = hostapd_dfs_start_channel_switch(hapd);
+ res = hostapd_dfs_start_channel_switch(iface);
return res;
}
-int hostapd_dfs_nop_finished(struct hostapd_data *hapd, int freq,
+int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
int ht_enabled, int chan_offset, int chan_width,
int cf1, int cf2)
{
+ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NOP_FINISHED
+ "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
+ freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
/* TODO add correct implementation here */
- set_dfs_state(hapd, freq, ht_enabled, chan_offset, chan_width, cf1, cf2,
- HOSTAPD_CHAN_DFS_USABLE);
+ set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
+ cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
return 0;
}
diff --git a/src/ap/dfs.h b/src/ap/dfs.h
index c9f0578..859ff79 100644
--- a/src/ap/dfs.h
+++ b/src/ap/dfs.h
@@ -9,16 +9,16 @@
#ifndef DFS_H
#define DFS_H
-int hostapd_handle_dfs(struct hostapd_data *hapd);
+int hostapd_handle_dfs(struct hostapd_iface *iface);
-int hostapd_dfs_complete_cac(struct hostapd_data *hapd, int success, int freq,
+int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
int ht_enabled, int chan_offset, int chan_width,
int cf1, int cf2);
-int hostapd_dfs_radar_detected(struct hostapd_data *hapd, int freq,
+int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
int ht_enabled,
int chan_offset, int chan_width,
int cf1, int cf2);
-int hostapd_dfs_nop_finished(struct hostapd_data *hapd, int freq,
+int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
int ht_enabled,
int chan_offset, int chan_width, int cf1, int cf2);
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index b30da14..0f4b12e 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -799,7 +799,7 @@
struct dfs_event *radar)
{
wpa_printf(MSG_DEBUG, "DFS radar detected on %d MHz", radar->freq);
- hostapd_dfs_radar_detected(hapd, radar->freq, radar->ht_enabled,
+ hostapd_dfs_radar_detected(hapd->iface, radar->freq, radar->ht_enabled,
radar->chan_offset, radar->chan_width,
radar->cf1, radar->cf2);
}
@@ -809,7 +809,7 @@
struct dfs_event *radar)
{
wpa_printf(MSG_DEBUG, "DFS CAC finished on %d MHz", radar->freq);
- hostapd_dfs_complete_cac(hapd, 1, radar->freq, radar->ht_enabled,
+ hostapd_dfs_complete_cac(hapd->iface, 1, radar->freq, radar->ht_enabled,
radar->chan_offset, radar->chan_width,
radar->cf1, radar->cf2);
}
@@ -819,7 +819,7 @@
struct dfs_event *radar)
{
wpa_printf(MSG_DEBUG, "DFS CAC aborted on %d MHz", radar->freq);
- hostapd_dfs_complete_cac(hapd, 0, radar->freq, radar->ht_enabled,
+ hostapd_dfs_complete_cac(hapd->iface, 0, radar->freq, radar->ht_enabled,
radar->chan_offset, radar->chan_width,
radar->cf1, radar->cf2);
}
@@ -829,7 +829,7 @@
struct dfs_event *radar)
{
wpa_printf(MSG_DEBUG, "DFS NOP finished on %d MHz", radar->freq);
- hostapd_dfs_nop_finished(hapd, radar->freq, radar->ht_enabled,
+ hostapd_dfs_nop_finished(hapd->iface, radar->freq, radar->ht_enabled,
radar->chan_offset, radar->chan_width,
radar->cf1, radar->cf2);
}
@@ -1007,6 +1007,7 @@
/* TODO: check this. hostapd_get_hw_features() initializes
* too much stuff. */
/* hostapd_get_hw_features(hapd->iface); */
+ hostapd_channel_list_updated(hapd->iface);
break;
#endif /* NEED_AP_MLME */
default:
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 3bca385..5d51c77 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -1,6 +1,6 @@
/*
* hostapd / Initialization and configuration
- * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -11,6 +11,7 @@
#include "utils/common.h"
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
#include "radius/radius_client.h"
#include "radius/radius_das.h"
#include "drivers/driver.h"
@@ -38,6 +39,8 @@
static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd);
static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd);
+static int setup_interface2(struct hostapd_iface *iface);
+static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx);
extern int wpa_debug_level;
extern struct wpa_driver_ops *wpa_drivers[];
@@ -62,10 +65,22 @@
static void hostapd_reload_bss(struct hostapd_data *hapd)
{
+ struct hostapd_ssid *ssid;
+
#ifndef CONFIG_NO_RADIUS
radius_client_reconfig(hapd->radius, hapd->conf->radius);
#endif /* CONFIG_NO_RADIUS */
+ ssid = &hapd->conf->ssid;
+ if (!ssid->wpa_psk_set && ssid->wpa_psk && !ssid->wpa_psk->next &&
+ ssid->wpa_passphrase_set && ssid->wpa_passphrase) {
+ /*
+ * Force PSK to be derived again since SSID or passphrase may
+ * have changed.
+ */
+ os_free(ssid->wpa_psk);
+ ssid->wpa_psk = NULL;
+ }
if (hostapd_setup_wpa_psk(hapd->conf)) {
wpa_printf(MSG_ERROR, "Failed to re-configure WPA PSK "
"after reloading configuration");
@@ -160,7 +175,7 @@
for (j = 0; j < iface->num_bss; j++) {
hapd = iface->bss[j];
hapd->iconf = newconf;
- hapd->conf = &newconf->bss[j];
+ hapd->conf = newconf->bss[j];
hostapd_reload_bss(hapd);
}
@@ -245,8 +260,7 @@
authsrv_deinit(hapd);
- if (hapd->interface_added &&
- hostapd_if_remove(hapd, WPA_IF_AP_BSS, hapd->conf->iface)) {
+ if (hostapd_if_remove(hapd, WPA_IF_AP_BSS, hapd->conf->iface)) {
wpa_printf(MSG_WARNING, "Failed to remove BSS interface %s",
hapd->conf->iface);
}
@@ -326,6 +340,8 @@
*/
static void hostapd_cleanup_iface(struct hostapd_iface *iface)
{
+ eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
+
hostapd_cleanup_iface_partial(iface);
hostapd_config_free(iface->conf);
iface->conf = NULL;
@@ -430,7 +446,7 @@
/* Determine the bits necessary to any configured BSSIDs,
if they are higher than the number of BSSIDs. */
for (j = 0; j < iface->conf->num_bss; j++) {
- if (hostapd_mac_comp_empty(iface->conf->bss[j].bssid) == 0) {
+ if (hostapd_mac_comp_empty(iface->conf->bss[j]->bssid) == 0) {
if (j)
auto_addr++;
continue;
@@ -438,7 +454,7 @@
for (i = 0; i < ETH_ALEN; i++) {
mask[i] |=
- iface->conf->bss[j].bssid[i] ^
+ iface->conf->bss[j]->bssid[i] ^
hapd->own_addr[i];
}
}
@@ -503,7 +519,7 @@
size_t i;
for (i = 0; i < conf->num_bss; i++) {
- if (hostapd_mac_comp(conf->bss[i].bssid, a) == 0) {
+ if (hostapd_mac_comp(conf->bss[i]->bssid, a) == 0) {
return 1;
}
}
@@ -597,7 +613,8 @@
/**
* hostapd_setup_bss - Per-BSS setup (initialization)
* @hapd: Pointer to BSS data
- * @first: Whether this BSS is the first BSS of an interface
+ * @first: Whether this BSS is the first BSS of an interface; -1 = not first,
+ * but interface may exist
*
* This function is used to initialize all per-BSS data structures and
* resources. This gets called in a loop for each BSS when an interface is
@@ -612,7 +629,7 @@
char force_ifname[IFNAMSIZ];
u8 if_addr[ETH_ALEN];
- if (!first) {
+ if (!first || first == -1) {
if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0) {
/* Allocate the next available BSSID. */
do {
@@ -632,12 +649,11 @@
}
}
- hapd->interface_added = 1;
if (hostapd_if_add(hapd->iface->bss[0], WPA_IF_AP_BSS,
hapd->conf->iface, hapd->own_addr, hapd,
&hapd->drv_priv, force_ifname, if_addr,
hapd->conf->bridge[0] ? hapd->conf->bridge :
- NULL)) {
+ NULL, first == -1)) {
wpa_printf(MSG_ERROR, "Failed to add BSS (BSSID="
MACSTR ")", MAC2STR(hapd->own_addr));
return -1;
@@ -769,14 +785,14 @@
wpa_printf(MSG_ERROR, "GAS server initialization failed");
return -1;
}
-#endif /* CONFIG_INTERWORKING */
- if (hapd->iface->interfaces &&
- hapd->iface->interfaces->ctrl_iface_init &&
- hapd->iface->interfaces->ctrl_iface_init(hapd)) {
- wpa_printf(MSG_ERROR, "Failed to setup control interface");
+ if (conf->qos_map_set_len &&
+ hostapd_drv_set_qos_map(hapd, conf->qos_map_set,
+ conf->qos_map_set_len)) {
+ wpa_printf(MSG_ERROR, "Failed to initialize QoS Map");
return -1;
}
+#endif /* CONFIG_INTERWORKING */
if (!hostapd_drv_none(hapd) && vlan_init(hapd)) {
wpa_printf(MSG_ERROR, "VLAN initialization failed.");
@@ -850,14 +866,15 @@
if (hapd->iface->drv_max_acl_mac_addrs == 0)
return;
- if (!(conf->bss->num_accept_mac || conf->bss->num_deny_mac))
+ if (!(conf->bss[0]->num_accept_mac || conf->bss[0]->num_deny_mac))
return;
- if (conf->bss->macaddr_acl == DENY_UNLESS_ACCEPTED) {
- if (conf->bss->num_accept_mac) {
+ if (conf->bss[0]->macaddr_acl == DENY_UNLESS_ACCEPTED) {
+ if (conf->bss[0]->num_accept_mac) {
accept_acl = 1;
- err = hostapd_set_acl_list(hapd, conf->bss->accept_mac,
- conf->bss->num_accept_mac,
+ err = hostapd_set_acl_list(hapd,
+ conf->bss[0]->accept_mac,
+ conf->bss[0]->num_accept_mac,
accept_acl);
if (err) {
wpa_printf(MSG_DEBUG, "Failed to set accept acl");
@@ -866,11 +883,11 @@
} else {
wpa_printf(MSG_DEBUG, "Mismatch between ACL Policy & Accept/deny lists file");
}
- } else if (conf->bss->macaddr_acl == ACCEPT_UNLESS_DENIED) {
- if (conf->bss->num_deny_mac) {
+ } else if (conf->bss[0]->macaddr_acl == ACCEPT_UNLESS_DENIED) {
+ if (conf->bss[0]->num_deny_mac) {
accept_acl = 0;
- err = hostapd_set_acl_list(hapd, conf->bss->deny_mac,
- conf->bss->num_deny_mac,
+ err = hostapd_set_acl_list(hapd, conf->bss[0]->deny_mac,
+ conf->bss[0]->num_deny_mac,
accept_acl);
if (err) {
wpa_printf(MSG_DEBUG, "Failed to set deny acl");
@@ -883,11 +900,85 @@
}
+static int start_ctrl_iface_bss(struct hostapd_data *hapd)
+{
+ if (!hapd->iface->interfaces ||
+ !hapd->iface->interfaces->ctrl_iface_init)
+ return 0;
+
+ if (hapd->iface->interfaces->ctrl_iface_init(hapd)) {
+ wpa_printf(MSG_ERROR,
+ "Failed to setup control interface for %s",
+ hapd->conf->iface);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int start_ctrl_iface(struct hostapd_iface *iface)
+{
+ size_t i;
+
+ if (!iface->interfaces || !iface->interfaces->ctrl_iface_init)
+ return 0;
+
+ for (i = 0; i < iface->num_bss; i++) {
+ struct hostapd_data *hapd = iface->bss[i];
+ if (iface->interfaces->ctrl_iface_init(hapd)) {
+ wpa_printf(MSG_ERROR,
+ "Failed to setup control interface for %s",
+ hapd->conf->iface);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_iface *iface = eloop_ctx;
+
+ if (!iface->wait_channel_update) {
+ wpa_printf(MSG_INFO, "Channel list update timeout, but interface was not waiting for it");
+ return;
+ }
+
+ /*
+ * It is possible that the existing channel list is acceptable, so try
+ * to proceed.
+ */
+ wpa_printf(MSG_DEBUG, "Channel list update timeout - try to continue anyway");
+ setup_interface2(iface);
+}
+
+
+void hostapd_channel_list_updated(struct hostapd_iface *iface)
+{
+ if (!iface->wait_channel_update)
+ return;
+
+ wpa_printf(MSG_DEBUG, "Channel list updated - continue setup");
+ eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
+ setup_interface2(iface);
+}
+
+
static int setup_interface(struct hostapd_iface *iface)
{
struct hostapd_data *hapd = iface->bss[0];
size_t i;
- char country[4];
+
+ if (!iface->phy[0]) {
+ const char *phy = hostapd_drv_get_radio_name(hapd);
+ if (phy) {
+ wpa_printf(MSG_DEBUG, "phy: %s", phy);
+ os_strlcpy(iface->phy, phy, sizeof(iface->phy));
+ }
+ }
/*
* Make sure that all BSSes get configured with a pointer to the same
@@ -901,15 +992,49 @@
if (hostapd_validate_bssid_configuration(iface))
return -1;
+ /*
+ * Initialize control interfaces early to allow external monitoring of
+ * channel setup operations that may take considerable amount of time
+ * especially for DFS cases.
+ */
+ if (start_ctrl_iface(iface))
+ return -1;
+
if (hapd->iconf->country[0] && hapd->iconf->country[1]) {
+ char country[4], previous_country[4];
+
+ hostapd_set_state(iface, HAPD_IFACE_COUNTRY_UPDATE);
+ if (hostapd_get_country(hapd, previous_country) < 0)
+ previous_country[0] = '\0';
+
os_memcpy(country, hapd->iconf->country, 3);
country[3] = '\0';
if (hostapd_set_country(hapd, country) < 0) {
wpa_printf(MSG_ERROR, "Failed to set country code");
return -1;
}
+
+ wpa_printf(MSG_DEBUG, "Previous country code %s, new country code %s",
+ previous_country, country);
+
+ if (os_strncmp(previous_country, country, 2) != 0) {
+ wpa_printf(MSG_DEBUG, "Continue interface setup after channel list update");
+ iface->wait_channel_update = 1;
+ eloop_register_timeout(1, 0,
+ channel_list_update_timeout,
+ iface, NULL);
+ return 0;
+ }
}
+ return setup_interface2(iface);
+}
+
+
+static int setup_interface2(struct hostapd_iface *iface)
+{
+ iface->wait_channel_update = 0;
+
if (hostapd_get_hw_features(iface)) {
/* Not all drivers support this yet, so continue without hw
* feature data. */
@@ -940,6 +1065,14 @@
}
+/**
+ * hostapd_setup_interface_complete - Complete interface setup
+ *
+ * This function is called when previous steps in the interface setup has been
+ * completed. This can also start operations, e.g., DFS, that will require
+ * additional processing before interface is ready to be enabled. Such
+ * operations will call this function from eloop callbacks when finished.
+ */
int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
{
struct hostapd_data *hapd = iface->bss[0];
@@ -948,25 +1081,26 @@
if (err) {
wpa_printf(MSG_ERROR, "Interface initialization failed");
+ hostapd_set_state(iface, HAPD_IFACE_DISABLED);
eloop_terminate();
return -1;
}
wpa_printf(MSG_DEBUG, "Completing interface initialization");
- if (hapd->iconf->channel) {
+ if (iface->conf->channel) {
#ifdef NEED_AP_MLME
int res;
#endif /* NEED_AP_MLME */
- iface->freq = hostapd_hw_get_freq(hapd, hapd->iconf->channel);
+ iface->freq = hostapd_hw_get_freq(hapd, iface->conf->channel);
wpa_printf(MSG_DEBUG, "Mode: %s Channel: %d "
"Frequency: %d MHz",
- hostapd_hw_mode_txt(hapd->iconf->hw_mode),
- hapd->iconf->channel, iface->freq);
+ hostapd_hw_mode_txt(iface->conf->hw_mode),
+ iface->conf->channel, iface->freq);
#ifdef NEED_AP_MLME
/* Check DFS */
- res = hostapd_handle_dfs(hapd);
+ res = hostapd_handle_dfs(iface);
if (res <= 0)
return res;
#endif /* NEED_AP_MLME */
@@ -1021,6 +1155,7 @@
if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0)
prev_addr = hapd->own_addr;
}
+ hapd = iface->bss[0];
hostapd_tx_queue_params(iface);
@@ -1045,6 +1180,8 @@
return -1;
}
+ hostapd_set_state(iface, HAPD_IFACE_ENABLED);
+ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_ENABLED);
if (hapd->setup_complete_cb)
hapd->setup_complete_cb(hapd->setup_complete_cb_ctx);
@@ -1064,6 +1201,12 @@
* and sets driver parameters based on the configuration.
* Flushes old stations, sets the channel, encryption,
* beacons, and WDS links based on the configuration.
+ *
+ * If interface setup requires more time, e.g., to perform HT co-ex scans, ACS,
+ * or DFS operations, this function returns 0 before such operations have been
+ * completed. The pending operations are registered into eloop and will be
+ * completed from eloop callbacks. Those callbacks end up calling
+ * hostapd_setup_interface_complete() once setup has been completed.
*/
int hostapd_setup_interface(struct hostapd_iface *iface)
{
@@ -1115,13 +1258,16 @@
void hostapd_interface_deinit(struct hostapd_iface *iface)
{
- size_t j;
+ int j;
if (iface == NULL)
return;
+ eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
+ iface->wait_channel_update = 0;
+
hostapd_cleanup_iface_pre(iface);
- for (j = 0; j < iface->num_bss; j++) {
+ for (j = iface->num_bss - 1; j >= 0; j--) {
struct hostapd_data *hapd = iface->bss[j];
hostapd_free_stas(hapd);
hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
@@ -1140,7 +1286,200 @@
}
-#ifdef HOSTAPD
+/**
+ * hostapd_init - Allocate and initialize per-interface data
+ * @config_file: Path to the configuration file
+ * Returns: Pointer to the allocated interface data or %NULL on failure
+ *
+ * This function is used to allocate main data structures for per-interface
+ * data. The allocated data buffer will be freed by calling
+ * hostapd_cleanup_iface().
+ */
+struct hostapd_iface * hostapd_init(struct hapd_interfaces *interfaces,
+ const char *config_file)
+{
+ struct hostapd_iface *hapd_iface = NULL;
+ struct hostapd_config *conf = NULL;
+ struct hostapd_data *hapd;
+ size_t i;
+
+ hapd_iface = os_zalloc(sizeof(*hapd_iface));
+ if (hapd_iface == NULL)
+ goto fail;
+
+ hapd_iface->config_fname = os_strdup(config_file);
+ if (hapd_iface->config_fname == NULL)
+ goto fail;
+
+ conf = interfaces->config_read_cb(hapd_iface->config_fname);
+ if (conf == NULL)
+ goto fail;
+ hapd_iface->conf = conf;
+
+ hapd_iface->num_bss = conf->num_bss;
+ hapd_iface->bss = os_calloc(conf->num_bss,
+ sizeof(struct hostapd_data *));
+ if (hapd_iface->bss == NULL)
+ goto fail;
+
+ for (i = 0; i < conf->num_bss; i++) {
+ hapd = hapd_iface->bss[i] =
+ hostapd_alloc_bss_data(hapd_iface, conf,
+ conf->bss[i]);
+ if (hapd == NULL)
+ goto fail;
+ hapd->msg_ctx = hapd;
+ }
+
+ return hapd_iface;
+
+fail:
+ wpa_printf(MSG_ERROR, "Failed to set up interface with %s",
+ config_file);
+ if (conf)
+ hostapd_config_free(conf);
+ if (hapd_iface) {
+ os_free(hapd_iface->config_fname);
+ os_free(hapd_iface->bss);
+ os_free(hapd_iface);
+ }
+ return NULL;
+}
+
+
+static int ifname_in_use(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 1;
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ * hostapd_interface_init_bss - Read configuration file and init BSS data
+ *
+ * This function is used to parse configuration file for a BSS. This BSS is
+ * added to an existing interface sharing the same radio (if any) or a new
+ * interface is created if this is the first interface on a radio. This
+ * allocate memory for the BSS. No actual driver operations are started.
+ *
+ * This is similar to hostapd_interface_init(), but for a case where the
+ * configuration is used to add a single BSS instead of all BSSes for a radio.
+ */
+struct hostapd_iface *
+hostapd_interface_init_bss(struct hapd_interfaces *interfaces, const char *phy,
+ const char *config_fname, int debug)
+{
+ struct hostapd_iface *new_iface = NULL, *iface = NULL;
+ struct hostapd_data *hapd;
+ int k;
+ size_t i, bss_idx;
+
+ if (!phy || !*phy)
+ return NULL;
+
+ for (i = 0; i < interfaces->count; i++) {
+ if (os_strcmp(interfaces->iface[i]->phy, phy) == 0) {
+ iface = interfaces->iface[i];
+ break;
+ }
+ }
+
+ wpa_printf(MSG_INFO, "Configuration file: %s (phy %s)%s",
+ config_fname, phy, iface ? "" : " --> new PHY");
+ if (iface) {
+ struct hostapd_config *conf;
+ struct hostapd_bss_config **tmp_conf;
+ struct hostapd_data **tmp_bss;
+ struct hostapd_bss_config *bss;
+ const char *ifname;
+
+ /* Add new BSS to existing iface */
+ conf = interfaces->config_read_cb(config_fname);
+ if (conf == NULL)
+ return NULL;
+ if (conf->num_bss > 1) {
+ wpa_printf(MSG_ERROR, "Multiple BSSes specified in BSS-config");
+ hostapd_config_free(conf);
+ return NULL;
+ }
+
+ ifname = conf->bss[0]->iface;
+ if (ifname[0] != '\0' && ifname_in_use(interfaces, ifname)) {
+ wpa_printf(MSG_ERROR,
+ "Interface name %s already in use", ifname);
+ hostapd_config_free(conf);
+ return NULL;
+ }
+
+ tmp_conf = os_realloc_array(
+ iface->conf->bss, iface->conf->num_bss + 1,
+ sizeof(struct hostapd_bss_config *));
+ tmp_bss = os_realloc_array(iface->bss, iface->num_bss + 1,
+ sizeof(struct hostapd_data *));
+ if (tmp_bss)
+ iface->bss = tmp_bss;
+ if (tmp_conf) {
+ iface->conf->bss = tmp_conf;
+ iface->conf->last_bss = tmp_conf[0];
+ }
+ if (tmp_bss == NULL || tmp_conf == NULL) {
+ hostapd_config_free(conf);
+ return NULL;
+ }
+ bss = iface->conf->bss[iface->conf->num_bss] = conf->bss[0];
+ iface->conf->num_bss++;
+
+ hapd = hostapd_alloc_bss_data(iface, iface->conf, bss);
+ if (hapd == NULL) {
+ iface->conf->num_bss--;
+ hostapd_config_free(conf);
+ return NULL;
+ }
+ iface->conf->last_bss = bss;
+ iface->bss[iface->num_bss] = hapd;
+ hapd->msg_ctx = hapd;
+
+ bss_idx = iface->num_bss++;
+ conf->num_bss--;
+ conf->bss[0] = NULL;
+ hostapd_config_free(conf);
+ } else {
+ /* Add a new iface with the first BSS */
+ new_iface = iface = hostapd_init(interfaces, config_fname);
+ if (!iface)
+ return NULL;
+ os_strlcpy(iface->phy, phy, sizeof(iface->phy));
+ iface->interfaces = interfaces;
+ bss_idx = 0;
+ }
+
+ for (k = 0; k < debug; k++) {
+ if (iface->bss[bss_idx]->conf->logger_stdout_level > 0)
+ iface->bss[bss_idx]->conf->logger_stdout_level--;
+ }
+
+ if (iface->conf->bss[bss_idx]->iface[0] == '\0' &&
+ !hostapd_drv_none(iface->bss[bss_idx])) {
+ wpa_printf(MSG_ERROR, "Interface name not specified in %s",
+ config_fname);
+ if (new_iface)
+ hostapd_interface_deinit_free(new_iface);
+ return NULL;
+ }
+
+ return iface;
+}
+
void hostapd_interface_deinit_free(struct hostapd_iface *iface)
{
@@ -1161,20 +1500,31 @@
{
if (hapd_iface->bss[0]->drv_priv != NULL) {
wpa_printf(MSG_ERROR, "Interface %s already enabled",
- hapd_iface->conf->bss[0].iface);
+ hapd_iface->conf->bss[0]->iface);
return -1;
}
wpa_printf(MSG_DEBUG, "Enable interface %s",
- hapd_iface->conf->bss[0].iface);
+ hapd_iface->conf->bss[0]->iface);
if (hapd_iface->interfaces == NULL ||
hapd_iface->interfaces->driver_init == NULL ||
- hapd_iface->interfaces->driver_init(hapd_iface) ||
- hostapd_setup_interface(hapd_iface)) {
- hostapd_interface_deinit_free(hapd_iface);
+ hapd_iface->interfaces->driver_init(hapd_iface))
+ return -1;
+
+ if (hostapd_setup_interface(hapd_iface)) {
+ const struct wpa_driver_ops *driver;
+ void *drv_priv;
+
+ driver = hapd_iface->bss[0]->driver;
+ drv_priv = hapd_iface->bss[0]->drv_priv;
+ if (driver && driver->hapd_deinit && drv_priv) {
+ driver->hapd_deinit(drv_priv);
+ hapd_iface->bss[0]->drv_priv = NULL;
+ }
return -1;
}
+
return 0;
}
@@ -1184,19 +1534,17 @@
size_t j;
wpa_printf(MSG_DEBUG, "Reload interface %s",
- hapd_iface->conf->bss[0].iface);
- for (j = 0; j < hapd_iface->num_bss; j++) {
- hostapd_flush_old_stations(hapd_iface->bss[j],
- WLAN_REASON_PREV_AUTH_NOT_VALID);
-
-#ifndef CONFIG_NO_RADIUS
- /* TODO: update dynamic data based on changed configuration
- * items (e.g., open/close sockets, etc.) */
- radius_client_flush(hapd_iface->bss[j]->radius, 0);
-#endif /* CONFIG_NO_RADIUS */
-
- hostapd_reload_bss(hapd_iface->bss[j]);
+ hapd_iface->conf->bss[0]->iface);
+ for (j = 0; j < hapd_iface->num_bss; j++)
+ hostapd_set_security_params(hapd_iface->conf->bss[j]);
+ if (hostapd_config_check(hapd_iface->conf) < 0) {
+ wpa_printf(MSG_ERROR, "Updated configuration is invalid");
+ return -1;
}
+ hostapd_clear_old(hapd_iface);
+ for (j = 0; j < hapd_iface->num_bss; j++)
+ hostapd_reload_bss(hapd_iface->bss[j]);
+
return 0;
}
@@ -1209,6 +1557,7 @@
if (hapd_iface == NULL)
return -1;
+ wpa_msg(hapd_iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
driver = hapd_iface->bss[0]->driver;
drv_priv = hapd_iface->bss[0]->drv_priv;
@@ -1233,6 +1582,7 @@
wpa_printf(MSG_DEBUG, "Interface %s disabled",
hapd_iface->bss[0]->conf->iface);
+ hostapd_set_state(hapd_iface, HAPD_IFACE_DISABLED);
return 0;
}
@@ -1283,7 +1633,7 @@
return NULL;
}
- bss = conf->last_bss = conf->bss;
+ bss = conf->last_bss = conf->bss[0];
os_strlcpy(bss->iface, ifname, sizeof(bss->iface));
bss->ctrl_interface = os_strdup(ctrl_iface);
@@ -1318,8 +1668,7 @@
for (i = 0; i < conf->num_bss; i++) {
hapd = hapd_iface->bss[i] =
- hostapd_alloc_bss_data(hapd_iface, conf,
- &conf->bss[i]);
+ hostapd_alloc_bss_data(hapd_iface, conf, conf->bss[i]);
if (hapd == NULL)
return NULL;
hapd->msg_ctx = hapd;
@@ -1334,10 +1683,69 @@
int hostapd_add_iface(struct hapd_interfaces *interfaces, char *buf)
{
struct hostapd_config *conf = NULL;
- struct hostapd_iface *hapd_iface = NULL;
+ struct hostapd_iface *hapd_iface = NULL, *new_iface = NULL;
+ struct hostapd_data *hapd;
char *ptr;
- size_t i;
- const char *conf_file = NULL;
+ size_t i, j;
+ const char *conf_file = NULL, *phy_name = NULL;
+
+ if (os_strncmp(buf, "bss_config=", 11) == 0) {
+ char *pos;
+ phy_name = buf + 11;
+ pos = os_strchr(phy_name, ':');
+ if (!pos)
+ return -1;
+ *pos++ = '\0';
+ conf_file = pos;
+ if (!os_strlen(conf_file))
+ return -1;
+
+ hapd_iface = hostapd_interface_init_bss(interfaces, phy_name,
+ conf_file, 0);
+ if (!hapd_iface)
+ return -1;
+ for (j = 0; j < interfaces->count; j++) {
+ if (interfaces->iface[j] == hapd_iface)
+ break;
+ }
+ if (j == interfaces->count) {
+ struct hostapd_iface **tmp;
+ tmp = os_realloc_array(interfaces->iface,
+ interfaces->count + 1,
+ sizeof(struct hostapd_iface *));
+ if (!tmp) {
+ hostapd_interface_deinit_free(hapd_iface);
+ return -1;
+ }
+ interfaces->iface = tmp;
+ interfaces->iface[interfaces->count++] = hapd_iface;
+ new_iface = hapd_iface;
+ }
+
+ if (new_iface) {
+ if (interfaces->driver_init(hapd_iface) ||
+ hostapd_setup_interface(hapd_iface)) {
+ interfaces->count--;
+ goto fail;
+ }
+ } else {
+ /* Assign new BSS with bss[0]'s driver info */
+ hapd = hapd_iface->bss[hapd_iface->num_bss - 1];
+ hapd->driver = hapd_iface->bss[0]->driver;
+ hapd->drv_priv = hapd_iface->bss[0]->drv_priv;
+ os_memcpy(hapd->own_addr, hapd_iface->bss[0]->own_addr,
+ ETH_ALEN);
+
+ if (start_ctrl_iface_bss(hapd) < 0 ||
+ hostapd_setup_bss(hapd, -1)) {
+ hapd_iface->conf->num_bss--;
+ hapd_iface->num_bss--;
+ os_free(hapd);
+ return -1;
+ }
+ }
+ return 0;
+ }
ptr = os_strchr(buf, ' ');
if (ptr == NULL)
@@ -1348,7 +1756,7 @@
conf_file = ptr + 7;
for (i = 0; i < interfaces->count; i++) {
- if (!os_strcmp(interfaces->iface[i]->conf->bss[0].iface,
+ if (!os_strcmp(interfaces->iface[i]->conf->bss[0]->iface,
buf)) {
wpa_printf(MSG_INFO, "Cannot add interface - it "
"already exists");
@@ -1366,8 +1774,8 @@
if (conf_file && interfaces->config_read_cb) {
conf = interfaces->config_read_cb(conf_file);
if (conf && conf->bss)
- os_strlcpy(conf->bss->iface, buf,
- sizeof(conf->bss->iface));
+ os_strlcpy(conf->bss[0]->iface, buf,
+ sizeof(conf->bss[0]->iface));
} else
conf = hostapd_config_alloc(interfaces, buf, ptr);
if (conf == NULL || conf->bss == NULL) {
@@ -1383,14 +1791,10 @@
goto fail;
}
- if (hapd_iface->interfaces &&
- hapd_iface->interfaces->ctrl_iface_init &&
- hapd_iface->interfaces->ctrl_iface_init(hapd_iface->bss[0])) {
- wpa_printf(MSG_ERROR, "%s: Failed to setup control "
- "interface", __func__);
+ if (start_ctrl_iface(hapd_iface) < 0)
goto fail;
- }
- wpa_printf(MSG_INFO, "Add interface '%s'", conf->bss[0].iface);
+
+ wpa_printf(MSG_INFO, "Add interface '%s'", conf->bss[0]->iface);
return 0;
@@ -1398,23 +1802,57 @@
if (conf)
hostapd_config_free(conf);
if (hapd_iface) {
- os_free(hapd_iface->bss[interfaces->count]);
+ if (hapd_iface->bss) {
+ for (i = 0; i < hapd_iface->num_bss; i++)
+ os_free(hapd_iface->bss[i]);
+ os_free(hapd_iface->bss);
+ }
os_free(hapd_iface);
}
return -1;
}
+static int hostapd_remove_bss(struct hostapd_iface *iface, unsigned int idx)
+{
+ struct hostapd_data *hapd;
+ size_t i;
+
+ if (idx > iface->num_bss || idx > iface->conf->num_bss)
+ return -1;
+ hapd = iface->bss[idx];
+ wpa_printf(MSG_INFO, "Remove BSS '%s'", hapd->conf->iface);
+
+ hostapd_free_stas(hapd);
+ hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
+ hostapd_clear_wep(hapd);
+ hostapd_cleanup(hapd);
+ hostapd_config_free_bss(hapd->conf);
+ os_free(hapd);
+
+ iface->num_bss--;
+ for (i = idx; i < iface->num_bss; i++)
+ iface->bss[i] = iface->bss[i + 1];
+
+ iface->conf->num_bss--;
+ for (i = idx; i < iface->num_bss; i++)
+ iface->conf->bss[i] = iface->conf->bss[i + 1];
+
+ return 0;
+}
+
+
int hostapd_remove_iface(struct hapd_interfaces *interfaces, char *buf)
{
struct hostapd_iface *hapd_iface;
- size_t i, k = 0;
+ size_t i, j, k = 0;
for (i = 0; i < interfaces->count; i++) {
hapd_iface = interfaces->iface[i];
if (hapd_iface == NULL)
return -1;
- if (!os_strcmp(hapd_iface->conf->bss[0].iface, buf)) {
+ if (hapd_iface->conf->num_bss == 1 &&
+ !os_strcmp(hapd_iface->conf->bss[0]->iface, buf)) {
wpa_printf(MSG_INFO, "Remove interface '%s'", buf);
hostapd_interface_deinit_free(hapd_iface);
k = i;
@@ -1426,12 +1864,15 @@
interfaces->count--;
return 0;
}
+
+ for (j = 0; j < hapd_iface->conf->num_bss; j++) {
+ if (!os_strcmp(hapd_iface->conf->bss[j]->iface, buf))
+ return hostapd_remove_bss(hapd_iface, j);
+ }
}
return -1;
}
-#endif /* HOSTAPD */
-
/**
* hostapd_new_assoc_sta - Notify that a new station associated with the AP
@@ -1493,3 +1934,35 @@
eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
ap_handle_timer, hapd, sta);
}
+
+
+const char * hostapd_state_text(enum hostapd_iface_state s)
+{
+ switch (s) {
+ case HAPD_IFACE_UNINITIALIZED:
+ return "UNINITIALIZED";
+ case HAPD_IFACE_DISABLED:
+ return "DISABLED";
+ case HAPD_IFACE_COUNTRY_UPDATE:
+ return "COUNTRY_UPDATE";
+ case HAPD_IFACE_ACS:
+ return "ACS";
+ case HAPD_IFACE_HT_SCAN:
+ return "HT_SCAN";
+ case HAPD_IFACE_DFS:
+ return "DFS";
+ case HAPD_IFACE_ENABLED:
+ return "ENABLED";
+ }
+
+ return "UNKNOWN";
+}
+
+
+void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s)
+{
+ wpa_printf(MSG_INFO, "%s: interface state %s->%s",
+ iface->conf->bss[0]->iface, hostapd_state_text(iface->state),
+ hostapd_state_text(s));
+ iface->state = s;
+}
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index d79c3e5..05bcb62 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -1,6 +1,6 @@
/*
* hostapd / Initialization and configuration
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -99,7 +99,6 @@
struct hostapd_iface *iface;
struct hostapd_config *iconf;
struct hostapd_bss_config *conf;
- int interface_added; /* virtual interface added for this BSS */
u8 own_addr[ETH_ALEN];
@@ -152,9 +151,6 @@
int parameter_set_count;
- /* DFS specific parameters */
- int cac_started;
-
/* Time Advertisement */
u8 time_update_counter;
struct wpabuf *time_adv;
@@ -250,10 +246,24 @@
void *owner;
char *config_fname;
struct hostapd_config *conf;
+ char phy[16]; /* Name of the PHY (radio) */
+
+ enum hostapd_iface_state {
+ HAPD_IFACE_UNINITIALIZED,
+ HAPD_IFACE_DISABLED,
+ HAPD_IFACE_COUNTRY_UPDATE,
+ HAPD_IFACE_ACS,
+ HAPD_IFACE_HT_SCAN,
+ HAPD_IFACE_DFS,
+ HAPD_IFACE_ENABLED
+ } state;
size_t num_bss;
struct hostapd_data **bss;
+ unsigned int wait_channel_update:1;
+ unsigned int cac_started:1;
+
int num_ap; /* number of entries in ap_list */
struct ap_info *ap_list; /* AP info list head */
struct ap_info *ap_hash[STA_HASH_SIZE];
@@ -348,6 +358,11 @@
int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err);
void hostapd_interface_deinit(struct hostapd_iface *iface);
void hostapd_interface_free(struct hostapd_iface *iface);
+struct hostapd_iface * hostapd_init(struct hapd_interfaces *interfaces,
+ const char *config_file);
+struct hostapd_iface *
+hostapd_interface_init_bss(struct hapd_interfaces *interfaces, const char *phy,
+ const char *config_fname, int debug);
void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
int reassoc);
void hostapd_interface_deinit_free(struct hostapd_iface *iface);
@@ -356,6 +371,9 @@
int hostapd_disable_iface(struct hostapd_iface *hapd_iface);
int hostapd_add_iface(struct hapd_interfaces *ifaces, char *buf);
int hostapd_remove_iface(struct hapd_interfaces *ifaces, char *buf);
+void hostapd_channel_list_updated(struct hostapd_iface *iface);
+void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s);
+const char * hostapd_state_text(enum hostapd_iface_state s);
/* utils.c */
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index d2831d4..e95e0e1 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -20,6 +20,7 @@
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
+#include "common/wpa_ctrl.h"
#include "drivers/driver.h"
#include "hostapd.h"
#include "ap_config.h"
@@ -531,6 +532,47 @@
}
+static void ieee80211n_scan_channels_5g(struct hostapd_iface *iface,
+ struct wpa_driver_scan_params *params)
+{
+ /* Scan only the affected frequency range */
+ int pri_freq;
+ int affected_start, affected_end;
+ int i, pos;
+ struct hostapd_hw_modes *mode;
+
+ if (iface->current_mode == NULL)
+ return;
+
+ pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
+ if (iface->conf->secondary_channel > 0) {
+ affected_start = pri_freq - 10;
+ affected_end = pri_freq + 30;
+ } else {
+ affected_start = pri_freq - 30;
+ affected_end = pri_freq + 10;
+ }
+ wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
+ affected_start, affected_end);
+
+ mode = iface->current_mode;
+ params->freqs = os_calloc(mode->num_channels + 1, sizeof(int));
+ if (params->freqs == NULL)
+ return;
+ pos = 0;
+
+ for (i = 0; i < mode->num_channels; i++) {
+ struct hostapd_channel_data *chan = &mode->channels[i];
+ if (chan->flag & HOSTAPD_CHAN_DISABLED)
+ continue;
+ if (chan->freq < affected_start ||
+ chan->freq > affected_end)
+ continue;
+ params->freqs[pos++] = chan->freq;
+ }
+}
+
+
static int ieee80211n_check_40mhz(struct hostapd_iface *iface)
{
struct wpa_driver_scan_params params;
@@ -538,11 +580,14 @@
if (!iface->conf->secondary_channel)
return 0; /* HT40 not used */
+ hostapd_set_state(iface, HAPD_IFACE_HT_SCAN);
wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling "
"40 MHz channel");
os_memset(¶ms, 0, sizeof(params));
if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
ieee80211n_scan_channels_2g4(iface, ¶ms);
+ else
+ ieee80211n_scan_channels_5g(iface, ¶ms);
if (hostapd_driver_scan(iface->bss[0], ¶ms) < 0) {
wpa_printf(MSG_ERROR, "Failed to request a scan of "
"neighboring BSSes");
@@ -857,14 +902,21 @@
switch (hostapd_check_chans(iface)) {
case HOSTAPD_CHAN_VALID:
+ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO,
+ ACS_EVENT_COMPLETED "freq=%d channel=%d",
+ hostapd_hw_get_freq(iface->bss[0],
+ iface->conf->channel),
+ iface->conf->channel);
break;
case HOSTAPD_CHAN_ACS:
wpa_printf(MSG_ERROR, "ACS error - reported complete, but no result available");
+ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_FAILED);
hostapd_notify_bad_chans(iface);
goto out;
case HOSTAPD_CHAN_INVALID:
default:
wpa_printf(MSG_ERROR, "ACS picked unusable channels");
+ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_FAILED);
hostapd_notify_bad_chans(iface);
goto out;
}
diff --git a/src/ap/iapp.c b/src/ap/iapp.c
index be55c69..bad080f 100644
--- a/src/ap/iapp.c
+++ b/src/ap/iapp.c
@@ -204,7 +204,7 @@
addr.sin_port = htons(IAPP_UDP_PORT);
if (sendto(iapp->udp_sock, buf, (char *) (add + 1) - buf, 0,
(struct sockaddr *) &addr, sizeof(addr)) < 0)
- perror("sendto[IAPP-ADD]");
+ wpa_printf(MSG_INFO, "sendto[IAPP-ADD]: %s", strerror(errno));
}
@@ -231,7 +231,7 @@
* FIX: what is correct RW with 802.11? */
if (send(iapp->packet_sock, &msg, sizeof(msg), 0) < 0)
- perror("send[L2 Update]");
+ wpa_printf(MSG_INFO, "send[L2 Update]: %s", strerror(errno));
}
@@ -276,8 +276,8 @@
struct sta_info *sta;
if (len != sizeof(*add)) {
- printf("Invalid IAPP-ADD packet length %d (expected %lu)\n",
- len, (unsigned long) sizeof(*add));
+ wpa_printf(MSG_INFO, "Invalid IAPP-ADD packet length %d (expected %lu)",
+ len, (unsigned long) sizeof(*add));
return;
}
@@ -326,7 +326,8 @@
len = recvfrom(iapp->udp_sock, buf, sizeof(buf), 0,
(struct sockaddr *) &from, &fromlen);
if (len < 0) {
- perror("recvfrom");
+ wpa_printf(MSG_INFO, "iapp_receive_udp - recvfrom: %s",
+ strerror(errno));
return;
}
@@ -350,17 +351,18 @@
hdr->version, hdr->command,
be_to_host16(hdr->identifier), hlen);
if (hdr->version != IAPP_VERSION) {
- printf("Dropping IAPP frame with unknown version %d\n",
- hdr->version);
+ wpa_printf(MSG_INFO, "Dropping IAPP frame with unknown version %d",
+ hdr->version);
return;
}
if (hlen > len) {
- printf("Underflow IAPP frame (hlen=%d len=%d)\n", hlen, len);
+ wpa_printf(MSG_INFO, "Underflow IAPP frame (hlen=%d len=%d)",
+ hlen, len);
return;
}
if (hlen < len) {
- printf("Ignoring %d extra bytes from IAPP frame\n",
- len - hlen);
+ wpa_printf(MSG_INFO, "Ignoring %d extra bytes from IAPP frame",
+ len - hlen);
len = hlen;
}
@@ -376,7 +378,7 @@
/* TODO: process */
break;
default:
- printf("Unknown IAPP command %d\n", hdr->command);
+ wpa_printf(MSG_INFO, "Unknown IAPP command %d", hdr->command);
break;
}
}
@@ -403,7 +405,8 @@
iapp->udp_sock = socket(PF_INET, SOCK_DGRAM, 0);
if (iapp->udp_sock < 0) {
- perror("socket[PF_INET,SOCK_DGRAM]");
+ wpa_printf(MSG_INFO, "iapp_init - socket[PF_INET,SOCK_DGRAM]: %s",
+ strerror(errno));
iapp_deinit(iapp);
return NULL;
}
@@ -411,35 +414,38 @@
os_memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
if (ioctl(iapp->udp_sock, SIOCGIFINDEX, &ifr) != 0) {
- perror("ioctl(SIOCGIFINDEX)");
+ wpa_printf(MSG_INFO, "iapp_init - ioctl(SIOCGIFINDEX): %s",
+ strerror(errno));
iapp_deinit(iapp);
return NULL;
}
ifindex = ifr.ifr_ifindex;
if (ioctl(iapp->udp_sock, SIOCGIFADDR, &ifr) != 0) {
- perror("ioctl(SIOCGIFADDR)");
+ wpa_printf(MSG_INFO, "iapp_init - ioctl(SIOCGIFADDR): %s",
+ strerror(errno));
iapp_deinit(iapp);
return NULL;
}
paddr = (struct sockaddr_in *) &ifr.ifr_addr;
if (paddr->sin_family != AF_INET) {
- printf("Invalid address family %i (SIOCGIFADDR)\n",
- paddr->sin_family);
+ wpa_printf(MSG_INFO, "IAPP: Invalid address family %i (SIOCGIFADDR)",
+ paddr->sin_family);
iapp_deinit(iapp);
return NULL;
}
iapp->own.s_addr = paddr->sin_addr.s_addr;
if (ioctl(iapp->udp_sock, SIOCGIFBRDADDR, &ifr) != 0) {
- perror("ioctl(SIOCGIFBRDADDR)");
+ wpa_printf(MSG_INFO, "iapp_init - ioctl(SIOCGIFBRDADDR): %s",
+ strerror(errno));
iapp_deinit(iapp);
return NULL;
}
paddr = (struct sockaddr_in *) &ifr.ifr_addr;
if (paddr->sin_family != AF_INET) {
- printf("Invalid address family %i (SIOCGIFBRDADDR)\n",
- paddr->sin_family);
+ wpa_printf(MSG_INFO, "Invalid address family %i (SIOCGIFBRDADDR)",
+ paddr->sin_family);
iapp_deinit(iapp);
return NULL;
}
@@ -450,7 +456,8 @@
uaddr.sin_port = htons(IAPP_UDP_PORT);
if (bind(iapp->udp_sock, (struct sockaddr *) &uaddr,
sizeof(uaddr)) < 0) {
- perror("bind[UDP]");
+ wpa_printf(MSG_INFO, "iapp_init - bind[UDP]: %s",
+ strerror(errno));
iapp_deinit(iapp);
return NULL;
}
@@ -461,14 +468,16 @@
mreq.imr_ifindex = 0;
if (setsockopt(iapp->udp_sock, SOL_IP, IP_ADD_MEMBERSHIP, &mreq,
sizeof(mreq)) < 0) {
- perror("setsockopt[UDP,IP_ADD_MEMBERSHIP]");
+ wpa_printf(MSG_INFO, "iapp_init - setsockopt[UDP,IP_ADD_MEMBERSHIP]: %s",
+ strerror(errno));
iapp_deinit(iapp);
return NULL;
}
iapp->packet_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (iapp->packet_sock < 0) {
- perror("socket[PF_PACKET,SOCK_RAW]");
+ wpa_printf(MSG_INFO, "iapp_init - socket[PF_PACKET,SOCK_RAW]: %s",
+ strerror(errno));
iapp_deinit(iapp);
return NULL;
}
@@ -478,19 +487,20 @@
addr.sll_ifindex = ifindex;
if (bind(iapp->packet_sock, (struct sockaddr *) &addr,
sizeof(addr)) < 0) {
- perror("bind[PACKET]");
+ wpa_printf(MSG_INFO, "iapp_init - bind[PACKET]: %s",
+ strerror(errno));
iapp_deinit(iapp);
return NULL;
}
if (eloop_register_read_sock(iapp->udp_sock, iapp_receive_udp,
iapp, NULL)) {
- printf("Could not register read socket for IAPP.\n");
+ wpa_printf(MSG_INFO, "Could not register read socket for IAPP");
iapp_deinit(iapp);
return NULL;
}
- printf("IEEE 802.11F (IAPP) using interface %s\n", iface);
+ wpa_printf(MSG_INFO, "IEEE 802.11F (IAPP) using interface %s", iface);
/* TODO: For levels 2 and 3: send RADIUS Initiate-Request, receive
* RADIUS Initiate-Accept or Initiate-Reject. IAPP port should actually
@@ -515,7 +525,8 @@
mreq.imr_ifindex = 0;
if (setsockopt(iapp->udp_sock, SOL_IP, IP_DROP_MEMBERSHIP,
&mreq, sizeof(mreq)) < 0) {
- perror("setsockopt[UDP,IP_DEL_MEMBERSHIP]");
+ wpa_printf(MSG_INFO, "iapp_deinit - setsockopt[UDP,IP_DEL_MEMBERSHIP]: %s",
+ strerror(errno));
}
eloop_unregister_read_sock(iapp->udp_sock);
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index c7db7f4..d553caa 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -286,7 +286,7 @@
MAC2STR(dst), auth_alg, auth_transaction,
resp, (unsigned long) ies_len);
if (hostapd_drv_send_mlme(hapd, reply, rlen, 0) < 0)
- perror("send_auth_reply: send");
+ wpa_printf(MSG_INFO, "send_auth_reply: send");
os_free(buf);
}
@@ -552,8 +552,8 @@
char *radius_cui = NULL;
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
- printf("handle_auth - too short payload (len=%lu)\n",
- (unsigned long) len);
+ wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)",
+ (unsigned long) len);
return;
}
@@ -601,23 +601,23 @@
#endif /* CONFIG_SAE */
((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) &&
auth_alg == WLAN_AUTH_SHARED_KEY))) {
- printf("Unsupported authentication algorithm (%d)\n",
- auth_alg);
+ wpa_printf(MSG_INFO, "Unsupported authentication algorithm (%d)",
+ auth_alg);
resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
goto fail;
}
if (!(auth_transaction == 1 || auth_alg == WLAN_AUTH_SAE ||
(auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 3))) {
- printf("Unknown authentication transaction number (%d)\n",
- auth_transaction);
+ wpa_printf(MSG_INFO, "Unknown authentication transaction number (%d)",
+ auth_transaction);
resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
goto fail;
}
if (os_memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) {
- printf("Station " MACSTR " not allowed to authenticate.\n",
- MAC2STR(mgmt->sa));
+ wpa_printf(MSG_INFO, "Station " MACSTR " not allowed to authenticate",
+ MAC2STR(mgmt->sa));
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto fail;
}
@@ -628,8 +628,8 @@
&psk, &identity, &radius_cui);
if (res == HOSTAPD_ACL_REJECT) {
- printf("Station " MACSTR " not allowed to authenticate.\n",
- MAC2STR(mgmt->sa));
+ wpa_printf(MSG_INFO, "Station " MACSTR " not allowed to authenticate",
+ MAC2STR(mgmt->sa));
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto fail;
}
@@ -1255,8 +1255,8 @@
if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
sizeof(mgmt->u.assoc_req))) {
- printf("handle_assoc(reassoc=%d) - too short payload (len=%lu)"
- "\n", reassoc, (unsigned long) len);
+ wpa_printf(MSG_INFO, "handle_assoc(reassoc=%d) - too short payload (len=%lu)",
+ reassoc, (unsigned long) len);
return;
}
@@ -1442,8 +1442,8 @@
struct sta_info *sta;
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.disassoc)) {
- printf("handle_disassoc - too short payload (len=%lu)\n",
- (unsigned long) len);
+ wpa_printf(MSG_INFO, "handle_disassoc - too short payload (len=%lu)",
+ (unsigned long) len);
return;
}
@@ -1453,8 +1453,8 @@
sta = ap_get_sta(hapd, mgmt->sa);
if (sta == NULL) {
- printf("Station " MACSTR " trying to disassociate, but it "
- "is not associated.\n", MAC2STR(mgmt->sa));
+ wpa_printf(MSG_INFO, "Station " MACSTR " trying to disassociate, but it is not associated",
+ MAC2STR(mgmt->sa));
return;
}
@@ -1528,8 +1528,8 @@
struct ieee802_11_elems elems;
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.beacon)) {
- printf("handle_beacon - too short payload (len=%lu)\n",
- (unsigned long) len);
+ wpa_printf(MSG_INFO, "handle_beacon - too short payload (len=%lu)",
+ (unsigned long) len);
return;
}
@@ -1749,8 +1749,8 @@
stype == WLAN_FC_STYPE_ACTION) &&
#endif /* CONFIG_P2P */
os_memcmp(mgmt->bssid, hapd->own_addr, ETH_ALEN) != 0) {
- printf("MGMT: BSSID=" MACSTR " not our address\n",
- MAC2STR(mgmt->bssid));
+ wpa_printf(MSG_INFO, "MGMT: BSSID=" MACSTR " not our address",
+ MAC2STR(mgmt->bssid));
return;
}
@@ -1817,8 +1817,8 @@
}
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
- printf("handle_auth_cb - too short payload (len=%lu)\n",
- (unsigned long) len);
+ wpa_printf(MSG_INFO, "handle_auth_cb - too short payload (len=%lu)",
+ (unsigned long) len);
return;
}
@@ -1828,8 +1828,8 @@
sta = ap_get_sta(hapd, mgmt->da);
if (!sta) {
- printf("handle_auth_cb: STA " MACSTR " not found\n",
- MAC2STR(mgmt->da));
+ wpa_printf(MSG_INFO, "handle_auth_cb: STA " MACSTR " not found",
+ MAC2STR(mgmt->da));
return;
}
@@ -1879,15 +1879,15 @@
if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) :
sizeof(mgmt->u.assoc_resp))) {
- printf("handle_assoc_cb(reassoc=%d) - too short payload "
- "(len=%lu)\n", reassoc, (unsigned long) len);
+ wpa_printf(MSG_INFO, "handle_assoc_cb(reassoc=%d) - too short payload (len=%lu)",
+ reassoc, (unsigned long) len);
return;
}
sta = ap_get_sta(hapd, mgmt->da);
if (!sta) {
- printf("handle_assoc_cb: STA " MACSTR " not found\n",
- MAC2STR(mgmt->da));
+ wpa_printf(MSG_INFO, "handle_assoc_cb: STA " MACSTR " not found",
+ MAC2STR(mgmt->da));
return;
}
@@ -2103,7 +2103,7 @@
wpa_printf(MSG_DEBUG, "mgmt::action cb");
break;
default:
- printf("unknown mgmt cb frame subtype %d\n", stype);
+ wpa_printf(MSG_INFO, "unknown mgmt cb frame subtype %d", stype);
break;
}
}
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index 4172218..76688b5 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -69,7 +69,7 @@
WLAN_SA_QUERY_TR_ID_LEN);
end = mgmt.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
if (hostapd_drv_send_mlme(hapd, &mgmt, end - (u8 *) &mgmt, 0) < 0)
- perror("ieee802_11_send_sa_query_req: send");
+ wpa_printf(MSG_INFO, "ieee802_11_send_sa_query_req: send failed");
}
@@ -107,7 +107,7 @@
WLAN_SA_QUERY_TR_ID_LEN);
end = resp.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
if (hostapd_drv_send_mlme(hapd, &resp, end - (u8 *) &resp, 0) < 0)
- perror("ieee80211_mgmt_sa_query_request: send");
+ wpa_printf(MSG_INFO, "ieee80211_mgmt_sa_query_request: send failed");
}
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index da6f67c..59241cb 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -453,7 +453,7 @@
msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST,
sm->radius_identifier);
if (msg == NULL) {
- printf("Could not create net RADIUS packet\n");
+ wpa_printf(MSG_INFO, "Could not create new RADIUS packet");
return;
}
@@ -462,7 +462,7 @@
if (sm->identity &&
!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME,
sm->identity, sm->identity_len)) {
- printf("Could not add User-Name\n");
+ wpa_printf(MSG_INFO, "Could not add User-Name");
goto fail;
}
@@ -476,12 +476,12 @@
if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
RADIUS_ATTR_FRAMED_MTU) &&
!radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) {
- printf("Could not add Framed-MTU\n");
+ wpa_printf(MSG_INFO, "Could not add Framed-MTU");
goto fail;
}
if (eap && !radius_msg_add_eap(msg, eap, len)) {
- printf("Could not add EAP-Message\n");
+ wpa_printf(MSG_INFO, "Could not add EAP-Message");
goto fail;
}
@@ -493,8 +493,7 @@
int res = radius_msg_copy_attr(msg, sm->last_recv_radius,
RADIUS_ATTR_STATE);
if (res < 0) {
- printf("Could not copy State attribute from previous "
- "Access-Challenge\n");
+ wpa_printf(MSG_INFO, "Could not copy State attribute from previous Access-Challenge");
goto fail;
}
if (res > 0) {
@@ -544,7 +543,7 @@
data = (u8 *) (eap + 1);
if (len < sizeof(*eap) + 1) {
- printf("handle_eap_response: too short response data\n");
+ wpa_printf(MSG_INFO, "handle_eap_response: too short response data");
return;
}
@@ -572,7 +571,7 @@
u16 eap_len;
if (len < sizeof(*eap)) {
- printf(" too short EAP packet\n");
+ wpa_printf(MSG_INFO, " too short EAP packet");
return;
}
@@ -665,7 +664,7 @@
}
if (len < sizeof(*hdr)) {
- printf(" too short IEEE 802.1X packet\n");
+ wpa_printf(MSG_INFO, " too short IEEE 802.1X packet");
return;
}
@@ -675,7 +674,7 @@
hdr->version, hdr->type, datalen);
if (len - sizeof(*hdr) < datalen) {
- printf(" frame too short for this IEEE 802.1X packet\n");
+ wpa_printf(MSG_INFO, " frame too short for this IEEE 802.1X packet");
if (sta->eapol_sm)
sta->eapol_sm->dot1xAuthEapLengthErrorFramesRx++;
return;
@@ -1277,15 +1276,14 @@
"EAP-Message");
} else if (radius_msg_verify(msg, shared_secret, shared_secret_len,
req, 1)) {
- printf("Incoming RADIUS packet did not have correct "
- "Message-Authenticator - dropped\n");
+ wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have correct Message-Authenticator - dropped");
return RADIUS_RX_INVALID_AUTHENTICATOR;
}
if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
hdr->code != RADIUS_CODE_ACCESS_REJECT &&
hdr->code != RADIUS_CODE_ACCESS_CHALLENGE) {
- printf("Unknown RADIUS message code\n");
+ wpa_printf(MSG_INFO, "Unknown RADIUS message code");
return RADIUS_RX_UNKNOWN;
}
@@ -1449,7 +1447,7 @@
if (eapol->default_wep_key == NULL ||
random_get_bytes(eapol->default_wep_key,
hapd->conf->default_wep_key_len)) {
- printf("Could not generate random WEP key.\n");
+ wpa_printf(MSG_INFO, "Could not generate random WEP key");
os_free(eapol->default_wep_key);
eapol->default_wep_key = NULL;
return -1;
diff --git a/src/ap/wmm.c b/src/ap/wmm.c
index d21c82f..2851672 100644
--- a/src/ap/wmm.c
+++ b/src/ap/wmm.c
@@ -157,7 +157,7 @@
len = ((u8 *) (t + 1)) - buf;
if (hostapd_drv_send_mlme(hapd, m, len, 0) < 0)
- perror("wmm_send_action: send");
+ wpa_printf(MSG_INFO, "wmm_send_action: send failed");
}
diff --git a/src/common/sae.c b/src/common/sae.c
index bce60a3..4e9e461 100644
--- a/src/common/sae.c
+++ b/src/common/sae.c
@@ -678,7 +678,7 @@
{
if (allowed_groups) {
int i;
- for (i = 0; allowed_groups[i] >= 0; i++) {
+ for (i = 0; allowed_groups[i] > 0; i++) {
if (allowed_groups[i] == group)
break;
}
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index fd7f686..862f881 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -166,6 +166,19 @@
#define AP_REJECTED_MAX_STA "AP-REJECTED-MAX-STA "
#define AP_REJECTED_BLOCKED_STA "AP-REJECTED-BLOCKED-STA "
+#define AP_EVENT_ENABLED "AP-ENABLED "
+#define AP_EVENT_DISABLED "AP-DISABLED "
+
+#define ACS_EVENT_STARTED "ACS-STARTED "
+#define ACS_EVENT_COMPLETED "ACS-COMPLETED "
+#define ACS_EVENT_FAILED "ACS-FAILED "
+
+#define DFS_EVENT_RADAR_DETECTED "DFS-RADAR-DETECTED "
+#define DFS_EVENT_NEW_CHANNEL "DFS-NEW-CHANNEL "
+#define DFS_EVENT_CAC_START "DFS-CAC-START "
+#define DFS_EVENT_CAC_COMPLETED "DFS-CAC-COMPLETED "
+#define DFS_EVENT_NOP_FINISHED "DFS-NOP-FINISHED "
+
/* BSS command information masks */
#define WPA_BSS_MASK_ALL 0xFFFDFFFF
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 01903f9..0e4dc79 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -1570,6 +1570,14 @@
int (*set_country)(void *priv, const char *alpha2);
/**
+ * get_country - Get country
+ * @priv: Private driver interface data
+ * @alpha2: Buffer for returning country code (at least 3 octets)
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*get_country)(void *priv, char *alpha2);
+
+ /**
* global_init - Global driver initialization
* Returns: Pointer to private data (global), %NULL on failure
*
@@ -1955,12 +1963,13 @@
* (this may differ from the requested addr if the driver cannot
* change interface address)
* @bridge: Bridge interface to use or %NULL if no bridge configured
+ * @use_existing: Whether to allow existing interface to be used
* Returns: 0 on success, -1 on failure
*/
int (*if_add)(void *priv, enum wpa_driver_if_type type,
const char *ifname, const u8 *addr, void *bss_ctx,
void **drv_priv, char *force_ifname, u8 *if_addr,
- const char *bridge);
+ const char *bridge, int use_existing);
/**
* if_remove - Remove a virtual interface
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 704bc79..9430516 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -218,6 +218,7 @@
unsigned int added_bridge:1;
unsigned int in_deinit:1;
unsigned int wdev_id_set:1;
+ unsigned int added_if:1;
u8 addr[ETH_ALEN];
@@ -294,7 +295,7 @@
struct wpa_driver_scan_filter *filter_ssids;
size_t num_filter_ssids;
- struct i802_bss first_bss;
+ struct i802_bss *first_bss;
int eapol_tx_sock;
@@ -1051,7 +1052,8 @@
event.interface_status.ifname,
del ? "removed" : "added");
- if (os_strcmp(drv->first_bss.ifname, event.interface_status.ifname) == 0) {
+ if (os_strcmp(drv->first_bss->ifname, event.interface_status.ifname) ==
+ 0) {
if (del) {
if (drv->if_removed) {
wpa_printf(MSG_DEBUG, "nl80211: if_removed "
@@ -1060,11 +1062,11 @@
}
drv->if_removed = 1;
} else {
- if (if_nametoindex(drv->first_bss.ifname) == 0) {
+ if (if_nametoindex(drv->first_bss->ifname) == 0) {
wpa_printf(MSG_DEBUG, "nl80211: Interface %s "
"does not exist - ignore "
"RTM_NEWLINK",
- drv->first_bss.ifname);
+ drv->first_bss->ifname);
return;
}
if (!drv->if_removed) {
@@ -1092,8 +1094,8 @@
rta_len = RTA_ALIGN(sizeof(struct rtattr));
while (RTA_OK(attr, attrlen)) {
if (attr->rta_type == IFLA_IFNAME) {
- if (os_strcmp(((char *) attr) + rta_len, drv->first_bss.ifname)
- == 0)
+ if (os_strcmp(((char *) attr) + rta_len,
+ drv->first_bss->ifname) == 0)
return 1;
else
break;
@@ -1165,7 +1167,7 @@
if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) {
if (if_indextoname(ifi->ifi_index, namebuf) &&
linux_iface_up(drv->global->ioctl_sock,
- drv->first_bss.ifname) > 0) {
+ drv->first_bss->ifname) > 0) {
wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
"event since interface %s is up", namebuf);
return;
@@ -1185,18 +1187,18 @@
if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) {
if (if_indextoname(ifi->ifi_index, namebuf) &&
linux_iface_up(drv->global->ioctl_sock,
- drv->first_bss.ifname) == 0) {
+ drv->first_bss->ifname) == 0) {
wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
"event since interface %s is down",
namebuf);
- } else if (if_nametoindex(drv->first_bss.ifname) == 0) {
+ } else if (if_nametoindex(drv->first_bss->ifname) == 0) {
wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
"event since interface %s does not exist",
- drv->first_bss.ifname);
+ drv->first_bss->ifname);
} else if (drv->if_removed) {
wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
"event since interface %s is marked "
- "removed", drv->first_bss.ifname);
+ "removed", drv->first_bss->ifname);
} else {
wpa_printf(MSG_DEBUG, "nl80211: Interface up");
drv->if_disabled = 0;
@@ -1696,7 +1698,7 @@
if (type == EVENT_DISASSOC) {
event.disassoc_info.locally_generated =
- !os_memcmp(mgmt->sa, drv->first_bss.addr, ETH_ALEN);
+ !os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN);
event.disassoc_info.addr = bssid;
event.disassoc_info.reason_code = reason_code;
if (frame + len > mgmt->u.disassoc.variable) {
@@ -1706,7 +1708,7 @@
}
} else {
event.deauth_info.locally_generated =
- !os_memcmp(mgmt->sa, drv->first_bss.addr, ETH_ALEN);
+ !os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN);
event.deauth_info.addr = bssid;
event.deauth_info.reason_code = reason_code;
if (frame + len > mgmt->u.deauth.variable) {
@@ -2577,9 +2579,12 @@
}
/* Get VHT params */
- data.dfs_event.chan_width =
- convert2width(nla_get_u32(tb[NL80211_ATTR_CHANNEL_WIDTH]));
- data.dfs_event.cf1 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
+ if (tb[NL80211_ATTR_CHANNEL_WIDTH])
+ data.dfs_event.chan_width =
+ convert2width(nla_get_u32(
+ tb[NL80211_ATTR_CHANNEL_WIDTH]));
+ if (tb[NL80211_ATTR_CENTER_FREQ1])
+ data.dfs_event.cf1 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
if (tb[NL80211_ATTR_CENTER_FREQ2])
data.dfs_event.cf2 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
@@ -2638,7 +2643,7 @@
if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED &&
(cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
cmd == NL80211_CMD_SCAN_ABORTED)) {
- wpa_driver_nl80211_set_mode(&drv->first_bss,
+ wpa_driver_nl80211_set_mode(drv->first_bss,
drv->ap_scan_as_station);
drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
}
@@ -2790,7 +2795,7 @@
if (tb[NL80211_ATTR_IFINDEX]) {
ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
- for (bss = &drv->first_bss; bss; bss = bss->next)
+ for (bss = drv->first_bss; bss; bss = bss->next)
if (ifidx == -1 || ifidx == bss->ifindex) {
do_process_drv_event(bss, gnlh->cmd, tb);
return NL_SKIP;
@@ -2801,7 +2806,7 @@
} else if (tb[NL80211_ATTR_WDEV]) {
u64 wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
wpa_printf(MSG_DEBUG, "nl80211: Process event on P2P device");
- for (bss = &drv->first_bss; bss; bss = bss->next) {
+ for (bss = drv->first_bss; bss; bss = bss->next) {
if (bss->wdev_id_set && wdev_id == bss->wdev_id) {
do_process_drv_event(bss, gnlh->cmd, tb);
return NL_SKIP;
@@ -2839,7 +2844,7 @@
dl_list_for_each_safe(drv, tmp, &global->interfaces,
struct wpa_driver_nl80211_data, list) {
- for (bss = &drv->first_bss; bss; bss = bss->next) {
+ for (bss = drv->first_bss; bss; bss = bss->next) {
if ((ifidx == -1 && !wdev_id_set) ||
ifidx == bss->ifindex ||
(wdev_id_set && bss->wdev_id_set &&
@@ -2944,6 +2949,44 @@
}
+static int nl80211_get_country(struct nl_msg *msg, void *arg)
+{
+ char *alpha2 = arg;
+ struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+
+ nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+ if (!tb_msg[NL80211_ATTR_REG_ALPHA2]) {
+ wpa_printf(MSG_DEBUG, "nl80211: No country information available");
+ return NL_SKIP;
+ }
+ os_strlcpy(alpha2, nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]), 3);
+ return NL_SKIP;
+}
+
+
+static int wpa_driver_nl80211_get_country(void *priv, char *alpha2)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG);
+ alpha2[0] = '\0';
+ ret = send_and_recv_msgs(drv, msg, nl80211_get_country, alpha2);
+ if (!alpha2[0])
+ ret = -1;
+
+ return ret;
+}
+
+
static int protocol_feature_handler(struct nl_msg *msg, void *arg)
{
u32 *feat = arg;
@@ -3334,7 +3377,7 @@
nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
NLA_PUT_FLAG(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
- if (nl80211_set_iface_id(msg, &drv->first_bss) < 0)
+ if (nl80211_set_iface_id(msg, drv->first_bss) < 0)
goto nla_put_failure;
if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info))
@@ -3599,7 +3642,7 @@
{
struct wpa_driver_nl80211_data *drv = ctx;
wpa_printf(MSG_DEBUG, "nl80211: RFKILL unblocked");
- if (i802_set_iface_flags(&drv->first_bss, 1)) {
+ if (i802_set_iface_flags(drv->first_bss, 1)) {
wpa_printf(MSG_DEBUG, "nl80211: Could not set interface UP "
"after rfkill unblock");
return;
@@ -3711,7 +3754,13 @@
return NULL;
drv->global = global_priv;
drv->ctx = ctx;
- bss = &drv->first_bss;
+
+ drv->first_bss = os_zalloc(sizeof(*drv->first_bss));
+ if (!drv->first_bss) {
+ os_free(drv);
+ return NULL;
+ }
+ bss = drv->first_bss;
bss->drv = drv;
bss->ctx = ctx;
@@ -4132,7 +4181,7 @@
#ifndef HOSTAPD
enum nl80211_iftype nlmode = NL80211_IFTYPE_STATION;
#endif /* HOSTAPD */
- struct i802_bss *bss = &drv->first_bss;
+ struct i802_bss *bss = drv->first_bss;
int send_rfkill_event = 0;
drv->ifindex = if_nametoindex(bss->ifname);
@@ -4212,6 +4261,8 @@
if (!msg)
return -ENOMEM;
+ wpa_printf(MSG_DEBUG, "nl80211: Remove beacon (ifindex=%d)",
+ drv->ifindex);
nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_BEACON);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
@@ -4297,7 +4348,7 @@
}
nl_cb_put(drv->nl_cb);
- nl80211_destroy_bss(&drv->first_bss);
+ nl80211_destroy_bss(drv->first_bss);
os_free(drv->filter_ssids);
@@ -4308,6 +4359,7 @@
os_free(drv->extended_capa);
os_free(drv->extended_capa_mask);
+ os_free(drv->first_bss);
os_free(drv);
}
@@ -4324,7 +4376,7 @@
{
struct wpa_driver_nl80211_data *drv = eloop_ctx;
if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED) {
- wpa_driver_nl80211_set_mode(&drv->first_bss,
+ wpa_driver_nl80211_set_mode(drv->first_bss,
drv->ap_scan_as_station);
drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
}
@@ -4929,7 +4981,7 @@
goto nla_put_failure;
nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
- if (nl80211_set_iface_id(msg, &drv->first_bss) < 0)
+ if (nl80211_set_iface_id(msg, drv->first_bss) < 0)
goto nla_put_failure;
arg.drv = drv;
@@ -5572,7 +5624,7 @@
struct wpa_driver_nl80211_data *drv)
{
struct wpa_driver_auth_params params;
- struct i802_bss *bss = &drv->first_bss;
+ struct i802_bss *bss = drv->first_bss;
int i;
wpa_printf(MSG_DEBUG, "nl80211: Try to authenticate again");
@@ -7021,7 +7073,7 @@
return -1;
nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_INTERFACE);
- if (nl80211_set_iface_id(msg, &drv->first_bss) < 0)
+ if (nl80211_set_iface_id(msg, drv->first_bss) < 0)
goto nla_put_failure;
NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname);
NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype);
@@ -7077,7 +7129,7 @@
const char *ifname, enum nl80211_iftype iftype,
const u8 *addr, int wds,
int (*handler)(struct nl_msg *, void *),
- void *arg)
+ void *arg, int use_existing)
{
int ret;
@@ -7086,6 +7138,11 @@
/* if error occurred and interface exists already */
if (ret == -ENFILE && if_nametoindex(ifname)) {
+ if (use_existing) {
+ wpa_printf(MSG_DEBUG, "nl80211: Continue using existing interface %s",
+ ifname);
+ return -ENFILE;
+ }
wpa_printf(MSG_INFO, "Try to remove and re-create %s", ifname);
/* Try to remove the interface that was already there. */
@@ -7400,7 +7457,10 @@
static void nl80211_remove_monitor_interface(
struct wpa_driver_nl80211_data *drv)
{
- drv->monitor_refcount--;
+ if (drv->monitor_refcount > 0)
+ drv->monitor_refcount--;
+ wpa_printf(MSG_DEBUG, "nl80211: Remove monitor interface: refcount=%d",
+ drv->monitor_refcount);
if (drv->monitor_refcount > 0)
return;
@@ -7426,27 +7486,29 @@
if (drv->monitor_ifidx >= 0) {
drv->monitor_refcount++;
+ wpa_printf(MSG_DEBUG, "nl80211: Re-use existing monitor interface: refcount=%d",
+ drv->monitor_refcount);
return 0;
}
- if (os_strncmp(drv->first_bss.ifname, "p2p-", 4) == 0) {
+ if (os_strncmp(drv->first_bss->ifname, "p2p-", 4) == 0) {
/*
* P2P interface name is of the format p2p-%s-%d. For monitor
* interface name corresponding to P2P GO, replace "p2p-" with
* "mon-" to retain the same interface name length and to
* indicate that it is a monitor interface.
*/
- snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss.ifname + 4);
+ snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss->ifname + 4);
} else {
/* Non-P2P interface with AP functionality. */
- snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss.ifname);
+ snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss->ifname);
}
buf[IFNAMSIZ - 1] = '\0';
drv->monitor_ifidx =
nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL,
- 0, NULL, NULL);
+ 0, NULL, NULL, 0);
if (drv->monitor_ifidx == -EOPNOTSUPP) {
/*
@@ -7503,6 +7565,7 @@
goto error;
}
+ drv->monitor_refcount++;
return 0;
error:
nl80211_remove_monitor_interface(drv);
@@ -7514,8 +7577,8 @@
{
struct wpa_driver_nl80211_data *drv = bss->drv;
- wpa_printf(MSG_DEBUG, "nl80211: Setup AP - device_ap_sme=%d "
- "use_monitor=%d", drv->device_ap_sme, drv->use_monitor);
+ wpa_printf(MSG_DEBUG, "nl80211: Setup AP(%s) - device_ap_sme=%d use_monitor=%d",
+ bss->ifname, drv->device_ap_sme, drv->use_monitor);
/*
* Disable Probe Request reporting unless we need it in this way for
@@ -7563,6 +7626,8 @@
{
struct wpa_driver_nl80211_data *drv = bss->drv;
+ wpa_printf(MSG_DEBUG, "nl80211: Teardown AP(%s) - device_ap_sme=%d use_monitor=%d",
+ bss->ifname, drv->device_ap_sme, drv->use_monitor);
if (drv->device_ap_sme) {
wpa_driver_nl80211_probe_req_report(bss, 0);
if (!drv->use_monitor)
@@ -7746,14 +7811,14 @@
nlmode = NL80211_IFTYPE_AP;
old_mode = drv->nlmode;
- if (wpa_driver_nl80211_set_mode(&drv->first_bss, nlmode)) {
+ if (wpa_driver_nl80211_set_mode(drv->first_bss, nlmode)) {
nl80211_remove_monitor_interface(drv);
return -1;
}
- if (wpa_driver_nl80211_set_freq(&drv->first_bss, &freq)) {
+ if (wpa_driver_nl80211_set_freq(drv->first_bss, &freq)) {
if (old_mode != nlmode)
- wpa_driver_nl80211_set_mode(&drv->first_bss, old_mode);
+ wpa_driver_nl80211_set_mode(drv->first_bss, old_mode);
nl80211_remove_monitor_interface(drv);
return -1;
}
@@ -7785,7 +7850,7 @@
wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS request sent successfully");
nla_put_failure:
- if (wpa_driver_nl80211_set_mode(&drv->first_bss,
+ if (wpa_driver_nl80211_set_mode(drv->first_bss,
NL80211_IFTYPE_STATION)) {
wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
"station mode");
@@ -7805,7 +7870,7 @@
wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex);
- if (wpa_driver_nl80211_set_mode(&drv->first_bss,
+ if (wpa_driver_nl80211_set_mode(drv->first_bss,
NL80211_IFTYPE_ADHOC)) {
wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
"IBSS mode");
@@ -8318,7 +8383,7 @@
return -ENOMEM;
nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_INTERFACE);
- if (nl80211_set_iface_id(msg, &drv->first_bss) < 0)
+ if (nl80211_set_iface_id(msg, drv->first_bss) < 0)
goto nla_put_failure;
NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, mode);
@@ -8818,6 +8883,10 @@
if (!msg)
return -ENOMEM;
+ wpa_printf(MSG_DEBUG, "nl80211: %s[%d]: set_sta_vlan(" MACSTR
+ ", ifname=%s[%d], vlan_id=%d)",
+ bss->ifname, if_nametoindex(bss->ifname),
+ MAC2STR(addr), ifname, if_nametoindex(ifname), vlan_id);
nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
@@ -8993,7 +9062,8 @@
if (!if_nametoindex(name)) {
if (nl80211_create_iface(drv, name,
NL80211_IFTYPE_AP_VLAN,
- bss->addr, 1, NULL, NULL) < 0)
+ bss->addr, 1, NULL, NULL, 0) <
+ 0)
return -1;
if (bridge_ifname &&
linux_br_add_if(drv->global->ioctl_sock,
@@ -9225,7 +9295,7 @@
struct wpa_driver_nl80211_data *drv;
dl_list_for_each(drv, &global->interfaces,
struct wpa_driver_nl80211_data, list) {
- if (os_memcmp(addr, drv->first_bss.addr, ETH_ALEN) == 0)
+ if (os_memcmp(addr, drv->first_bss->addr, ETH_ALEN) == 0)
return 1;
}
return 0;
@@ -9240,9 +9310,9 @@
if (!drv->global)
return -1;
- os_memcpy(new_addr, drv->first_bss.addr, ETH_ALEN);
+ os_memcpy(new_addr, drv->first_bss->addr, ETH_ALEN);
for (idx = 0; idx < 64; idx++) {
- new_addr[0] = drv->first_bss.addr[0] | 0x02;
+ new_addr[0] = drv->first_bss->addr[0] | 0x02;
new_addr[0] ^= idx << 2;
if (!nl80211_addr_in_use(drv->global, new_addr))
break;
@@ -9290,12 +9360,13 @@
const char *ifname, const u8 *addr,
void *bss_ctx, void **drv_priv,
char *force_ifname, u8 *if_addr,
- const char *bridge)
+ const char *bridge, int use_existing)
{
enum nl80211_iftype nlmode;
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
int ifidx;
+ int added = 1;
if (addr)
os_memcpy(if_addr, addr, ETH_ALEN);
@@ -9306,7 +9377,7 @@
os_memset(&p2pdev_info, 0, sizeof(p2pdev_info));
ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
0, nl80211_wdev_handler,
- &p2pdev_info);
+ &p2pdev_info, use_existing);
if (!p2pdev_info.wdev_id_set || ifidx != 0) {
wpa_printf(MSG_ERROR, "nl80211: Failed to create a P2P Device interface %s",
ifname);
@@ -9322,8 +9393,11 @@
(long long unsigned int) p2pdev_info.wdev_id);
} else {
ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
- 0, NULL, NULL);
- if (ifidx < 0) {
+ 0, NULL, NULL, use_existing);
+ if (use_existing && ifidx == -ENFILE) {
+ added = 0;
+ ifidx = if_nametoindex(ifname);
+ } else if (ifidx < 0) {
return -1;
}
}
@@ -9333,7 +9407,8 @@
os_memcpy(if_addr, bss->addr, ETH_ALEN);
else if (linux_get_ifhwaddr(drv->global->ioctl_sock,
bss->ifname, if_addr) < 0) {
- nl80211_remove_iface(drv, ifidx);
+ if (added)
+ nl80211_remove_iface(drv, ifidx);
return -1;
}
}
@@ -9371,7 +9446,8 @@
if (type == WPA_IF_AP_BSS) {
struct i802_bss *new_bss = os_zalloc(sizeof(*new_bss));
if (new_bss == NULL) {
- nl80211_remove_iface(drv, ifidx);
+ if (added)
+ nl80211_remove_iface(drv, ifidx);
return -1;
}
@@ -9380,7 +9456,8 @@
wpa_printf(MSG_ERROR, "nl80211: Failed to add the new "
"interface %s to a bridge %s",
ifname, bridge);
- nl80211_remove_iface(drv, ifidx);
+ if (added)
+ nl80211_remove_iface(drv, ifidx);
os_free(new_bss);
return -1;
}
@@ -9395,10 +9472,11 @@
os_memcpy(new_bss->addr, if_addr, ETH_ALEN);
new_bss->ifindex = ifidx;
new_bss->drv = drv;
- new_bss->next = drv->first_bss.next;
- new_bss->freq = drv->first_bss.freq;
+ new_bss->next = drv->first_bss->next;
+ new_bss->freq = drv->first_bss->freq;
new_bss->ctx = bss_ctx;
- drv->first_bss.next = new_bss;
+ new_bss->added_if = added;
+ drv->first_bss->next = new_bss;
if (drv_priv)
*drv_priv = new_bss;
nl80211_init_bss(new_bss);
@@ -9423,9 +9501,9 @@
struct wpa_driver_nl80211_data *drv = bss->drv;
int ifindex = if_nametoindex(ifname);
- wpa_printf(MSG_DEBUG, "nl80211: %s(type=%d ifname=%s) ifindex=%d",
- __func__, type, ifname, ifindex);
- if (ifindex > 0)
+ wpa_printf(MSG_DEBUG, "nl80211: %s(type=%d ifname=%s) ifindex=%d added_if=%d",
+ __func__, type, ifname, ifindex, bss->added_if);
+ if (ifindex > 0 && bss->added_if)
nl80211_remove_iface(drv, ifindex);
#ifdef HOSTAPD
@@ -9446,10 +9524,11 @@
bss->brname, strerror(errno));
}
- if (bss != &drv->first_bss) {
+ if (bss != drv->first_bss) {
struct i802_bss *tbss;
- for (tbss = &drv->first_bss; tbss; tbss = tbss->next) {
+ wpa_printf(MSG_DEBUG, "nl80211: Not the first BSS - remove it");
+ for (tbss = drv->first_bss; tbss; tbss = tbss->next) {
if (tbss->next == bss) {
tbss->next = bss->next;
/* Unsubscribe management frames */
@@ -9463,6 +9542,21 @@
if (bss)
wpa_printf(MSG_INFO, "nl80211: %s - could not find "
"BSS %p in the list", __func__, bss);
+ } else {
+ wpa_printf(MSG_DEBUG, "nl80211: First BSS - reassign context");
+ nl80211_teardown_ap(bss);
+ if (!bss->added_if && !drv->first_bss->next)
+ wpa_driver_nl80211_del_beacon(drv);
+ nl80211_destroy_bss(bss);
+ if (!bss->added_if)
+ i802_set_iface_flags(bss, 0);
+ if (drv->first_bss->next) {
+ drv->first_bss = drv->first_bss->next;
+ drv->ctx = drv->first_bss->ctx;
+ os_free(bss);
+ } else {
+ wpa_printf(MSG_DEBUG, "nl80211: No second BSS to reassign context to");
+ }
}
#endif /* HOSTAPD */
@@ -10056,10 +10150,10 @@
wpa_printf(MSG_DEBUG, "nl80211: Found a match for PHY %s - %s "
MACSTR,
- driver->phyname, driver->first_bss.ifname,
- MAC2STR(driver->first_bss.addr));
+ driver->phyname, driver->first_bss->ifname,
+ MAC2STR(driver->first_bss->addr));
if (is_ap_interface(driver->nlmode))
- freq = driver->first_bss.freq;
+ freq = driver->first_bss->freq;
else
freq = nl80211_get_assoc_freq(driver);
wpa_printf(MSG_DEBUG, "nl80211: Shared freq for PHY %s: %d",
@@ -11203,6 +11297,7 @@
.set_operstate = wpa_driver_nl80211_set_operstate,
.set_supp_port = wpa_driver_nl80211_set_supp_port,
.set_country = wpa_driver_nl80211_set_country,
+ .get_country = wpa_driver_nl80211_get_country,
.set_ap = wpa_driver_nl80211_set_ap,
.set_acl = wpa_driver_nl80211_set_acl,
.if_add = wpa_driver_nl80211_if_add,
diff --git a/src/drivers/driver_test.c b/src/drivers/driver_test.c
index 541ebcc..5742b98 100644
--- a/src/drivers/driver_test.c
+++ b/src/drivers/driver_test.c
@@ -1059,7 +1059,7 @@
const char *ifname, const u8 *addr,
void *bss_ctx, void **drv_priv,
char *force_ifname, u8 *if_addr,
- const char *bridge)
+ const char *bridge, int use_existing)
{
struct test_driver_bss *dbss = priv;
struct wpa_driver_test_data *drv = dbss->drv;
diff --git a/src/eap_server/eap_sim_db.c b/src/eap_server/eap_sim_db.c
index 1b9d701..345c788 100644
--- a/src/eap_server/eap_sim_db.c
+++ b/src/eap_server/eap_sim_db.c
@@ -630,7 +630,7 @@
data->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
if (data->sock < 0) {
- perror("socket(eap_sim_db)");
+ wpa_printf(MSG_INFO, "socket(eap_sim_db): %s", strerror(errno));
return -1;
}
@@ -641,7 +641,7 @@
os_free(data->local_sock);
data->local_sock = os_strdup(addr.sun_path);
if (bind(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("bind(eap_sim_db)");
+ wpa_printf(MSG_INFO, "bind(eap_sim_db): %s", strerror(errno));
close(data->sock);
data->sock = -1;
return -1;
@@ -651,7 +651,8 @@
addr.sun_family = AF_UNIX;
os_strlcpy(addr.sun_path, data->fname + 5, sizeof(addr.sun_path));
if (connect(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("connect(eap_sim_db)");
+ wpa_printf(MSG_INFO, "connect(eap_sim_db): %s",
+ strerror(errno));
wpa_hexdump_ascii(MSG_INFO, "HLR/AuC GW socket",
(u8 *) addr.sun_path,
os_strlen(addr.sun_path));
@@ -804,7 +805,8 @@
if (send(data->sock, msg, len, 0) < 0) {
_errno = errno;
- perror("send[EAP-SIM DB UNIX]");
+ wpa_printf(MSG_INFO, "send[EAP-SIM DB UNIX]: %s",
+ strerror(errno));
}
if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
@@ -816,7 +818,8 @@
wpa_printf(MSG_DEBUG, "EAP-SIM DB: Reconnected to the "
"external server");
if (send(data->sock, msg, len, 0) < 0) {
- perror("send[EAP-SIM DB UNIX]");
+ wpa_printf(MSG_INFO, "send[EAP-SIM DB UNIX]: %s",
+ strerror(errno));
return -1;
}
}
diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c
index 425ad93..290c7c8 100644
--- a/src/radius/radius_client.c
+++ b/src/radius/radius_client.c
@@ -300,7 +300,7 @@
{
#ifndef CONFIG_NATIVE_WINDOWS
int _errno = errno;
- perror("send[RADIUS]");
+ wpa_printf(MSG_INFO, "send[RADIUS]: %s", strerror(errno));
if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
_errno == EBADF) {
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
@@ -361,8 +361,7 @@
if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT)
entry->next_wait = RADIUS_CLIENT_MAX_WAIT;
if (entry->attempts >= RADIUS_CLIENT_MAX_RETRIES) {
- printf("Removing un-ACKed RADIUS message due to too many "
- "failed retransmit attempts\n");
+ wpa_printf(MSG_INFO, "RADIUS: Removing un-ACKed message due to too many failed retransmit attempts");
return 1;
}
@@ -526,7 +525,7 @@
entry = os_zalloc(sizeof(*entry));
if (entry == NULL) {
- printf("Failed to add RADIUS packet into retransmit list\n");
+ wpa_printf(MSG_INFO, "RADIUS: Failed to add packet into retransmit list");
radius_msg_free(msg);
return;
}
@@ -547,8 +546,7 @@
radius_client_update_timeout(radius);
if (radius->num_msgs >= RADIUS_CLIENT_MAX_ENTRIES) {
- printf("Removing the oldest un-ACKed RADIUS packet due to "
- "retransmit list limits.\n");
+ wpa_printf(MSG_INFO, "RADIUS: Removing the oldest un-ACKed packet due to retransmit list limits");
prev = NULL;
while (entry->next) {
prev = entry;
@@ -710,21 +708,20 @@
len = recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
if (len < 0) {
- perror("recv[RADIUS]");
+ wpa_printf(MSG_INFO, "recv[RADIUS]: %s", strerror(errno));
return;
}
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_DEBUG, "Received %d bytes from RADIUS "
"server", len);
if (len == sizeof(buf)) {
- printf("Possibly too long UDP frame for our buffer - "
- "dropping it\n");
+ wpa_printf(MSG_INFO, "RADIUS: Possibly too long UDP frame for our buffer - dropping it");
return;
}
msg = radius_msg_parse(buf, len);
if (msg == NULL) {
- printf("Parsing incoming RADIUS frame failed\n");
+ wpa_printf(MSG_INFO, "RADIUS: Parsing incoming frame failed");
rconf->malformed_responses++;
return;
}
@@ -1041,13 +1038,14 @@
}
if (bind(sel_sock, cl_addr, claddrlen) < 0) {
- perror("bind[radius]");
+ wpa_printf(MSG_INFO, "bind[radius]: %s",
+ strerror(errno));
return -1;
}
}
if (connect(sel_sock, addr, addrlen) < 0) {
- perror("connect[radius]");
+ wpa_printf(MSG_INFO, "connect[radius]: %s", strerror(errno));
return -1;
}
@@ -1123,8 +1121,8 @@
r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action,
sizeof(action));
if (r == -1)
- wpa_printf(MSG_ERROR, "Failed to set IP_MTU_DISCOVER: "
- "%s", strerror(errno));
+ wpa_printf(MSG_ERROR, "RADIUS: Failed to set IP_MTU_DISCOVER: %s",
+ strerror(errno));
#endif
return r;
}
@@ -1137,7 +1135,8 @@
radius->auth_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
if (radius->auth_serv_sock < 0)
- perror("socket[PF_INET,SOCK_DGRAM]");
+ wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET,SOCK_DGRAM]: %s",
+ strerror(errno));
else {
radius_client_disable_pmtu_discovery(radius->auth_serv_sock);
ok++;
@@ -1146,7 +1145,8 @@
#ifdef CONFIG_IPV6
radius->auth_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
if (radius->auth_serv_sock6 < 0)
- perror("socket[PF_INET6,SOCK_DGRAM]");
+ wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET6,SOCK_DGRAM]: %s",
+ strerror(errno));
else
ok++;
#endif /* CONFIG_IPV6 */
@@ -1162,8 +1162,7 @@
eloop_register_read_sock(radius->auth_serv_sock,
radius_client_receive, radius,
(void *) RADIUS_AUTH)) {
- printf("Could not register read socket for authentication "
- "server\n");
+ wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for authentication server");
return -1;
}
@@ -1172,8 +1171,7 @@
eloop_register_read_sock(radius->auth_serv_sock6,
radius_client_receive, radius,
(void *) RADIUS_AUTH)) {
- printf("Could not register read socket for authentication "
- "server\n");
+ wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for authentication server");
return -1;
}
#endif /* CONFIG_IPV6 */
@@ -1189,7 +1187,8 @@
radius->acct_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
if (radius->acct_serv_sock < 0)
- perror("socket[PF_INET,SOCK_DGRAM]");
+ wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET,SOCK_DGRAM]: %s",
+ strerror(errno));
else {
radius_client_disable_pmtu_discovery(radius->acct_serv_sock);
ok++;
@@ -1198,7 +1197,8 @@
#ifdef CONFIG_IPV6
radius->acct_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
if (radius->acct_serv_sock6 < 0)
- perror("socket[PF_INET6,SOCK_DGRAM]");
+ wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET6,SOCK_DGRAM]: %s",
+ strerror(errno));
else
ok++;
#endif /* CONFIG_IPV6 */
@@ -1214,8 +1214,7 @@
eloop_register_read_sock(radius->acct_serv_sock,
radius_client_receive, radius,
(void *) RADIUS_ACCT)) {
- printf("Could not register read socket for accounting "
- "server\n");
+ wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for accounting server");
return -1;
}
@@ -1224,8 +1223,7 @@
eloop_register_read_sock(radius->acct_serv_sock6,
radius_client_receive, radius,
(void *) RADIUS_ACCT)) {
- printf("Could not register read socket for accounting "
- "server\n");
+ wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for accounting server");
return -1;
}
#endif /* CONFIG_IPV6 */
diff --git a/src/radius/radius_das.c b/src/radius/radius_das.c
index bded965..8e5988d 100644
--- a/src/radius/radius_das.c
+++ b/src/radius/radius_das.c
@@ -1,6 +1,6 @@
/*
* RADIUS Dynamic Authorization Server (DAS) (RFC 5176)
- * Copyright (c) 2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -284,7 +284,7 @@
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s < 0) {
- perror("socket");
+ wpa_printf(MSG_INFO, "RADIUS DAS: socket: %s", strerror(errno));
return -1;
}
@@ -292,7 +292,7 @@
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("bind");
+ wpa_printf(MSG_INFO, "RADIUS DAS: bind: %s", strerror(errno));
close(s);
return -1;
}
diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c
index 0144c9f..fe19770 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -679,7 +679,7 @@
buf = radius_msg_get_buf(msg);
if (sendto(data->auth_sock, wpabuf_head(buf), wpabuf_len(buf), 0,
(struct sockaddr *) from, sizeof(*from)) < 0) {
- perror("sendto[RADIUS SRV]");
+ wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s", strerror(errno));
ret = -1;
}
@@ -750,7 +750,8 @@
wpabuf_len(buf), 0,
(struct sockaddr *) from, fromlen);
if (res < 0) {
- perror("sendto[RADIUS SRV]");
+ wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s",
+ strerror(errno));
}
return 0;
}
@@ -842,7 +843,8 @@
wpabuf_len(buf), 0,
(struct sockaddr *) from, fromlen);
if (res < 0) {
- perror("sendto[RADIUS SRV]");
+ wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s",
+ strerror(errno));
}
radius_msg_free(sess->last_reply);
sess->last_reply = reply;
@@ -897,7 +899,8 @@
len = recvfrom(sock, buf, RADIUS_MAX_MSG_LEN, 0,
(struct sockaddr *) &from.ss, &fromlen);
if (len < 0) {
- perror("recvfrom[radius_server]");
+ wpa_printf(MSG_INFO, "recvfrom[radius_server]: %s",
+ strerror(errno));
goto fail;
}
@@ -1001,7 +1004,7 @@
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s < 0) {
- perror("socket");
+ wpa_printf(MSG_INFO, "RADIUS: socket: %s", strerror(errno));
return -1;
}
@@ -1011,7 +1014,7 @@
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("bind");
+ wpa_printf(MSG_INFO, "RADIUS: bind: %s", strerror(errno));
close(s);
return -1;
}
@@ -1028,7 +1031,8 @@
s = socket(PF_INET6, SOCK_DGRAM, 0);
if (s < 0) {
- perror("socket[IPv6]");
+ wpa_printf(MSG_INFO, "RADIUS: socket[IPv6]: %s",
+ strerror(errno));
return -1;
}
@@ -1037,7 +1041,7 @@
os_memcpy(&addr.sin6_addr, &in6addr_any, sizeof(in6addr_any));
addr.sin6_port = htons(port);
if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("bind");
+ wpa_printf(MSG_INFO, "RADIUS: bind: %s", strerror(errno));
close(s);
return -1;
}
@@ -1248,8 +1252,7 @@
#ifndef CONFIG_IPV6
if (conf->ipv6) {
- fprintf(stderr, "RADIUS server compiled without IPv6 "
- "support.\n");
+ wpa_printf(MSG_ERROR, "RADIUS server compiled without IPv6 support");
return NULL;
}
#endif /* CONFIG_IPV6 */
@@ -1305,7 +1308,7 @@
data->clients = radius_server_read_clients(conf->client_file,
conf->ipv6);
if (data->clients == NULL) {
- printf("No RADIUS clients configured.\n");
+ wpa_printf(MSG_ERROR, "No RADIUS clients configured");
radius_server_deinit(data);
return NULL;
}
@@ -1317,8 +1320,7 @@
#endif /* CONFIG_IPV6 */
data->auth_sock = radius_server_open_socket(conf->auth_port);
if (data->auth_sock < 0) {
- printf("Failed to open UDP socket for RADIUS authentication "
- "server\n");
+ wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS authentication server");
radius_server_deinit(data);
return NULL;
}
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 292255c..d4f86e6 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -1126,7 +1126,8 @@
goto failed;
}
- wpa_sm_set_rekey_offload(sm);
+ if (ie.gtk)
+ wpa_sm_set_rekey_offload(sm);
return;
@@ -1347,13 +1348,14 @@
MAC2STR(sm->bssid), wpa_cipher_txt(sm->group_cipher));
wpa_sm_cancel_auth_timeout(sm);
wpa_sm_set_state(sm, WPA_COMPLETED);
-
- wpa_sm_set_rekey_offload(sm);
} else {
wpa_supplicant_key_neg_complete(sm, sm->bssid,
key_info &
WPA_KEY_INFO_SECURE);
}
+
+ wpa_sm_set_rekey_offload(sm);
+
return;
failed:
diff --git a/src/utils/eloop.c b/src/utils/eloop.c
index f62e2b7..12aa125 100644
--- a/src/utils/eloop.c
+++ b/src/utils/eloop.c
@@ -753,7 +753,8 @@
timeout ? timeout_ms : -1);
if (res < 0 && errno != EINTR && errno != 0) {
- perror("poll");
+ wpa_printf(MSG_INFO, "eloop: poll: %s",
+ strerror(errno));
goto out;
}
#else /* CONFIG_ELOOP_POLL */
@@ -763,7 +764,8 @@
res = select(eloop.max_sock + 1, rfds, wfds, efds,
timeout ? &_tv : NULL);
if (res < 0 && errno != EINTR && errno != 0) {
- perror("select");
+ wpa_printf(MSG_INFO, "eloop: select: %s",
+ strerror(errno));
goto out;
}
#endif /* CONFIG_ELOOP_POLL */