aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hostapd/Android.mk16
-rw-r--r--hostapd/Makefile20
-rw-r--r--hostapd/config_file.c3
-rw-r--r--hostapd/ctrl_iface.c5
-rw-r--r--hostapd/hostapd_cli.c15
-rw-r--r--hostapd/main.c3
-rw-r--r--hs20/client/osu_client.c20
-rw-r--r--src/ap/beacon.c6
-rw-r--r--src/ap/ctrl_iface_ap.c13
-rw-r--r--src/ap/ctrl_iface_ap.h3
-rw-r--r--src/ap/drv_callbacks.c27
-rw-r--r--src/ap/hostapd.c4
-rw-r--r--src/ap/hostapd.h1
-rw-r--r--src/ap/iapp.c4
-rw-r--r--src/ap/ieee802_11.c28
-rw-r--r--src/ap/ieee802_11.h1
-rw-r--r--src/ap/pmksa_cache_auth.c66
-rw-r--r--src/ap/pmksa_cache_auth.h2
-rw-r--r--src/ap/sta_info.h1
-rw-r--r--src/ap/vlan_full.c752
-rw-r--r--src/ap/vlan_ifconfig.c69
-rw-r--r--src/ap/vlan_init.c948
-rw-r--r--src/ap/vlan_ioctl.c155
-rw-r--r--src/ap/vlan_util.c14
-rw-r--r--src/ap/vlan_util.h18
-rw-r--r--src/ap/wpa_auth.c40
-rw-r--r--src/ap/wpa_auth.h9
-rw-r--r--src/common/ctrl_iface_common.c37
-rw-r--r--src/common/ieee802_11_defs.h5
-rw-r--r--src/common/linux_bridge.h24
-rw-r--r--src/common/linux_vlan.h52
-rw-r--r--src/common/sae.c21
-rw-r--r--src/crypto/crypto_openssl.c47
-rw-r--r--src/crypto/sha256-prf.c26
-rw-r--r--src/crypto/sha256.h12
-rw-r--r--src/crypto/tls_openssl_ocsp.c3
-rw-r--r--src/drivers/driver.h24
-rw-r--r--src/drivers/driver_atheros.c7
-rw-r--r--src/drivers/driver_bsd.c69
-rw-r--r--src/drivers/driver_nl80211.c126
-rw-r--r--src/drivers/driver_nl80211.h2
-rw-r--r--src/drivers/driver_nl80211_event.c20
-rw-r--r--src/drivers/driver_privsep.c2
-rw-r--r--src/drivers/drivers.mak4
-rw-r--r--src/drivers/drivers.mk4
-rw-r--r--src/p2p/p2p.h6
-rw-r--r--src/p2p/p2p_group.c3
-rw-r--r--src/utils/common.h3
-rw-r--r--src/utils/xml_libxml2.c2
-rw-r--r--wpa_supplicant/Android.mk15
-rw-r--r--wpa_supplicant/Makefile6
-rw-r--r--wpa_supplicant/README19
-rw-r--r--wpa_supplicant/android.config4
-rw-r--r--wpa_supplicant/ap.c52
-rw-r--r--wpa_supplicant/ap.h4
-rw-r--r--wpa_supplicant/binder/binder.cpp108
-rw-r--r--wpa_supplicant/binder/binder.h46
-rw-r--r--wpa_supplicant/binder/binder_i.h27
-rw-r--r--wpa_supplicant/binder/binder_manager.cpp107
-rw-r--r--wpa_supplicant/binder/binder_manager.h59
-rw-r--r--wpa_supplicant/binder/fi/w1/wpa_supplicant/IIface.aidl16
-rw-r--r--wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicant.aidl59
-rw-r--r--wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl20
-rw-r--r--wpa_supplicant/binder/iface.cpp19
-rw-r--r--wpa_supplicant/binder/iface.h42
-rw-r--r--wpa_supplicant/binder/supplicant.cpp125
-rw-r--r--wpa_supplicant/binder/supplicant.h57
-rw-r--r--wpa_supplicant/config.c82
-rw-r--r--wpa_supplicant/ctrl_iface.c91
-rw-r--r--wpa_supplicant/ctrl_iface_udp.c21
-rw-r--r--wpa_supplicant/ctrl_iface_unix.c5
-rw-r--r--wpa_supplicant/defconfig3
-rw-r--r--wpa_supplicant/events.c85
-rw-r--r--wpa_supplicant/interworking.c19
-rw-r--r--wpa_supplicant/main.c52
-rw-r--r--wpa_supplicant/mesh.c13
-rw-r--r--wpa_supplicant/mesh.h3
-rw-r--r--wpa_supplicant/mesh_mpm.c103
-rw-r--r--wpa_supplicant/mesh_mpm.h3
-rw-r--r--wpa_supplicant/mesh_rsn.c48
-rw-r--r--wpa_supplicant/notify.c12
-rw-r--r--wpa_supplicant/p2p_supplicant.c11
-rw-r--r--wpa_supplicant/scan.c16
-rw-r--r--wpa_supplicant/wnm_sta.c11
-rw-r--r--wpa_supplicant/wpa_cli.c20
-rw-r--r--wpa_supplicant/wpa_priv.c57
-rw-r--r--wpa_supplicant/wpa_supplicant.c102
-rw-r--r--wpa_supplicant/wpa_supplicant_i.h25
88 files changed, 3117 insertions, 1192 deletions
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index 96500b6a..67ca1295 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -175,12 +175,18 @@ ifdef CONFIG_NO_VLAN
L_CFLAGS += -DCONFIG_NO_VLAN
else
OBJS += src/ap/vlan_init.c
+OBJS += src/ap/vlan_ifconfig.c
OBJS += src/ap/vlan.c
-ifdef CONFIG_VLAN_NETLINK
ifdef CONFIG_FULL_DYNAMIC_VLAN
+# Define CONFIG_FULL_DYNAMIC_VLAN to have hostapd manipulate bridges
+# and VLAN interfaces for the VLAN feature.
+L_CFLAGS += -DCONFIG_FULL_DYNAMIC_VLAN
+OBJS += src/ap/vlan_full.c
+ifdef CONFIG_VLAN_NETLINK
OBJS += src/ap/vlan_util.c
+else
+OBJS += src/ap/vlan_ioctl.c
endif
-L_CFLAGS += -DCONFIG_VLAN_NETLINK
endif
endif
@@ -869,12 +875,6 @@ ifdef CONFIG_DRIVER_RADIUS_ACL
L_CFLAGS += -DCONFIG_DRIVER_RADIUS_ACL
endif
-ifdef CONFIG_FULL_DYNAMIC_VLAN
-# define CONFIG_FULL_DYNAMIC_VLAN to have hostapd manipulate bridges
-# and vlan interfaces for the vlan feature.
-L_CFLAGS += -DCONFIG_FULL_DYNAMIC_VLAN
-endif
-
ifdef NEED_BASE64
OBJS += src/utils/base64.c
endif
diff --git a/hostapd/Makefile b/hostapd/Makefile
index e0d25a53..fa4af82a 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -27,10 +27,6 @@ CFLAGS += -I$(abspath ../src/utils)
export BINDIR ?= /usr/local/bin/
-# Uncomment following line and set the path to your kernel tree include
-# directory if your C library does not include all header files.
-# CFLAGS += -DUSE_KERNEL_HEADERS -I/usr/src/linux/include
-
-include .config
ifndef CONFIG_NO_GITVER
@@ -194,12 +190,18 @@ ifdef CONFIG_NO_VLAN
CFLAGS += -DCONFIG_NO_VLAN
else
OBJS += ../src/ap/vlan_init.o
+OBJS += ../src/ap/vlan_ifconfig.o
OBJS += ../src/ap/vlan.o
-ifdef CONFIG_VLAN_NETLINK
ifdef CONFIG_FULL_DYNAMIC_VLAN
+# Define CONFIG_FULL_DYNAMIC_VLAN to have hostapd manipulate bridges
+# and VLAN interfaces for the VLAN feature.
+CFLAGS += -DCONFIG_FULL_DYNAMIC_VLAN
+OBJS += ../src/ap/vlan_full.o
+ifdef CONFIG_VLAN_NETLINK
OBJS += ../src/ap/vlan_util.o
+else
+OBJS += ../src/ap/vlan_ioctl.o
endif
-CFLAGS += -DCONFIG_VLAN_NETLINK
endif
endif
@@ -907,12 +909,6 @@ ifdef CONFIG_DRIVER_RADIUS_ACL
CFLAGS += -DCONFIG_DRIVER_RADIUS_ACL
endif
-ifdef CONFIG_FULL_DYNAMIC_VLAN
-# define CONFIG_FULL_DYNAMIC_VLAN to have hostapd manipulate bridges
-# and vlan interfaces for the vlan feature.
-CFLAGS += -DCONFIG_FULL_DYNAMIC_VLAN
-endif
-
ifdef NEED_BASE64
OBJS += ../src/utils/base64.o
endif
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 6f525d92..c35d5aec 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -3468,7 +3468,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
return -1;
}
val = strtol(pos, &endp, 0);
- if (*endp || val < 1 || val > FST_MAX_LLT_MS) {
+ if (*endp || val < 1 ||
+ (unsigned long int) val > FST_MAX_LLT_MS) {
wpa_printf(MSG_ERROR,
"Line %d: Invalid fst_llt %ld (%s) (expected 1..%u)",
line, val, pos, FST_MAX_LLT_MS);
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 33819ab8..a87f1174 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -2307,6 +2307,11 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
reply_len = hostapd_ctrl_iface_track_sta_list(
hapd, reply, reply_size);
#endif /* NEED_AP_MLME */
+ } else if (os_strcmp(buf, "PMKSA") == 0) {
+ reply_len = hostapd_ctrl_iface_pmksa_list(hapd, reply,
+ reply_size);
+ } else if (os_strcmp(buf, "PMKSA_FLUSH") == 0) {
+ hostapd_ctrl_iface_pmksa_flush(hapd);
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index fc8a72e3..bf86d376 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -1130,6 +1130,19 @@ static int hostapd_cli_cmd_raw(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
+static int hostapd_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "PMKSA");
+}
+
+
+static int hostapd_cli_cmd_pmksa_flush(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "PMKSA_FLUSH");
+}
+
+
struct hostapd_cli_cmd {
const char *cmd;
int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
@@ -1189,6 +1202,8 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
{ "disable", hostapd_cli_cmd_disable },
{ "erp_flush", hostapd_cli_cmd_erp_flush },
{ "log_level", hostapd_cli_cmd_log_level },
+ { "pmksa", hostapd_cli_cmd_pmksa },
+ { "pmksa_flush", hostapd_cli_cmd_pmksa_flush },
{ NULL, NULL }
};
diff --git a/hostapd/main.c b/hostapd/main.c
index 25dc20b4..1d9e63e3 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -171,7 +171,8 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
if (global.drv_priv[i] == NULL &&
wpa_drivers[i]->global_init) {
- global.drv_priv[i] = wpa_drivers[i]->global_init();
+ global.drv_priv[i] =
+ wpa_drivers[i]->global_init(iface->interfaces);
if (global.drv_priv[i] == NULL) {
wpa_printf(MSG_ERROR, "Failed to initialize "
"driver '%s'",
diff --git a/hs20/client/osu_client.c b/hs20/client/osu_client.c
index 2907c641..c05c57d4 100644
--- a/hs20/client/osu_client.c
+++ b/hs20/client/osu_client.c
@@ -2570,7 +2570,7 @@ static int cmd_pol_upd(struct hs20_osu_client *ctx, const char *address,
if (!pps_fname) {
char buf[256];
wpa_printf(MSG_INFO, "Determining PPS file based on Home SP information");
- if (os_strncmp(address, "fqdn=", 5) == 0) {
+ if (address && os_strncmp(address, "fqdn=", 5) == 0) {
wpa_printf(MSG_INFO, "Use requested FQDN from command line");
os_snprintf(buf, sizeof(buf), "%s", address + 5);
address = NULL;
@@ -3133,20 +3133,12 @@ int main(int argc, char *argv[])
usage();
exit(0);
}
- if (argc - optind < 2)
- wpa_printf(MSG_ERROR, "Server URL missing from command line");
- else
- ret = cmd_sub_rem(&ctx, argv[optind + 1],
- argc > optind + 2 ?
- argv[optind + 2] : NULL,
- argc > optind + 3 ?
- argv[optind + 3] : NULL);
+ ret = cmd_sub_rem(&ctx, argv[optind + 1],
+ argc > optind + 2 ? argv[optind + 2] : NULL,
+ argc > optind + 3 ? argv[optind + 3] : NULL);
} else if (strcmp(argv[optind], "pol_upd") == 0) {
- if (argc - optind < 2) {
- usage();
- exit(0);
- }
- ret = cmd_pol_upd(&ctx, argc > 2 ? argv[optind + 1] : NULL,
+ ret = cmd_pol_upd(&ctx,
+ argc > optind + 1 ? argv[optind + 1] : NULL,
argc > optind + 2 ? argv[optind + 2] : NULL,
argc > optind + 3 ? argv[optind + 3] : NULL);
} else if (strcmp(argv[optind], "prov") == 0) {
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 0720e141..19bff7bb 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -685,12 +685,12 @@ void handle_probe_req(struct hostapd_data *hapd,
u16 csa_offs[2];
size_t csa_offs_len;
- ie = mgmt->u.probe_req.variable;
- if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
+ if (len < IEEE80211_HDRLEN)
return;
+ ie = ((const u8 *) mgmt) + IEEE80211_HDRLEN;
if (hapd->iconf->track_sta_max_num)
sta_track_add(hapd->iface, mgmt->sa);
- ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
+ ie_len = len - IEEE80211_HDRLEN;
for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++)
if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 9f249d74..317b238c 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -568,3 +568,16 @@ int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd)
{
return hostapd_drv_stop_ap(hapd);
}
+
+
+int hostapd_ctrl_iface_pmksa_list(struct hostapd_data *hapd, char *buf,
+ size_t len)
+{
+ return wpa_auth_pmksa_list(hapd->wpa_auth, buf, len);
+}
+
+
+void hostapd_ctrl_iface_pmksa_flush(struct hostapd_data *hapd)
+{
+ wpa_auth_pmksa_flush(hapd->wpa_auth);
+}
diff --git a/src/ap/ctrl_iface_ap.h b/src/ap/ctrl_iface_ap.h
index e5297d03..3ad622f0 100644
--- a/src/ap/ctrl_iface_ap.h
+++ b/src/ap/ctrl_iface_ap.h
@@ -24,5 +24,8 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
int hostapd_parse_csa_settings(const char *pos,
struct csa_settings *settings);
int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd);
+int hostapd_ctrl_iface_pmksa_list(struct hostapd_data *hapd, char *buf,
+ size_t len);
+void hostapd_ctrl_iface_pmksa_flush(struct hostapd_data *hapd);
#endif /* CTRL_IFACE_AP_H */
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index f54d1ade..3ab5bf39 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -1353,4 +1353,31 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
}
}
+
+void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event,
+ union wpa_event_data *data)
+{
+ struct hapd_interfaces *interfaces = ctx;
+ struct hostapd_data *hapd;
+
+ if (event != EVENT_INTERFACE_STATUS)
+ return;
+
+ hapd = hostapd_get_iface(interfaces, data->interface_status.ifname);
+ if (hapd && hapd->driver && hapd->driver->get_ifindex &&
+ hapd->drv_priv) {
+ unsigned int ifindex;
+
+ ifindex = hapd->driver->get_ifindex(hapd->drv_priv);
+ if (ifindex != data->interface_status.ifindex) {
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
+ "interface status ifindex %d mismatch (%d)",
+ ifindex, data->interface_status.ifindex);
+ return;
+ }
+ }
+ if (hapd)
+ wpa_supplicant_event(hapd, event, data);
+}
+
#endif /* HOSTAPD */
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 55ca9e8f..ee80f4f7 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -3090,6 +3090,8 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface,
hostapd_enable_iface(iface);
}
+#endif /* NEED_AP_MLME */
+
struct hostapd_data * hostapd_get_iface(struct hapd_interfaces *interfaces,
const char *ifname)
@@ -3110,8 +3112,6 @@ struct hostapd_data * hostapd_get_iface(struct hapd_interfaces *interfaces,
return NULL;
}
-#endif /* NEED_AP_MLME */
-
void hostapd_periodic_iface(struct hostapd_iface *iface)
{
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 60516aec..75a7c049 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -262,6 +262,7 @@ struct hostapd_data {
struct sta_info *sta);
struct wpabuf *mesh_pending_auth;
struct os_reltime mesh_pending_auth_time;
+ u8 mesh_required_peer[ETH_ALEN];
#endif /* CONFIG_MESH */
#ifdef CONFIG_SQLITE
diff --git a/src/ap/iapp.c b/src/ap/iapp.c
index 99aa04dc..07672ce8 100644
--- a/src/ap/iapp.c
+++ b/src/ap/iapp.c
@@ -34,11 +34,7 @@
#include "utils/includes.h"
#include <net/if.h>
#include <sys/ioctl.h>
-#ifdef USE_KERNEL_HEADERS
-#include <linux/if_packet.h>
-#else /* USE_KERNEL_HEADERS */
#include <netpacket/packet.h>
-#endif /* USE_KERNEL_HEADERS */
#include "utils/common.h"
#include "utils/eloop.h"
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 134ae062..6a373c54 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -554,6 +554,18 @@ static void sae_set_retransmit_timer(struct hostapd_data *hapd,
}
+void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ sta->flags |= WLAN_STA_AUTH;
+ sta->auth_alg = WLAN_AUTH_SAE;
+ mlme_authenticate_indication(hapd, sta);
+ wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
+ sta->sae->state = SAE_ACCEPTED;
+ wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
+ sta->sae->pmk, sta->sae->pmkid);
+}
+
+
static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *bssid, u8 auth_transaction)
{
@@ -676,13 +688,7 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
sae_set_retransmit_timer(hapd, sta);
} else {
- sta->flags |= WLAN_STA_AUTH;
- sta->auth_alg = WLAN_AUTH_SAE;
- mlme_authenticate_indication(hapd, sta);
- wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
- sta->sae->state = SAE_ACCEPTED;
- wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
- sta->sae->pmk, sta->sae->pmkid);
+ sae_accept_sta(hapd, sta);
}
break;
case SAE_ACCEPTED:
@@ -691,6 +697,7 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
") doing reauthentication",
MAC2STR(sta->addr));
ap_free_sta(hapd, sta);
+ wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
} else {
if (sae_check_big_sync(sta))
return WLAN_STATUS_SUCCESS;
@@ -733,6 +740,13 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
sta->sae->sync = 0;
}
+ if (sta->mesh_sae_pmksa_caching) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Cancel use of mesh PMKSA caching because peer starts SAE authentication");
+ wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
+ sta->mesh_sae_pmksa_caching = 0;
+ }
+
if (auth_transaction == 1) {
const u8 *token = NULL, *pos, *end;
size_t token_len = 0;
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 1a96b331..71b3b497 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -102,6 +102,7 @@ int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta);
#ifdef CONFIG_SAE
void sae_clear_retransmit_timer(struct hostapd_data *hapd,
struct sta_info *sta);
+void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta);
#else /* CONFIG_SAE */
static inline void sae_clear_retransmit_timer(struct hostapd_data *hapd,
struct sta_info *sta)
diff --git a/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c
index 30be30c2..d610e7e5 100644
--- a/src/ap/pmksa_cache_auth.c
+++ b/src/ap/pmksa_cache_auth.c
@@ -92,6 +92,20 @@ void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
}
+/**
+ * pmksa_cache_auth_flush - Flush all PMKSA cache entries
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
+ */
+void pmksa_cache_auth_flush(struct rsn_pmksa_cache *pmksa)
+{
+ while (pmksa->pmksa) {
+ wpa_printf(MSG_DEBUG, "RSN: Flush PMKSA cache entry for "
+ MACSTR, MAC2STR(pmksa->pmksa->spa));
+ pmksa_cache_free_entry(pmksa, pmksa->pmksa);
+ }
+}
+
+
static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
{
struct rsn_pmksa_cache *pmksa = eloop_ctx;
@@ -167,8 +181,6 @@ void pmksa_cache_to_eapol_data(struct hostapd_data *hapd,
struct rsn_pmksa_cache_entry *entry,
struct eapol_state_machine *eapol)
{
- struct sta_info *sta;
-
if (entry == NULL || eapol == NULL)
return;
@@ -199,8 +211,9 @@ void pmksa_cache_to_eapol_data(struct hostapd_data *hapd,
}
eapol->eap_type_authsrv = entry->eap_type_authsrv;
- sta = (struct sta_info *) eapol->sta;
- ap_sta_set_vlan(hapd, sta, entry->vlan_desc);
+#ifndef CONFIG_NO_VLAN
+ ap_sta_set_vlan(hapd, eapol->sta, entry->vlan_desc);
+#endif /* CONFIG_NO_VLAN */
eapol->acct_multi_session_id = entry->acct_multi_session_id;
}
@@ -547,3 +560,48 @@ int pmksa_cache_auth_radius_das_disconnect(struct rsn_pmksa_cache *pmksa,
return found ? 0 : -1;
}
+
+
+/**
+ * pmksa_cache_auth_list - Dump text list of entries in PMKSA cache
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
+ * @buf: Buffer for the list
+ * @len: Length of the buffer
+ * Returns: Number of bytes written to buffer
+ *
+ * This function is used to generate a text format representation of the
+ * current PMKSA cache contents for the ctrl_iface PMKSA command.
+ */
+int pmksa_cache_auth_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len)
+{
+ int i, ret;
+ char *pos = buf;
+ struct rsn_pmksa_cache_entry *entry;
+ struct os_reltime now;
+
+ os_get_reltime(&now);
+ ret = os_snprintf(pos, buf + len - pos,
+ "Index / SPA / PMKID / expiration (in seconds) / opportunistic\n");
+ if (os_snprintf_error(buf + len - pos, ret))
+ return pos - buf;
+ pos += ret;
+ i = 0;
+ entry = pmksa->pmksa;
+ while (entry) {
+ ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " ",
+ i, MAC2STR(entry->spa));
+ if (os_snprintf_error(buf + len - pos, ret))
+ return pos - buf;
+ pos += ret;
+ pos += wpa_snprintf_hex(pos, buf + len - pos, entry->pmkid,
+ PMKID_LEN);
+ ret = os_snprintf(pos, buf + len - pos, " %d %d\n",
+ (int) (entry->expiration - now.sec),
+ entry->opportunistic);
+ if (os_snprintf_error(buf + len - pos, ret))
+ return pos - buf;
+ pos += ret;
+ entry = entry->next;
+ }
+ return pos - buf;
+}
diff --git a/src/ap/pmksa_cache_auth.h b/src/ap/pmksa_cache_auth.h
index 3e602771..d8d9c5a2 100644
--- a/src/ap/pmksa_cache_auth.h
+++ b/src/ap/pmksa_cache_auth.h
@@ -63,5 +63,7 @@ void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
struct rsn_pmksa_cache_entry *entry);
int pmksa_cache_auth_radius_das_disconnect(struct rsn_pmksa_cache *pmksa,
struct radius_das_attrs *attr);
+int pmksa_cache_auth_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len);
+void pmksa_cache_auth_flush(struct rsn_pmksa_cache *pmksa);
#endif /* PMKSA_CACHE_H */
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 70a59ccd..3d9a928a 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -183,6 +183,7 @@ struct sta_info {
#ifdef CONFIG_SAE
struct sae_data *sae;
+ unsigned int mesh_sae_pmksa_caching:1;
#endif /* CONFIG_SAE */
u32 session_timeout; /* valid only if session_timeout_set == 1 */
diff --git a/src/ap/vlan_full.c b/src/ap/vlan_full.c
new file mode 100644
index 00000000..aa42335b
--- /dev/null
+++ b/src/ap/vlan_full.c
@@ -0,0 +1,752 @@
+/*
+ * hostapd / VLAN initialization - full dynamic VLAN
+ * Copyright 2003, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include <net/if.h>
+/* Avoid conflicts due to NetBSD net/if.h if_type define with driver.h */
+#undef if_type
+#include <sys/ioctl.h>
+
+#include "utils/common.h"
+#include "drivers/priv_netlink.h"
+#include "common/linux_bridge.h"
+#include "common/linux_vlan.h"
+#include "utils/eloop.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "ap_drv_ops.h"
+#include "wpa_auth.h"
+#include "vlan_init.h"
+#include "vlan_util.h"
+
+
+struct full_dynamic_vlan {
+ int s; /* socket on which to listen for new/removed interfaces. */
+};
+
+#define DVLAN_CLEAN_BR 0x1
+#define DVLAN_CLEAN_VLAN 0x2
+#define DVLAN_CLEAN_VLAN_PORT 0x4
+
+struct dynamic_iface {
+ char ifname[IFNAMSIZ + 1];
+ int usage;
+ int clean;
+ struct dynamic_iface *next;
+};
+
+
+/* Increment ref counter for ifname and add clean flag.
+ * If not in list, add it only if some flags are given.
+ */
+static void dyn_iface_get(struct hostapd_data *hapd, const char *ifname,
+ int clean)
+{
+ struct dynamic_iface *next, **dynamic_ifaces;
+ struct hapd_interfaces *interfaces;
+
+ interfaces = hapd->iface->interfaces;
+ dynamic_ifaces = &interfaces->vlan_priv;
+
+ for (next = *dynamic_ifaces; next; next = next->next) {
+ if (os_strcmp(ifname, next->ifname) == 0)
+ break;
+ }
+
+ if (next) {
+ next->usage++;
+ next->clean |= clean;
+ return;
+ }
+
+ if (!clean)
+ return;
+
+ next = os_zalloc(sizeof(*next));
+ if (!next)
+ return;
+ os_strlcpy(next->ifname, ifname, sizeof(next->ifname));
+ next->usage = 1;
+ next->clean = clean;
+ next->next = *dynamic_ifaces;
+ *dynamic_ifaces = next;
+}
+
+
+/* Decrement reference counter for given ifname.
+ * Return clean flag iff reference counter was decreased to zero, else zero
+ */
+static int dyn_iface_put(struct hostapd_data *hapd, const char *ifname)
+{
+ struct dynamic_iface *next, *prev = NULL, **dynamic_ifaces;
+ struct hapd_interfaces *interfaces;
+ int clean;
+
+ interfaces = hapd->iface->interfaces;
+ dynamic_ifaces = &interfaces->vlan_priv;
+
+ for (next = *dynamic_ifaces; next; next = next->next) {
+ if (os_strcmp(ifname, next->ifname) == 0)
+ break;
+ prev = next;
+ }
+
+ if (!next)
+ return 0;
+
+ next->usage--;
+ if (next->usage)
+ return 0;
+
+ if (prev)
+ prev->next = next->next;
+ else
+ *dynamic_ifaces = next->next;
+ clean = next->clean;
+ os_free(next);
+
+ return clean;
+}
+
+
+static int ifconfig_down(const char *if_name)
+{
+ wpa_printf(MSG_DEBUG, "VLAN: Set interface %s down", if_name);
+ return ifconfig_helper(if_name, 0);
+}
+
+
+/* This value should be 256 ONLY. If it is something else, then hostapd
+ * might crash!, as this value has been hard-coded in 2.4.x kernel
+ * bridging code.
+ */
+#define MAX_BR_PORTS 256
+
+static int br_delif(const char *br_name, const char *if_name)
+{
+ int fd;
+ struct ifreq ifr;
+ unsigned long args[2];
+ int if_index;
+
+ wpa_printf(MSG_DEBUG, "VLAN: br_delif(%s, %s)", br_name, if_name);
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+ "failed: %s", __func__, strerror(errno));
+ return -1;
+ }
+
+ if_index = if_nametoindex(if_name);
+
+ if (if_index == 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
+ "interface index for '%s'",
+ __func__, if_name);
+ close(fd);
+ return -1;
+ }
+
+ args[0] = BRCTL_DEL_IF;
+ args[1] = if_index;
+
+ os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
+ ifr.ifr_data = (void *) args;
+
+ if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0 && errno != EINVAL) {
+ /* No error if interface already removed. */
+ wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
+ "BRCTL_DEL_IF] failed for br_name=%s if_name=%s: "
+ "%s", __func__, br_name, if_name, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+}
+
+
+/*
+ Add interface 'if_name' to the bridge 'br_name'
+
+ returns -1 on error
+ returns 1 if the interface is already part of the bridge
+ returns 0 otherwise
+*/
+static int br_addif(const char *br_name, const char *if_name)
+{
+ int fd;
+ struct ifreq ifr;
+ unsigned long args[2];
+ int if_index;
+
+ wpa_printf(MSG_DEBUG, "VLAN: br_addif(%s, %s)", br_name, if_name);
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+ "failed: %s", __func__, strerror(errno));
+ return -1;
+ }
+
+ if_index = if_nametoindex(if_name);
+
+ if (if_index == 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
+ "interface index for '%s'",
+ __func__, if_name);
+ close(fd);
+ return -1;
+ }
+
+ args[0] = BRCTL_ADD_IF;
+ args[1] = if_index;
+
+ os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
+ ifr.ifr_data = (void *) args;
+
+ if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
+ if (errno == EBUSY) {
+ /* The interface is already added. */
+ close(fd);
+ return 1;
+ }
+
+ wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
+ "BRCTL_ADD_IF] failed for br_name=%s if_name=%s: "
+ "%s", __func__, br_name, if_name, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+}
+
+
+static int br_delbr(const char *br_name)
+{
+ int fd;
+ unsigned long arg[2];
+
+ wpa_printf(MSG_DEBUG, "VLAN: br_delbr(%s)", br_name);
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+ "failed: %s", __func__, strerror(errno));
+ return -1;
+ }
+
+ arg[0] = BRCTL_DEL_BRIDGE;
+ arg[1] = (unsigned long) br_name;
+
+ if (ioctl(fd, SIOCGIFBR, arg) < 0 && errno != ENXIO) {
+ /* No error if bridge already removed. */
+ wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_DEL_BRIDGE failed for "
+ "%s: %s", __func__, br_name, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+}
+
+
+/*
+ Add a bridge with the name 'br_name'.
+
+ returns -1 on error
+ returns 1 if the bridge already exists
+ returns 0 otherwise
+*/
+static int br_addbr(const char *br_name)
+{
+ int fd;
+ unsigned long arg[4];
+ struct ifreq ifr;
+
+ wpa_printf(MSG_DEBUG, "VLAN: br_addbr(%s)", br_name);
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+ "failed: %s", __func__, strerror(errno));
+ return -1;
+ }
+
+ arg[0] = BRCTL_ADD_BRIDGE;
+ arg[1] = (unsigned long) br_name;
+
+ if (ioctl(fd, SIOCGIFBR, arg) < 0) {
+ if (errno == EEXIST) {
+ /* The bridge is already added. */
+ close(fd);
+ return 1;
+ } else {
+ wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_ADD_BRIDGE "
+ "failed for %s: %s",
+ __func__, br_name, strerror(errno));
+ close(fd);
+ return -1;
+ }
+ }
+
+ /* Decrease forwarding delay to avoid EAPOL timeouts. */
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, br_name, IFNAMSIZ);
+ arg[0] = BRCTL_SET_BRIDGE_FORWARD_DELAY;
+ arg[1] = 1;
+ arg[2] = 0;
+ arg[3] = 0;
+ ifr.ifr_data = (char *) &arg;
+ if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: "
+ "BRCTL_SET_BRIDGE_FORWARD_DELAY (1 sec) failed for "
+ "%s: %s", __func__, br_name, strerror(errno));
+ /* Continue anyway */
+ }
+
+ close(fd);
+ return 0;
+}
+
+
+static int br_getnumports(const char *br_name)
+{
+ int fd;
+ int i;
+ int port_cnt = 0;
+ unsigned long arg[4];
+ int ifindices[MAX_BR_PORTS];
+ struct ifreq ifr;
+
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+ "failed: %s", __func__, strerror(errno));
+ return -1;
+ }
+
+ arg[0] = BRCTL_GET_PORT_LIST;
+ arg[1] = (unsigned long) ifindices;
+ arg[2] = MAX_BR_PORTS;
+ arg[3] = 0;
+
+ os_memset(ifindices, 0, sizeof(ifindices));
+ os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
+ ifr.ifr_data = (void *) arg;
+
+ if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_GET_PORT_LIST "
+ "failed for %s: %s",
+ __func__, br_name, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ for (i = 1; i < MAX_BR_PORTS; i++) {
+ if (ifindices[i] > 0) {
+ port_cnt++;
+ }
+ }
+
+ close(fd);
+ return port_cnt;
+}
+
+
+static void vlan_newlink_tagged(int vlan_naming, const char *tagged_interface,
+ const char *br_name, int vid,
+ struct hostapd_data *hapd)
+{
+ char vlan_ifname[IFNAMSIZ];
+ int clean;
+
+ if (vlan_naming == DYNAMIC_VLAN_NAMING_WITH_DEVICE)
+ os_snprintf(vlan_ifname, sizeof(vlan_ifname), "%s.%d",
+ tagged_interface, vid);
+ else
+ os_snprintf(vlan_ifname, sizeof(vlan_ifname), "vlan%d", vid);
+
+ clean = 0;
+ ifconfig_up(tagged_interface);
+ if (!vlan_add(tagged_interface, vid, vlan_ifname))
+ clean |= DVLAN_CLEAN_VLAN;
+
+ if (!br_addif(br_name, vlan_ifname))
+ clean |= DVLAN_CLEAN_VLAN_PORT;
+
+ dyn_iface_get(hapd, vlan_ifname, clean);
+
+ ifconfig_up(vlan_ifname);
+}
+
+
+static void vlan_bridge_name(char *br_name, struct hostapd_data *hapd, int vid)
+{
+ char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
+
+ if (hapd->conf->vlan_bridge[0]) {
+ os_snprintf(br_name, IFNAMSIZ, "%s%d",
+ hapd->conf->vlan_bridge, vid);
+ } else if (tagged_interface) {
+ os_snprintf(br_name, IFNAMSIZ, "br%s.%d",
+ tagged_interface, vid);
+ } else {
+ os_snprintf(br_name, IFNAMSIZ, "brvlan%d", vid);
+ }
+}
+
+
+static void vlan_get_bridge(const char *br_name, struct hostapd_data *hapd,
+ int vid)
+{
+ char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
+ int vlan_naming = hapd->conf->ssid.vlan_naming;
+
+ dyn_iface_get(hapd, br_name, br_addbr(br_name) ? 0 : DVLAN_CLEAN_BR);
+
+ ifconfig_up(br_name);
+
+ if (tagged_interface)
+ vlan_newlink_tagged(vlan_naming, tagged_interface, br_name,
+ vid, hapd);
+}
+
+
+void vlan_newlink(const char *ifname, struct hostapd_data *hapd)
+{
+ char br_name[IFNAMSIZ];
+ struct hostapd_vlan *vlan;
+ int untagged, *tagged, i, notempty;
+
+ wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
+
+ for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
+ if (vlan->configured ||
+ os_strcmp(ifname, vlan->ifname) != 0)
+ continue;
+ break;
+ }
+ if (!vlan)
+ return;
+
+ vlan->configured = 1;
+
+ notempty = vlan->vlan_desc.notempty;
+ untagged = vlan->vlan_desc.untagged;
+ tagged = vlan->vlan_desc.tagged;
+
+ if (!notempty) {
+ /* Non-VLAN STA */
+ if (hapd->conf->bridge[0] &&
+ !br_addif(hapd->conf->bridge, ifname))
+ vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
+ } else if (untagged > 0 && untagged <= MAX_VLAN_ID) {
+ vlan_bridge_name(br_name, hapd, untagged);
+
+ vlan_get_bridge(br_name, hapd, untagged);
+
+ if (!br_addif(br_name, ifname))
+ vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
+ }
+
+ for (i = 0; i < MAX_NUM_TAGGED_VLAN && tagged[i]; i++) {
+ if (tagged[i] == untagged ||
+ tagged[i] <= 0 || tagged[i] > MAX_VLAN_ID ||
+ (i > 0 && tagged[i] == tagged[i - 1]))
+ continue;
+ vlan_bridge_name(br_name, hapd, tagged[i]);
+ vlan_get_bridge(br_name, hapd, tagged[i]);
+ vlan_newlink_tagged(DYNAMIC_VLAN_NAMING_WITH_DEVICE,
+ ifname, br_name, tagged[i], hapd);
+ }
+
+ ifconfig_up(ifname);
+}
+
+
+static void vlan_dellink_tagged(int vlan_naming, const char *tagged_interface,
+ const char *br_name, int vid,
+ struct hostapd_data *hapd)
+{
+ char vlan_ifname[IFNAMSIZ];
+ int clean;
+
+ if (vlan_naming == DYNAMIC_VLAN_NAMING_WITH_DEVICE)
+ os_snprintf(vlan_ifname, sizeof(vlan_ifname), "%s.%d",
+ tagged_interface, vid);
+ else
+ os_snprintf(vlan_ifname, sizeof(vlan_ifname), "vlan%d", vid);
+
+ clean = dyn_iface_put(hapd, vlan_ifname);
+
+ if (clean & DVLAN_CLEAN_VLAN_PORT)
+ br_delif(br_name, vlan_ifname);
+
+ if (clean & DVLAN_CLEAN_VLAN) {
+ ifconfig_down(vlan_ifname);
+ vlan_rem(vlan_ifname);
+ }
+}
+
+
+static void vlan_put_bridge(const char *br_name, struct hostapd_data *hapd,
+ int vid)
+{
+ int clean;
+ char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
+ int vlan_naming = hapd->conf->ssid.vlan_naming;
+
+ if (tagged_interface)
+ vlan_dellink_tagged(vlan_naming, tagged_interface, br_name,
+ vid, hapd);
+
+ clean = dyn_iface_put(hapd, br_name);
+ if ((clean & DVLAN_CLEAN_BR) && br_getnumports(br_name) == 0) {
+ ifconfig_down(br_name);
+ br_delbr(br_name);
+ }
+}
+
+
+void vlan_dellink(const char *ifname, struct hostapd_data *hapd)
+{
+ struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan;
+
+ wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname);
+
+ first = prev = vlan;
+
+ while (vlan) {
+ if (os_strcmp(ifname, vlan->ifname) != 0) {
+ prev = vlan;
+ vlan = vlan->next;
+ continue;
+ }
+ break;
+ }
+ if (!vlan)
+ return;
+
+ if (vlan->configured) {
+ int notempty = vlan->vlan_desc.notempty;
+ int untagged = vlan->vlan_desc.untagged;
+ int *tagged = vlan->vlan_desc.tagged;
+ char br_name[IFNAMSIZ];
+ int i;
+
+ for (i = 0; i < MAX_NUM_TAGGED_VLAN && tagged[i]; i++) {
+ if (tagged[i] == untagged ||
+ tagged[i] <= 0 || tagged[i] > MAX_VLAN_ID ||
+ (i > 0 && tagged[i] == tagged[i - 1]))
+ continue;
+ vlan_bridge_name(br_name, hapd, tagged[i]);
+ vlan_dellink_tagged(DYNAMIC_VLAN_NAMING_WITH_DEVICE,
+ ifname, br_name, tagged[i], hapd);
+ vlan_put_bridge(br_name, hapd, tagged[i]);
+ }
+
+ if (!notempty) {
+ /* Non-VLAN STA */
+ if (hapd->conf->bridge[0] &&
+ (vlan->clean & DVLAN_CLEAN_WLAN_PORT))
+ br_delif(hapd->conf->bridge, ifname);
+ } else if (untagged > 0 && untagged <= MAX_VLAN_ID) {
+ vlan_bridge_name(br_name, hapd, untagged);
+
+ if (vlan->clean & DVLAN_CLEAN_WLAN_PORT)
+ br_delif(br_name, vlan->ifname);
+
+ vlan_put_bridge(br_name, hapd, untagged);
+ }
+ }
+
+ /*
+ * Ensure this VLAN interface is actually removed even if
+ * NEWLINK message is only received later.
+ */
+ if (if_nametoindex(vlan->ifname) && vlan_if_remove(hapd, vlan))
+ wpa_printf(MSG_ERROR,
+ "VLAN: Could not remove VLAN iface: %s: %s",
+ vlan->ifname, strerror(errno));
+
+ if (vlan == first)
+ hapd->conf->vlan = vlan->next;
+ else
+ prev->next = vlan->next;
+
+ os_free(vlan);
+}
+
+
+static void
+vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del,
+ struct hostapd_data *hapd)
+{
+ struct ifinfomsg *ifi;
+ int attrlen, nlmsg_len, rta_len;
+ struct rtattr *attr;
+ char ifname[IFNAMSIZ + 1];
+
+ if (len < sizeof(*ifi))
+ return;
+
+ ifi = NLMSG_DATA(h);
+
+ nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
+
+ attrlen = h->nlmsg_len - nlmsg_len;
+ if (attrlen < 0)
+ return;
+
+ attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
+
+ os_memset(ifname, 0, sizeof(ifname));
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ while (RTA_OK(attr, attrlen)) {
+ if (attr->rta_type == IFLA_IFNAME) {
+ int n = attr->rta_len - rta_len;
+ if (n < 0)
+ break;
+
+ if ((size_t) n >= sizeof(ifname))
+ n = sizeof(ifname) - 1;
+ os_memcpy(ifname, ((char *) attr) + rta_len, n);
+
+ }
+
+ attr = RTA_NEXT(attr, attrlen);
+ }
+
+ if (!ifname[0])
+ return;
+ if (del && if_nametoindex(ifname)) {
+ /* interface still exists, race condition ->
+ * iface has just been recreated */
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "VLAN: RTM_%sLINK: ifi_index=%d ifname=%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
+ del ? "DEL" : "NEW",
+ ifi->ifi_index, ifname, ifi->ifi_family, ifi->ifi_flags,
+ (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
+ (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
+ (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
+ (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
+
+ if (del)
+ vlan_dellink(ifname, hapd);
+ else
+ vlan_newlink(ifname, hapd);
+}
+
+
+static void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ char buf[8192];
+ int left;
+ struct sockaddr_nl from;
+ socklen_t fromlen;
+ struct nlmsghdr *h;
+ struct hostapd_data *hapd = eloop_ctx;
+
+ fromlen = sizeof(from);
+ left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
+ (struct sockaddr *) &from, &fromlen);
+ if (left < 0) {
+ if (errno != EINTR && errno != EAGAIN)
+ wpa_printf(MSG_ERROR, "VLAN: %s: recvfrom failed: %s",
+ __func__, strerror(errno));
+ return;
+ }
+
+ h = (struct nlmsghdr *) buf;
+ while (NLMSG_OK(h, left)) {
+ int len, plen;
+
+ len = h->nlmsg_len;
+ plen = len - sizeof(*h);
+ if (len > left || plen < 0) {
+ wpa_printf(MSG_DEBUG, "VLAN: Malformed netlink "
+ "message: len=%d left=%d plen=%d",
+ len, left, plen);
+ break;
+ }
+
+ switch (h->nlmsg_type) {
+ case RTM_NEWLINK:
+ vlan_read_ifnames(h, plen, 0, hapd);
+ break;
+ case RTM_DELLINK:
+ vlan_read_ifnames(h, plen, 1, hapd);
+ break;
+ }
+
+ h = NLMSG_NEXT(h, left);
+ }
+
+ if (left > 0) {
+ wpa_printf(MSG_DEBUG, "VLAN: %s: %d extra bytes in the end of "
+ "netlink message", __func__, left);
+ }
+}
+
+
+struct full_dynamic_vlan *
+full_dynamic_vlan_init(struct hostapd_data *hapd)
+{
+ struct sockaddr_nl local;
+ struct full_dynamic_vlan *priv;
+
+ priv = os_zalloc(sizeof(*priv));
+ if (priv == NULL)
+ return NULL;
+
+ vlan_set_name_type(hapd->conf->ssid.vlan_naming ==
+ DYNAMIC_VLAN_NAMING_WITH_DEVICE ?
+ VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD :
+ VLAN_NAME_TYPE_PLUS_VID_NO_PAD);
+
+ priv->s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (priv->s < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: socket(PF_NETLINK,SOCK_RAW,"
+ "NETLINK_ROUTE) failed: %s",
+ __func__, strerror(errno));
+ os_free(priv);
+ return NULL;
+ }
+
+ os_memset(&local, 0, sizeof(local));
+ local.nl_family = AF_NETLINK;
+ local.nl_groups = RTMGRP_LINK;
+ if (bind(priv->s, (struct sockaddr *) &local, sizeof(local)) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: bind(netlink) failed: %s",
+ __func__, strerror(errno));
+ close(priv->s);
+ os_free(priv);
+ return NULL;
+ }
+
+ if (eloop_register_read_sock(priv->s, vlan_event_receive, hapd, NULL))
+ {
+ close(priv->s);
+ os_free(priv);
+ return NULL;
+ }
+
+ return priv;
+}
+
+
+void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv)
+{
+ if (priv == NULL)
+ return;
+ eloop_unregister_read_sock(priv->s);
+ close(priv->s);
+ os_free(priv);
+}
diff --git a/src/ap/vlan_ifconfig.c b/src/ap/vlan_ifconfig.c
new file mode 100644
index 00000000..ef953a5c
--- /dev/null
+++ b/src/ap/vlan_ifconfig.c
@@ -0,0 +1,69 @@
+/*
+ * hostapd / VLAN ifconfig helpers
+ * Copyright 2003, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include <net/if.h>
+#include <sys/ioctl.h>
+
+#include "utils/common.h"
+#include "vlan_util.h"
+
+
+int ifconfig_helper(const char *if_name, int up)
+{
+ int fd;
+ struct ifreq ifr;
+
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+ "failed: %s", __func__, strerror(errno));
+ return -1;
+ }
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, if_name, IFNAMSIZ);
+
+ if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCGIFFLAGS) failed "
+ "for interface %s: %s",
+ __func__, if_name, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ if (up)
+ ifr.ifr_flags |= IFF_UP;
+ else
+ ifr.ifr_flags &= ~IFF_UP;
+
+ if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCSIFFLAGS) failed "
+ "for interface %s (up=%d): %s",
+ __func__, if_name, up, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+}
+
+
+int ifconfig_up(const char *if_name)
+{
+ wpa_printf(MSG_DEBUG, "VLAN: Set interface %s up", if_name);
+ return ifconfig_helper(if_name, 1);
+}
+
+
+int iface_exists(const char *ifname)
+{
+ return if_nametoindex(ifname);
+}
diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c
index 45d1a1c8..31e4fc6b 100644
--- a/src/ap/vlan_init.c
+++ b/src/ap/vlan_init.c
@@ -18,158 +18,6 @@
#include "vlan_init.h"
#include "vlan_util.h"
-#include <net/if.h>
-#include <sys/ioctl.h>
-#ifdef CONFIG_FULL_DYNAMIC_VLAN
-#include <linux/sockios.h>
-#include <linux/if_vlan.h>
-#include <linux/if_bridge.h>
-#endif /* CONFIG_FULL_DYNAMIC_VLAN */
-
-
-#ifdef CONFIG_FULL_DYNAMIC_VLAN
-
-#include "drivers/priv_netlink.h"
-#include "utils/eloop.h"
-
-
-struct full_dynamic_vlan {
- int s; /* socket on which to listen for new/removed interfaces. */
-};
-
-#define DVLAN_CLEAN_BR 0x1
-#define DVLAN_CLEAN_VLAN 0x2
-#define DVLAN_CLEAN_VLAN_PORT 0x4
-
-struct dynamic_iface {
- char ifname[IFNAMSIZ + 1];
- int usage;
- int clean;
- struct dynamic_iface *next;
-};
-
-
-/* Increment ref counter for ifname and add clean flag.
- * If not in list, add it only if some flags are given.
- */
-static void dyn_iface_get(struct hostapd_data *hapd, const char *ifname,
- int clean)
-{
- struct dynamic_iface *next, **dynamic_ifaces;
- struct hapd_interfaces *interfaces;
-
- interfaces = hapd->iface->interfaces;
- dynamic_ifaces = &interfaces->vlan_priv;
-
- for (next = *dynamic_ifaces; next; next = next->next) {
- if (os_strcmp(ifname, next->ifname) == 0)
- break;
- }
-
- if (next) {
- next->usage++;
- next->clean |= clean;
- return;
- }
-
- if (!clean)
- return;
-
- next = os_zalloc(sizeof(*next));
- if (!next)
- return;
- os_strlcpy(next->ifname, ifname, sizeof(next->ifname));
- next->usage = 1;
- next->clean = clean;
- next->next = *dynamic_ifaces;
- *dynamic_ifaces = next;
-}
-
-
-/* Decrement reference counter for given ifname.
- * Return clean flag iff reference counter was decreased to zero, else zero
- */
-static int dyn_iface_put(struct hostapd_data *hapd, const char *ifname)
-{
- struct dynamic_iface *next, *prev = NULL, **dynamic_ifaces;
- struct hapd_interfaces *interfaces;
- int clean;
-
- interfaces = hapd->iface->interfaces;
- dynamic_ifaces = &interfaces->vlan_priv;
-
- for (next = *dynamic_ifaces; next; next = next->next) {
- if (os_strcmp(ifname, next->ifname) == 0)
- break;
- prev = next;
- }
-
- if (!next)
- return 0;
-
- next->usage--;
- if (next->usage)
- return 0;
-
- if (prev)
- prev->next = next->next;
- else
- *dynamic_ifaces = next->next;
- clean = next->clean;
- os_free(next);
-
- return clean;
-}
-
-#endif /* CONFIG_FULL_DYNAMIC_VLAN */
-
-
-static int ifconfig_helper(const char *if_name, int up)
-{
- int fd;
- struct ifreq ifr;
-
- if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
- "failed: %s", __func__, strerror(errno));
- return -1;
- }
-
- os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, if_name, IFNAMSIZ);
-
- if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCGIFFLAGS) failed "
- "for interface %s: %s",
- __func__, if_name, strerror(errno));
- close(fd);
- return -1;
- }
-
- if (up)
- ifr.ifr_flags |= IFF_UP;
- else
- ifr.ifr_flags &= ~IFF_UP;
-
- if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCSIFFLAGS) failed "
- "for interface %s (up=%d): %s",
- __func__, if_name, up, strerror(errno));
- close(fd);
- return -1;
- }
-
- close(fd);
- return 0;
-}
-
-
-static int ifconfig_up(const char *if_name)
-{
- wpa_printf(MSG_DEBUG, "VLAN: Set interface %s up", if_name);
- return ifconfig_helper(if_name, 1);
-}
-
static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
int existsok)
@@ -185,7 +33,7 @@ static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
return -1;
}
- if (!if_nametoindex(vlan->ifname))
+ if (!iface_exists(vlan->ifname))
ret = hostapd_vlan_if_add(hapd, vlan->ifname);
else if (!existsok)
return -1;
@@ -216,7 +64,7 @@ static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
}
-static int vlan_if_remove(struct hostapd_data *hapd, struct hostapd_vlan *vlan)
+int vlan_if_remove(struct hostapd_data *hapd, struct hostapd_vlan *vlan)
{
int ret;
@@ -230,798 +78,6 @@ static int vlan_if_remove(struct hostapd_data *hapd, struct hostapd_vlan *vlan)
}
-#ifdef CONFIG_FULL_DYNAMIC_VLAN
-
-static int ifconfig_down(const char *if_name)
-{
- wpa_printf(MSG_DEBUG, "VLAN: Set interface %s down", if_name);
- return ifconfig_helper(if_name, 0);
-}
-
-
-/*
- * These are only available in recent linux headers (without the leading
- * underscore).
- */
-#define _GET_VLAN_REALDEV_NAME_CMD 8
-#define _GET_VLAN_VID_CMD 9
-
-/* This value should be 256 ONLY. If it is something else, then hostapd
- * might crash!, as this value has been hard-coded in 2.4.x kernel
- * bridging code.
- */
-#define MAX_BR_PORTS 256
-
-static int br_delif(const char *br_name, const char *if_name)
-{
- int fd;
- struct ifreq ifr;
- unsigned long args[2];
- int if_index;
-
- wpa_printf(MSG_DEBUG, "VLAN: br_delif(%s, %s)", br_name, if_name);
- if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
- "failed: %s", __func__, strerror(errno));
- return -1;
- }
-
- if_index = if_nametoindex(if_name);
-
- if (if_index == 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
- "interface index for '%s'",
- __func__, if_name);
- close(fd);
- return -1;
- }
-
- args[0] = BRCTL_DEL_IF;
- args[1] = if_index;
-
- os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
- ifr.ifr_data = (__caddr_t) args;
-
- if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0 && errno != EINVAL) {
- /* No error if interface already removed. */
- wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
- "BRCTL_DEL_IF] failed for br_name=%s if_name=%s: "
- "%s", __func__, br_name, if_name, strerror(errno));
- close(fd);
- return -1;
- }
-
- close(fd);
- return 0;
-}
-
-
-/*
- Add interface 'if_name' to the bridge 'br_name'
-
- returns -1 on error
- returns 1 if the interface is already part of the bridge
- returns 0 otherwise
-*/
-static int br_addif(const char *br_name, const char *if_name)
-{
- int fd;
- struct ifreq ifr;
- unsigned long args[2];
- int if_index;
-
- wpa_printf(MSG_DEBUG, "VLAN: br_addif(%s, %s)", br_name, if_name);
- if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
- "failed: %s", __func__, strerror(errno));
- return -1;
- }
-
- if_index = if_nametoindex(if_name);
-
- if (if_index == 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
- "interface index for '%s'",
- __func__, if_name);
- close(fd);
- return -1;
- }
-
- args[0] = BRCTL_ADD_IF;
- args[1] = if_index;
-
- os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
- ifr.ifr_data = (__caddr_t) args;
-
- if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
- if (errno == EBUSY) {
- /* The interface is already added. */
- close(fd);
- return 1;
- }
-
- wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
- "BRCTL_ADD_IF] failed for br_name=%s if_name=%s: "
- "%s", __func__, br_name, if_name, strerror(errno));
- close(fd);
- return -1;
- }
-
- close(fd);
- return 0;
-}
-
-
-static int br_delbr(const char *br_name)
-{
- int fd;
- unsigned long arg[2];
-
- wpa_printf(MSG_DEBUG, "VLAN: br_delbr(%s)", br_name);
- if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
- "failed: %s", __func__, strerror(errno));
- return -1;
- }
-
- arg[0] = BRCTL_DEL_BRIDGE;
- arg[1] = (unsigned long) br_name;
-
- if (ioctl(fd, SIOCGIFBR, arg) < 0 && errno != ENXIO) {
- /* No error if bridge already removed. */
- wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_DEL_BRIDGE failed for "
- "%s: %s", __func__, br_name, strerror(errno));
- close(fd);
- return -1;
- }
-
- close(fd);
- return 0;
-}
-
-
-/*
- Add a bridge with the name 'br_name'.
-
- returns -1 on error
- returns 1 if the bridge already exists
- returns 0 otherwise
-*/
-static int br_addbr(const char *br_name)
-{
- int fd;
- unsigned long arg[4];
- struct ifreq ifr;
-
- wpa_printf(MSG_DEBUG, "VLAN: br_addbr(%s)", br_name);
- if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
- "failed: %s", __func__, strerror(errno));
- return -1;
- }
-
- arg[0] = BRCTL_ADD_BRIDGE;
- arg[1] = (unsigned long) br_name;
-
- if (ioctl(fd, SIOCGIFBR, arg) < 0) {
- if (errno == EEXIST) {
- /* The bridge is already added. */
- close(fd);
- return 1;
- } else {
- wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_ADD_BRIDGE "
- "failed for %s: %s",
- __func__, br_name, strerror(errno));
- close(fd);
- return -1;
- }
- }
-
- /* Decrease forwarding delay to avoid EAPOL timeouts. */
- os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, br_name, IFNAMSIZ);
- arg[0] = BRCTL_SET_BRIDGE_FORWARD_DELAY;
- arg[1] = 1;
- arg[2] = 0;
- arg[3] = 0;
- ifr.ifr_data = (char *) &arg;
- if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: "
- "BRCTL_SET_BRIDGE_FORWARD_DELAY (1 sec) failed for "
- "%s: %s", __func__, br_name, strerror(errno));
- /* Continue anyway */
- }
-
- close(fd);
- return 0;
-}
-
-
-static int br_getnumports(const char *br_name)
-{
- int fd;
- int i;
- int port_cnt = 0;
- unsigned long arg[4];
- int ifindices[MAX_BR_PORTS];
- struct ifreq ifr;
-
- if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
- "failed: %s", __func__, strerror(errno));
- return -1;
- }
-
- arg[0] = BRCTL_GET_PORT_LIST;
- arg[1] = (unsigned long) ifindices;
- arg[2] = MAX_BR_PORTS;
- arg[3] = 0;
-
- os_memset(ifindices, 0, sizeof(ifindices));
- os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
- ifr.ifr_data = (__caddr_t) arg;
-
- if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_GET_PORT_LIST "
- "failed for %s: %s",
- __func__, br_name, strerror(errno));
- close(fd);
- return -1;
- }
-
- for (i = 1; i < MAX_BR_PORTS; i++) {
- if (ifindices[i] > 0) {
- port_cnt++;
- }
- }
-
- close(fd);
- return port_cnt;
-}
-
-
-#ifndef CONFIG_VLAN_NETLINK
-
-int vlan_rem(const char *if_name)
-{
- int fd;
- struct vlan_ioctl_args if_request;
-
- wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(%s)", if_name);
- if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
- wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
- if_name);
- return -1;
- }
-
- if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
- "failed: %s", __func__, strerror(errno));
- return -1;
- }
-
- os_memset(&if_request, 0, sizeof(if_request));
-
- os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
- if_request.cmd = DEL_VLAN_CMD;
-
- if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: DEL_VLAN_CMD failed for %s: "
- "%s", __func__, if_name, strerror(errno));
- close(fd);
- return -1;
- }
-
- close(fd);
- return 0;
-}
-
-
-/*
- Add a vlan interface with VLAN ID 'vid' and tagged interface
- 'if_name'.
-
- returns -1 on error
- returns 1 if the interface already exists
- returns 0 otherwise
-*/
-int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
-{
- int fd;
- struct vlan_ioctl_args if_request;
-
- wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d)",
- if_name, vid);
- ifconfig_up(if_name);
-
- if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
- wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
- if_name);
- return -1;
- }
-
- if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
- "failed: %s", __func__, strerror(errno));
- return -1;
- }
-
- os_memset(&if_request, 0, sizeof(if_request));
-
- /* Determine if a suitable vlan device already exists. */
-
- os_snprintf(if_request.device1, sizeof(if_request.device1), "vlan%d",
- vid);
-
- if_request.cmd = _GET_VLAN_VID_CMD;
-
- if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0) {
-
- if (if_request.u.VID == vid) {
- if_request.cmd = _GET_VLAN_REALDEV_NAME_CMD;
-
- if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 &&
- os_strncmp(if_request.u.device2, if_name,
- sizeof(if_request.u.device2)) == 0) {
- close(fd);
- wpa_printf(MSG_DEBUG, "VLAN: vlan_add: "
- "if_name %s exists already",
- if_request.device1);
- return 1;
- }
- }
- }
-
- /* A suitable vlan device does not already exist, add one. */
-
- os_memset(&if_request, 0, sizeof(if_request));
- os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
- if_request.u.VID = vid;
- if_request.cmd = ADD_VLAN_CMD;
-
- if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: ADD_VLAN_CMD failed for %s: "
- "%s",
- __func__, if_request.device1, strerror(errno));
- close(fd);
- return -1;
- }
-
- close(fd);
- return 0;
-}
-
-
-static int vlan_set_name_type(unsigned int name_type)
-{
- int fd;
- struct vlan_ioctl_args if_request;
-
- wpa_printf(MSG_DEBUG, "VLAN: vlan_set_name_type(name_type=%u)",
- name_type);
- if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
- "failed: %s", __func__, strerror(errno));
- return -1;
- }
-
- os_memset(&if_request, 0, sizeof(if_request));
-
- if_request.u.name_type = name_type;
- if_request.cmd = SET_VLAN_NAME_TYPE_CMD;
- if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: SET_VLAN_NAME_TYPE_CMD "
- "name_type=%u failed: %s",
- __func__, name_type, strerror(errno));
- close(fd);
- return -1;
- }
-
- close(fd);
- return 0;
-}
-
-#endif /* CONFIG_VLAN_NETLINK */
-
-
-static void vlan_newlink_tagged(int vlan_naming, const char *tagged_interface,
- const char *br_name, int vid,
- struct hostapd_data *hapd)
-{
- char vlan_ifname[IFNAMSIZ];
- int clean;
-
- if (vlan_naming == DYNAMIC_VLAN_NAMING_WITH_DEVICE)
- os_snprintf(vlan_ifname, sizeof(vlan_ifname), "%s.%d",
- tagged_interface, vid);
- else
- os_snprintf(vlan_ifname, sizeof(vlan_ifname), "vlan%d", vid);
-
- clean = 0;
- ifconfig_up(tagged_interface);
- if (!vlan_add(tagged_interface, vid, vlan_ifname))
- clean |= DVLAN_CLEAN_VLAN;
-
- if (!br_addif(br_name, vlan_ifname))
- clean |= DVLAN_CLEAN_VLAN_PORT;
-
- dyn_iface_get(hapd, vlan_ifname, clean);
-
- ifconfig_up(vlan_ifname);
-}
-
-
-static void vlan_bridge_name(char *br_name, struct hostapd_data *hapd, int vid)
-{
- char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
-
- if (hapd->conf->vlan_bridge[0]) {
- os_snprintf(br_name, IFNAMSIZ, "%s%d",
- hapd->conf->vlan_bridge, vid);
- } else if (tagged_interface) {
- os_snprintf(br_name, IFNAMSIZ, "br%s.%d",
- tagged_interface, vid);
- } else {
- os_snprintf(br_name, IFNAMSIZ, "brvlan%d", vid);
- }
-}
-
-
-static void vlan_get_bridge(const char *br_name, struct hostapd_data *hapd,
- int vid)
-{
- char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
- int vlan_naming = hapd->conf->ssid.vlan_naming;
-
- dyn_iface_get(hapd, br_name, br_addbr(br_name) ? 0 : DVLAN_CLEAN_BR);
-
- ifconfig_up(br_name);
-
- if (tagged_interface)
- vlan_newlink_tagged(vlan_naming, tagged_interface, br_name,
- vid, hapd);
-}
-
-
-static void vlan_newlink(const char *ifname, struct hostapd_data *hapd)
-{
- char br_name[IFNAMSIZ];
- struct hostapd_vlan *vlan;
- int untagged, *tagged, i, notempty;
-
- wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
-
- for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
- if (vlan->configured ||
- os_strcmp(ifname, vlan->ifname) != 0)
- continue;
- break;
- }
- if (!vlan)
- return;
-
- vlan->configured = 1;
-
- notempty = vlan->vlan_desc.notempty;
- untagged = vlan->vlan_desc.untagged;
- tagged = vlan->vlan_desc.tagged;
-
- if (!notempty) {
- /* Non-VLAN STA */
- if (hapd->conf->bridge[0] &&
- !br_addif(hapd->conf->bridge, ifname))
- vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
- } else if (untagged > 0 && untagged <= MAX_VLAN_ID) {
- vlan_bridge_name(br_name, hapd, untagged);
-
- vlan_get_bridge(br_name, hapd, untagged);
-
- if (!br_addif(br_name, ifname))
- vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
- }
-
- for (i = 0; i < MAX_NUM_TAGGED_VLAN && tagged[i]; i++) {
- if (tagged[i] == untagged ||
- tagged[i] <= 0 || tagged[i] > MAX_VLAN_ID ||
- (i > 0 && tagged[i] == tagged[i - 1]))
- continue;
- vlan_bridge_name(br_name, hapd, tagged[i]);
- vlan_get_bridge(br_name, hapd, tagged[i]);
- vlan_newlink_tagged(DYNAMIC_VLAN_NAMING_WITH_DEVICE,
- ifname, br_name, tagged[i], hapd);
- }
-
- ifconfig_up(ifname);
-}
-
-
-static void vlan_dellink_tagged(int vlan_naming, const char *tagged_interface,
- const char *br_name, int vid,
- struct hostapd_data *hapd)
-{
- char vlan_ifname[IFNAMSIZ];
- int clean;
-
- if (vlan_naming == DYNAMIC_VLAN_NAMING_WITH_DEVICE)
- os_snprintf(vlan_ifname, sizeof(vlan_ifname), "%s.%d",
- tagged_interface, vid);
- else
- os_snprintf(vlan_ifname, sizeof(vlan_ifname), "vlan%d", vid);
-
- clean = dyn_iface_put(hapd, vlan_ifname);
-
- if (clean & DVLAN_CLEAN_VLAN_PORT)
- br_delif(br_name, vlan_ifname);
-
- if (clean & DVLAN_CLEAN_VLAN) {
- ifconfig_down(vlan_ifname);
- vlan_rem(vlan_ifname);
- }
-}
-
-
-static void vlan_put_bridge(const char *br_name, struct hostapd_data *hapd,
- int vid)
-{
- int clean;
- char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
- int vlan_naming = hapd->conf->ssid.vlan_naming;
-
- if (tagged_interface)
- vlan_dellink_tagged(vlan_naming, tagged_interface, br_name,
- vid, hapd);
-
- clean = dyn_iface_put(hapd, br_name);
- if ((clean & DVLAN_CLEAN_BR) && br_getnumports(br_name) == 0) {
- ifconfig_down(br_name);
- br_delbr(br_name);
- }
-}
-
-
-static void vlan_dellink(const char *ifname, struct hostapd_data *hapd)
-{
- struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan;
-
- wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname);
-
- first = prev = vlan;
-
- while (vlan) {
- if (os_strcmp(ifname, vlan->ifname) != 0) {
- prev = vlan;
- vlan = vlan->next;
- continue;
- }
- break;
- }
- if (!vlan)
- return;
-
- if (vlan->configured) {
- int notempty = vlan->vlan_desc.notempty;
- int untagged = vlan->vlan_desc.untagged;
- int *tagged = vlan->vlan_desc.tagged;
- char br_name[IFNAMSIZ];
- int i;
-
- for (i = 0; i < MAX_NUM_TAGGED_VLAN && tagged[i]; i++) {
- if (tagged[i] == untagged ||
- tagged[i] <= 0 || tagged[i] > MAX_VLAN_ID ||
- (i > 0 && tagged[i] == tagged[i - 1]))
- continue;
- vlan_bridge_name(br_name, hapd, tagged[i]);
- vlan_dellink_tagged(DYNAMIC_VLAN_NAMING_WITH_DEVICE,
- ifname, br_name, tagged[i], hapd);
- vlan_put_bridge(br_name, hapd, tagged[i]);
- }
-
- if (!notempty) {
- /* Non-VLAN STA */
- if (hapd->conf->bridge[0] &&
- (vlan->clean & DVLAN_CLEAN_WLAN_PORT))
- br_delif(hapd->conf->bridge, ifname);
- } else if (untagged > 0 && untagged <= MAX_VLAN_ID) {
- vlan_bridge_name(br_name, hapd, untagged);
-
- if (vlan->clean & DVLAN_CLEAN_WLAN_PORT)
- br_delif(br_name, vlan->ifname);
-
- vlan_put_bridge(br_name, hapd, untagged);
- }
- }
-
- /*
- * Ensure this VLAN interface is actually removed even if
- * NEWLINK message is only received later.
- */
- if (if_nametoindex(vlan->ifname) && vlan_if_remove(hapd, vlan))
- wpa_printf(MSG_ERROR,
- "VLAN: Could not remove VLAN iface: %s: %s",
- vlan->ifname, strerror(errno));
-
- if (vlan == first)
- hapd->conf->vlan = vlan->next;
- else
- prev->next = vlan->next;
-
- os_free(vlan);
-}
-
-
-static void
-vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del,
- struct hostapd_data *hapd)
-{
- struct ifinfomsg *ifi;
- int attrlen, nlmsg_len, rta_len;
- struct rtattr *attr;
- char ifname[IFNAMSIZ + 1];
-
- if (len < sizeof(*ifi))
- return;
-
- ifi = NLMSG_DATA(h);
-
- nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
-
- attrlen = h->nlmsg_len - nlmsg_len;
- if (attrlen < 0)
- return;
-
- attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
-
- os_memset(ifname, 0, sizeof(ifname));
- rta_len = RTA_ALIGN(sizeof(struct rtattr));
- while (RTA_OK(attr, attrlen)) {
- if (attr->rta_type == IFLA_IFNAME) {
- int n = attr->rta_len - rta_len;
- if (n < 0)
- break;
-
- if ((size_t) n >= sizeof(ifname))
- n = sizeof(ifname) - 1;
- os_memcpy(ifname, ((char *) attr) + rta_len, n);
-
- }
-
- attr = RTA_NEXT(attr, attrlen);
- }
-
- if (!ifname[0])
- return;
- if (del && if_nametoindex(ifname)) {
- /* interface still exists, race condition ->
- * iface has just been recreated */
- return;
- }
-
- wpa_printf(MSG_DEBUG,
- "VLAN: RTM_%sLINK: ifi_index=%d ifname=%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
- del ? "DEL" : "NEW",
- ifi->ifi_index, ifname, ifi->ifi_family, ifi->ifi_flags,
- (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
- (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
- (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
- (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
-
- if (del)
- vlan_dellink(ifname, hapd);
- else
- vlan_newlink(ifname, hapd);
-}
-
-
-static void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx)
-{
- char buf[8192];
- int left;
- struct sockaddr_nl from;
- socklen_t fromlen;
- struct nlmsghdr *h;
- struct hostapd_data *hapd = eloop_ctx;
-
- fromlen = sizeof(from);
- left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
- (struct sockaddr *) &from, &fromlen);
- if (left < 0) {
- if (errno != EINTR && errno != EAGAIN)
- wpa_printf(MSG_ERROR, "VLAN: %s: recvfrom failed: %s",
- __func__, strerror(errno));
- return;
- }
-
- h = (struct nlmsghdr *) buf;
- while (NLMSG_OK(h, left)) {
- int len, plen;
-
- len = h->nlmsg_len;
- plen = len - sizeof(*h);
- if (len > left || plen < 0) {
- wpa_printf(MSG_DEBUG, "VLAN: Malformed netlink "
- "message: len=%d left=%d plen=%d",
- len, left, plen);
- break;
- }
-
- switch (h->nlmsg_type) {
- case RTM_NEWLINK:
- vlan_read_ifnames(h, plen, 0, hapd);
- break;
- case RTM_DELLINK:
- vlan_read_ifnames(h, plen, 1, hapd);
- break;
- }
-
- h = NLMSG_NEXT(h, left);
- }
-
- if (left > 0) {
- wpa_printf(MSG_DEBUG, "VLAN: %s: %d extra bytes in the end of "
- "netlink message", __func__, left);
- }
-}
-
-
-static struct full_dynamic_vlan *
-full_dynamic_vlan_init(struct hostapd_data *hapd)
-{
- struct sockaddr_nl local;
- struct full_dynamic_vlan *priv;
-
- priv = os_zalloc(sizeof(*priv));
- if (priv == NULL)
- return NULL;
-
-#ifndef CONFIG_VLAN_NETLINK
- vlan_set_name_type(hapd->conf->ssid.vlan_naming ==
- DYNAMIC_VLAN_NAMING_WITH_DEVICE ?
- VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD :
- VLAN_NAME_TYPE_PLUS_VID_NO_PAD);
-#endif /* CONFIG_VLAN_NETLINK */
-
- priv->s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
- if (priv->s < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: socket(PF_NETLINK,SOCK_RAW,"
- "NETLINK_ROUTE) failed: %s",
- __func__, strerror(errno));
- os_free(priv);
- return NULL;
- }
-
- os_memset(&local, 0, sizeof(local));
- local.nl_family = AF_NETLINK;
- local.nl_groups = RTMGRP_LINK;
- if (bind(priv->s, (struct sockaddr *) &local, sizeof(local)) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: bind(netlink) failed: %s",
- __func__, strerror(errno));
- close(priv->s);
- os_free(priv);
- return NULL;
- }
-
- if (eloop_register_read_sock(priv->s, vlan_event_receive, hapd, NULL))
- {
- close(priv->s);
- os_free(priv);
- return NULL;
- }
-
- return priv;
-}
-
-
-static void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv)
-{
- if (priv == NULL)
- return;
- eloop_unregister_read_sock(priv->s);
- close(priv->s);
- os_free(priv);
-}
-#endif /* CONFIG_FULL_DYNAMIC_VLAN */
-
-
static int vlan_dynamic_add(struct hostapd_data *hapd,
struct hostapd_vlan *vlan)
{
diff --git a/src/ap/vlan_ioctl.c b/src/ap/vlan_ioctl.c
new file mode 100644
index 00000000..987b612e
--- /dev/null
+++ b/src/ap/vlan_ioctl.c
@@ -0,0 +1,155 @@
+/*
+ * hostapd / VLAN ioctl API
+ * Copyright 2003, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include <sys/ioctl.h>
+
+#include "utils/common.h"
+#include "common/linux_vlan.h"
+#include "vlan_util.h"
+
+
+int vlan_rem(const char *if_name)
+{
+ int fd;
+ struct vlan_ioctl_args if_request;
+
+ wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(%s)", if_name);
+ if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
+ wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
+ if_name);
+ return -1;
+ }
+
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+ "failed: %s", __func__, strerror(errno));
+ return -1;
+ }
+
+ os_memset(&if_request, 0, sizeof(if_request));
+
+ os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
+ if_request.cmd = DEL_VLAN_CMD;
+
+ if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: DEL_VLAN_CMD failed for %s: "
+ "%s", __func__, if_name, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+}
+
+
+/*
+ Add a vlan interface with VLAN ID 'vid' and tagged interface
+ 'if_name'.
+
+ returns -1 on error
+ returns 1 if the interface already exists
+ returns 0 otherwise
+*/
+int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
+{
+ int fd;
+ struct vlan_ioctl_args if_request;
+
+ wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d)",
+ if_name, vid);
+ ifconfig_up(if_name);
+
+ if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
+ wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
+ if_name);
+ return -1;
+ }
+
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+ "failed: %s", __func__, strerror(errno));
+ return -1;
+ }
+
+ os_memset(&if_request, 0, sizeof(if_request));
+
+ /* Determine if a suitable vlan device already exists. */
+
+ os_snprintf(if_request.device1, sizeof(if_request.device1), "vlan%d",
+ vid);
+
+ if_request.cmd = GET_VLAN_VID_CMD;
+
+ if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 &&
+ if_request.u.VID == vid) {
+ if_request.cmd = GET_VLAN_REALDEV_NAME_CMD;
+
+ if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 &&
+ os_strncmp(if_request.u.device2, if_name,
+ sizeof(if_request.u.device2)) == 0) {
+ close(fd);
+ wpa_printf(MSG_DEBUG,
+ "VLAN: vlan_add: if_name %s exists already",
+ if_request.device1);
+ return 1;
+ }
+ }
+
+ /* A suitable vlan device does not already exist, add one. */
+
+ os_memset(&if_request, 0, sizeof(if_request));
+ os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
+ if_request.u.VID = vid;
+ if_request.cmd = ADD_VLAN_CMD;
+
+ if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
+ wpa_printf(MSG_ERROR,
+ "VLAN: %s: ADD_VLAN_CMD failed for %s: %s",
+ __func__, if_request.device1, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+}
+
+
+int vlan_set_name_type(unsigned int name_type)
+{
+ int fd;
+ struct vlan_ioctl_args if_request;
+
+ wpa_printf(MSG_DEBUG, "VLAN: vlan_set_name_type(name_type=%u)",
+ name_type);
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ wpa_printf(MSG_ERROR,
+ "VLAN: %s: socket(AF_INET,SOCK_STREAM) failed: %s",
+ __func__, strerror(errno));
+ return -1;
+ }
+
+ os_memset(&if_request, 0, sizeof(if_request));
+
+ if_request.u.name_type = name_type;
+ if_request.cmd = SET_VLAN_NAME_TYPE_CMD;
+ if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
+ wpa_printf(MSG_ERROR,
+ "VLAN: %s: SET_VLAN_NAME_TYPE_CMD name_type=%u failed: %s",
+ __func__, name_type, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+}
diff --git a/src/ap/vlan_util.c b/src/ap/vlan_util.c
index 313d89fe..56d1d3d1 100644
--- a/src/ap/vlan_util.c
+++ b/src/ap/vlan_util.c
@@ -7,18 +7,10 @@
*/
#include "utils/includes.h"
-#include <sys/ioctl.h>
-#include <linux/sockios.h>
-#include <linux/if_vlan.h>
-#include <netlink/genl/genl.h>
-#include <netlink/genl/family.h>
-#include <netlink/genl/ctrl.h>
#include <netlink/route/link.h>
#include <netlink/route/link/vlan.h>
#include "utils/common.h"
-#include "utils/eloop.h"
-#include "hostapd.h"
#include "vlan_util.h"
/*
@@ -174,3 +166,9 @@ vlan_rem_error:
nl_socket_free(handle);
return ret;
}
+
+
+int vlan_set_name_type(unsigned int name_type)
+{
+ return 0;
+}
diff --git a/src/ap/vlan_util.h b/src/ap/vlan_util.h
index bef5a16f..24468597 100644
--- a/src/ap/vlan_util.h
+++ b/src/ap/vlan_util.h
@@ -1,5 +1,5 @@
/*
- * hostapd / VLAN netlink api
+ * hostapd / VLAN netlink/ioctl api
* Copyright (c) 2012, Michael Braun <michael-dev@fami-braun.de>
*
* This software may be distributed under the terms of the BSD license.
@@ -9,7 +9,23 @@
#ifndef VLAN_UTIL_H
#define VLAN_UTIL_H
+struct hostapd_data;
+struct hostapd_vlan;
+struct full_dynamic_vlan;
+
int vlan_add(const char *if_name, int vid, const char *vlan_if_name);
int vlan_rem(const char *if_name);
+int vlan_set_name_type(unsigned int name_type);
+
+int ifconfig_helper(const char *if_name, int up);
+int ifconfig_up(const char *if_name);
+int iface_exists(const char *ifname);
+int vlan_if_remove(struct hostapd_data *hapd, struct hostapd_vlan *vlan);
+
+struct full_dynamic_vlan *
+full_dynamic_vlan_init(struct hostapd_data *hapd);
+void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv);
+void vlan_newlink(const char *ifname, struct hostapd_data *hapd);
+void vlan_dellink(const char *ifname, struct hostapd_data *hapd);
#endif /* VLAN_UTIL_H */
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 4ded9bb6..35870864 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -3359,6 +3359,46 @@ void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
}
+int wpa_auth_pmksa_list(struct wpa_authenticator *wpa_auth, char *buf,
+ size_t len)
+{
+ if (!wpa_auth || !wpa_auth->pmksa)
+ return 0;
+ return pmksa_cache_auth_list(wpa_auth->pmksa, buf, len);
+}
+
+
+void wpa_auth_pmksa_flush(struct wpa_authenticator *wpa_auth)
+{
+ if (wpa_auth && wpa_auth->pmksa)
+ pmksa_cache_auth_flush(wpa_auth->pmksa);
+}
+
+
+struct rsn_pmksa_cache_entry *
+wpa_auth_pmksa_get(struct wpa_authenticator *wpa_auth, const u8 *sta_addr)
+{
+ if (!wpa_auth || !wpa_auth->pmksa)
+ return NULL;
+ return pmksa_cache_auth_get(wpa_auth->pmksa, sta_addr, NULL);
+}
+
+
+void wpa_auth_pmksa_set_to_sm(struct rsn_pmksa_cache_entry *pmksa,
+ struct wpa_state_machine *sm,
+ struct wpa_authenticator *wpa_auth,
+ u8 *pmkid, u8 *pmk)
+{
+ if (!sm)
+ return;
+
+ sm->pmksa = pmksa;
+ os_memcpy(pmk, pmksa->pmk, PMK_LEN);
+ os_memcpy(pmkid, pmksa->pmkid, PMKID_LEN);
+ os_memcpy(wpa_auth->dot11RSNAPMKIDUsed, pmksa->pmkid, PMKID_LEN);
+}
+
+
/*
* Remove and free the group from wpa_authenticator. This is triggered by a
* callback to make sure nobody is currently iterating the group list while it
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 2b601146..0de8d976 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -298,6 +298,15 @@ int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr,
const u8 *pmk, const u8 *pmkid);
void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
const u8 *sta_addr);
+int wpa_auth_pmksa_list(struct wpa_authenticator *wpa_auth, char *buf,
+ size_t len);
+void wpa_auth_pmksa_flush(struct wpa_authenticator *wpa_auth);
+struct rsn_pmksa_cache_entry *
+wpa_auth_pmksa_get(struct wpa_authenticator *wpa_auth, const u8 *sta_addr);
+void wpa_auth_pmksa_set_to_sm(struct rsn_pmksa_cache_entry *pmksa,
+ struct wpa_state_machine *sm,
+ struct wpa_authenticator *wpa_auth,
+ u8 *pmkid, u8 *pmk);
int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id);
void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, int ack);
diff --git a/src/common/ctrl_iface_common.c b/src/common/ctrl_iface_common.c
index acd24100..ebbe6ffd 100644
--- a/src/common/ctrl_iface_common.c
+++ b/src/common/ctrl_iface_common.c
@@ -17,15 +17,15 @@
static int sockaddr_compare(struct sockaddr_storage *a, socklen_t a_len,
struct sockaddr_storage *b, socklen_t b_len)
{
- struct sockaddr_in *in_a, *in_b;
- struct sockaddr_in6 *in6_a, *in6_b;
- struct sockaddr_un *u_a, *u_b;
-
if (a->ss_family != b->ss_family)
return 1;
switch (a->ss_family) {
+#ifdef CONFIG_CTRL_IFACE_UDP
case AF_INET:
+ {
+ struct sockaddr_in *in_a, *in_b;
+
in_a = (struct sockaddr_in *) a;
in_b = (struct sockaddr_in *) b;
@@ -34,7 +34,11 @@ static int sockaddr_compare(struct sockaddr_storage *a, socklen_t a_len,
if (in_a->sin_addr.s_addr != in_b->sin_addr.s_addr)
return 1;
break;
+ }
case AF_INET6:
+ {
+ struct sockaddr_in6 *in6_a, *in6_b;
+
in6_a = (struct sockaddr_in6 *) a;
in6_b = (struct sockaddr_in6 *) b;
@@ -44,7 +48,13 @@ static int sockaddr_compare(struct sockaddr_storage *a, socklen_t a_len,
sizeof(in6_a->sin6_addr)) != 0)
return 1;
break;
+ }
+#endif /* CONFIG_CTRL_IFACE_UDP */
+#ifdef CONFIG_CTRL_IFACE_UNIX
case AF_UNIX:
+ {
+ struct sockaddr_un *u_a, *u_b;
+
u_a = (struct sockaddr_un *) a;
u_b = (struct sockaddr_un *) b;
@@ -54,6 +64,8 @@ static int sockaddr_compare(struct sockaddr_storage *a, socklen_t a_len,
!= 0)
return 1;
break;
+ }
+#endif /* CONFIG_CTRL_IFACE_UNIX */
default:
return 1;
}
@@ -65,13 +77,14 @@ static int sockaddr_compare(struct sockaddr_storage *a, socklen_t a_len,
void sockaddr_print(int level, const char *msg, struct sockaddr_storage *sock,
socklen_t socklen)
{
- char host[NI_MAXHOST] = { 0 };
- char service[NI_MAXSERV] = { 0 };
- char addr_txt[200];
-
switch (sock->ss_family) {
+#ifdef CONFIG_CTRL_IFACE_UDP
case AF_INET:
case AF_INET6:
+ {
+ char host[NI_MAXHOST] = { 0 };
+ char service[NI_MAXSERV] = { 0 };
+
getnameinfo((struct sockaddr *) sock, socklen,
host, sizeof(host),
service, sizeof(service),
@@ -79,12 +92,20 @@ void sockaddr_print(int level, const char *msg, struct sockaddr_storage *sock,
wpa_printf(level, "%s %s:%s", msg, host, service);
break;
+ }
+#endif /* CONFIG_CTRL_IFACE_UDP */
+#ifdef CONFIG_CTRL_IFACE_UNIX
case AF_UNIX:
+ {
+ char addr_txt[200];
+
printf_encode(addr_txt, sizeof(addr_txt),
(u8 *) ((struct sockaddr_un *) sock)->sun_path,
socklen - offsetof(struct sockaddr_un, sun_path));
wpa_printf(level, "%s %s", msg, addr_txt);
break;
+ }
+#endif /* CONFIG_CTRL_IFACE_UNIX */
default:
wpa_printf(level, "%s", msg);
break;
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 73ffc999..e1a8ef78 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -527,10 +527,7 @@ struct ieee80211_mgmt {
* FH Params, DS Params, CF Params, IBSS Params, TIM */
u8 variable[];
} STRUCT_PACKED beacon;
- struct {
- /* only variable items: SSID, Supported rates */
- u8 variable[0];
- } STRUCT_PACKED probe_req;
+ /* probe_req: only variable items: SSID, Supported rates */
struct {
u8 timestamp[8];
le16 beacon_int;
diff --git a/src/common/linux_bridge.h b/src/common/linux_bridge.h
new file mode 100644
index 00000000..7b768464
--- /dev/null
+++ b/src/common/linux_bridge.h
@@ -0,0 +1,24 @@
+/*
+ * Linux bridge configuration kernel interface
+ * Copyright (c) 2016, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef LINUX_BRIDGE_H
+#define LINUX_BRIDGE_H
+
+/* This interface is defined in linux/if_bridge.h */
+
+#define BRCTL_GET_VERSION 0
+#define BRCTL_GET_BRIDGES 1
+#define BRCTL_ADD_BRIDGE 2
+#define BRCTL_DEL_BRIDGE 3
+#define BRCTL_ADD_IF 4
+#define BRCTL_DEL_IF 5
+#define BRCTL_GET_BRIDGE_INFO 6
+#define BRCTL_GET_PORT_LIST 7
+#define BRCTL_SET_BRIDGE_FORWARD_DELAY 8
+
+#endif /* LINUX_BRIDGE_H */
diff --git a/src/common/linux_vlan.h b/src/common/linux_vlan.h
new file mode 100644
index 00000000..8a1dd6e4
--- /dev/null
+++ b/src/common/linux_vlan.h
@@ -0,0 +1,52 @@
+/*
+ * Linux VLAN configuration kernel interface
+ * Copyright (c) 2016, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef LINUX_VLAN_H
+#define LINUX_VLAN_H
+
+/* This ioctl is defined in linux/sockios.h */
+
+#ifndef SIOCSIFVLAN
+#define SIOCSIFVLAN 0x8983
+#endif /* SIOCSIFVLAN */
+
+/* This interface is defined in linux/if_vlan.h */
+
+#define ADD_VLAN_CMD 0
+#define DEL_VLAN_CMD 1
+#define SET_VLAN_INGRESS_PRIORITY_CMD 2
+#define SET_VLAN_EGRESS_PRIORITY_CMD 3
+#define GET_VLAN_INGRESS_PRIORITY_CMD 4
+#define GET_VLAN_EGRESS_PRIORITY_CMD 5
+#define SET_VLAN_NAME_TYPE_CMD 6
+#define SET_VLAN_FLAG_CMD 7
+#define GET_VLAN_REALDEV_NAME_CMD 8
+#define GET_VLAN_VID_CMD 9
+
+#define VLAN_NAME_TYPE_PLUS_VID 0
+#define VLAN_NAME_TYPE_RAW_PLUS_VID 1
+#define VLAN_NAME_TYPE_PLUS_VID_NO_PAD 2
+#define VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD 3
+
+struct vlan_ioctl_args {
+ int cmd;
+ char device1[24];
+
+ union {
+ char device2[24];
+ int VID;
+ unsigned int skb_priority;
+ unsigned int name_type;
+ unsigned int bind_type;
+ unsigned int flag;
+ } u;
+
+ short vlan_qos;
+};
+
+#endif /* LINUX_VLAN_H */
diff --git a/src/common/sae.c b/src/common/sae.c
index 6c00a7e3..9f70f036 100644
--- a/src/common/sae.c
+++ b/src/common/sae.c
@@ -1,6 +1,6 @@
/*
* Simultaneous authentication of equals
- * Copyright (c) 2012-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2012-2016, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -275,8 +275,9 @@ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
/* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */
bits = crypto_ec_prime_len_bits(sae->tmp->ec);
- sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking",
- prime, sae->tmp->prime_len, pwd_value, bits);
+ if (sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking",
+ prime, sae->tmp->prime_len, pwd_value, bits) < 0)
+ return -1;
if (bits % 8)
buf_shift_right(pwd_value, sizeof(pwd_value), 8 - bits % 8);
wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value",
@@ -318,11 +319,10 @@ static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed,
wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN);
/* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */
- sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking",
- sae->tmp->dh->prime, sae->tmp->prime_len, pwd_value,
- bits);
- if (bits % 8)
- buf_shift_right(pwd_value, sizeof(pwd_value), 8 - bits % 8);
+ if (sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking",
+ sae->tmp->dh->prime, sae->tmp->prime_len, pwd_value,
+ bits) < 0)
+ return -1;
wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value", pwd_value,
sae->tmp->prime_len);
@@ -811,8 +811,9 @@ static int sae_derive_keys(struct sae_data *sae, const u8 *k)
crypto_bignum_mod(tmp, sae->tmp->order, tmp);
crypto_bignum_to_bin(tmp, val, sizeof(val), sae->tmp->prime_len);
wpa_hexdump(MSG_DEBUG, "SAE: PMKID", val, SAE_PMKID_LEN);
- sha256_prf(keyseed, sizeof(keyseed), "SAE KCK and PMK",
- val, sae->tmp->prime_len, keys, sizeof(keys));
+ if (sha256_prf(keyseed, sizeof(keyseed), "SAE KCK and PMK",
+ val, sae->tmp->prime_len, keys, sizeof(keys)) < 0)
+ goto fail;
os_memset(keyseed, 0, sizeof(keyseed));
os_memcpy(sae->tmp->kck, keys, SAE_KCK_LEN);
os_memcpy(sae->pmk, keys + SAE_KCK_LEN, SAE_PMK_LEN);
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index ee20b37f..c5a28ced 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -998,13 +998,20 @@ int omac1_aes_256(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
struct crypto_bignum * crypto_bignum_init(void)
{
+ if (TEST_FAIL())
+ return NULL;
return (struct crypto_bignum *) BN_new();
}
struct crypto_bignum * crypto_bignum_init_set(const u8 *buf, size_t len)
{
- BIGNUM *bn = BN_bin2bn(buf, len, NULL);
+ BIGNUM *bn;
+
+ if (TEST_FAIL())
+ return NULL;
+
+ bn = BN_bin2bn(buf, len, NULL);
return (struct crypto_bignum *) bn;
}
@@ -1023,6 +1030,9 @@ int crypto_bignum_to_bin(const struct crypto_bignum *a,
{
int num_bytes, offset;
+ if (TEST_FAIL())
+ return -1;
+
if (padlen > buflen)
return -1;
@@ -1076,6 +1086,9 @@ int crypto_bignum_exptmod(const struct crypto_bignum *a,
int res;
BN_CTX *bnctx;
+ if (TEST_FAIL())
+ return -1;
+
bnctx = BN_CTX_new();
if (bnctx == NULL)
return -1;
@@ -1094,6 +1107,8 @@ int crypto_bignum_inverse(const struct crypto_bignum *a,
BIGNUM *res;
BN_CTX *bnctx;
+ if (TEST_FAIL())
+ return -1;
bnctx = BN_CTX_new();
if (bnctx == NULL)
return -1;
@@ -1109,6 +1124,8 @@ int crypto_bignum_sub(const struct crypto_bignum *a,
const struct crypto_bignum *b,
struct crypto_bignum *c)
{
+ if (TEST_FAIL())
+ return -1;
return BN_sub((BIGNUM *) c, (const BIGNUM *) a, (const BIGNUM *) b) ?
0 : -1;
}
@@ -1122,6 +1139,9 @@ int crypto_bignum_div(const struct crypto_bignum *a,
BN_CTX *bnctx;
+ if (TEST_FAIL())
+ return -1;
+
bnctx = BN_CTX_new();
if (bnctx == NULL)
return -1;
@@ -1142,6 +1162,9 @@ int crypto_bignum_mulmod(const struct crypto_bignum *a,
BN_CTX *bnctx;
+ if (TEST_FAIL())
+ return -1;
+
bnctx = BN_CTX_new();
if (bnctx == NULL)
return -1;
@@ -1185,6 +1208,9 @@ int crypto_bignum_legendre(const struct crypto_bignum *a,
BIGNUM *exp = NULL, *tmp = NULL;
int res = -2;
+ if (TEST_FAIL())
+ return -2;
+
bnctx = BN_CTX_new();
if (bnctx == NULL)
return -2;
@@ -1309,6 +1335,8 @@ void crypto_ec_deinit(struct crypto_ec *e)
struct crypto_ec_point * crypto_ec_point_init(struct crypto_ec *e)
{
+ if (TEST_FAIL())
+ return NULL;
if (e == NULL)
return NULL;
return (struct crypto_ec_point *) EC_POINT_new(e->group);
@@ -1355,6 +1383,9 @@ int crypto_ec_point_to_bin(struct crypto_ec *e,
int ret = -1;
int len = BN_num_bytes(e->prime);
+ if (TEST_FAIL())
+ return -1;
+
x_bn = BN_new();
y_bn = BN_new();
@@ -1385,6 +1416,9 @@ struct crypto_ec_point * crypto_ec_point_from_bin(struct crypto_ec *e,
EC_POINT *elem;
int len = BN_num_bytes(e->prime);
+ if (TEST_FAIL())
+ return NULL;
+
x = BN_bin2bn(val, len, NULL);
y = BN_bin2bn(val + len, len, NULL);
elem = EC_POINT_new(e->group);
@@ -1412,6 +1446,8 @@ int crypto_ec_point_add(struct crypto_ec *e, const struct crypto_ec_point *a,
const struct crypto_ec_point *b,
struct crypto_ec_point *c)
{
+ if (TEST_FAIL())
+ return -1;
return EC_POINT_add(e->group, (EC_POINT *) c, (const EC_POINT *) a,
(const EC_POINT *) b, e->bnctx) ? 0 : -1;
}
@@ -1421,6 +1457,8 @@ int crypto_ec_point_mul(struct crypto_ec *e, const struct crypto_ec_point *p,
const struct crypto_bignum *b,
struct crypto_ec_point *res)
{
+ if (TEST_FAIL())
+ return -1;
return EC_POINT_mul(e->group, (EC_POINT *) res, NULL,
(const EC_POINT *) p, (const BIGNUM *) b, e->bnctx)
? 0 : -1;
@@ -1429,6 +1467,8 @@ int crypto_ec_point_mul(struct crypto_ec *e, const struct crypto_ec_point *p,
int crypto_ec_point_invert(struct crypto_ec *e, struct crypto_ec_point *p)
{
+ if (TEST_FAIL())
+ return -1;
return EC_POINT_invert(e->group, (EC_POINT *) p, e->bnctx) ? 0 : -1;
}
@@ -1437,6 +1477,8 @@ int crypto_ec_point_solve_y_coord(struct crypto_ec *e,
struct crypto_ec_point *p,
const struct crypto_bignum *x, int y_bit)
{
+ if (TEST_FAIL())
+ return -1;
if (!EC_POINT_set_compressed_coordinates_GFp(e->group, (EC_POINT *) p,
(const BIGNUM *) x, y_bit,
e->bnctx) ||
@@ -1452,6 +1494,9 @@ crypto_ec_point_compute_y_sqr(struct crypto_ec *e,
{
BIGNUM *tmp, *tmp2, *y_sqr = NULL;
+ if (TEST_FAIL())
+ return NULL;
+
tmp = BN_new();
tmp2 = BN_new();
diff --git a/src/crypto/sha256-prf.c b/src/crypto/sha256-prf.c
index 79791c06..722cad6b 100644
--- a/src/crypto/sha256-prf.c
+++ b/src/crypto/sha256-prf.c
@@ -1,6 +1,6 @@
/*
* SHA256-based PRF (IEEE 802.11r)
- * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2016, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -22,14 +22,16 @@
* @data_len: Length of the data
* @buf: Buffer for the generated pseudo-random key
* @buf_len: Number of bytes of key to generate
+ * Returns: 0 on success, -1 on failure
*
* This function is used to derive new, cryptographically separate keys from a
* given key.
*/
-void sha256_prf(const u8 *key, size_t key_len, const char *label,
+int sha256_prf(const u8 *key, size_t key_len, const char *label,
const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
{
- sha256_prf_bits(key, key_len, label, data, data_len, buf, buf_len * 8);
+ return sha256_prf_bits(key, key_len, label, data, data_len, buf,
+ buf_len * 8);
}
@@ -42,15 +44,16 @@ void sha256_prf(const u8 *key, size_t key_len, const char *label,
* @data_len: Length of the data
* @buf: Buffer for the generated pseudo-random key
* @buf_len: Number of bits of key to generate
+ * Returns: 0 on success, -1 on failure
*
* This function is used to derive new, cryptographically separate keys from a
* given key. If the requested buf_len is not divisible by eight, the least
* significant 1-7 bits of the last octet in the output are not part of the
* requested output.
*/
-void sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
- const u8 *data, size_t data_len, u8 *buf,
- size_t buf_len_bits)
+int sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf,
+ size_t buf_len_bits)
{
u16 counter = 1;
size_t pos, plen;
@@ -75,11 +78,14 @@ void sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
plen = buf_len - pos;
WPA_PUT_LE16(counter_le, counter);
if (plen >= SHA256_MAC_LEN) {
- hmac_sha256_vector(key, key_len, 4, addr, len,
- &buf[pos]);
+ if (hmac_sha256_vector(key, key_len, 4, addr, len,
+ &buf[pos]) < 0)
+ return -1;
pos += SHA256_MAC_LEN;
} else {
- hmac_sha256_vector(key, key_len, 4, addr, len, hash);
+ if (hmac_sha256_vector(key, key_len, 4, addr, len,
+ hash) < 0)
+ return -1;
os_memcpy(&buf[pos], hash, plen);
pos += plen;
break;
@@ -97,4 +103,6 @@ void sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
}
os_memset(hash, 0, sizeof(hash));
+
+ return 0;
}
diff --git a/src/crypto/sha256.h b/src/crypto/sha256.h
index b15f5115..5219022e 100644
--- a/src/crypto/sha256.h
+++ b/src/crypto/sha256.h
@@ -1,6 +1,6 @@
/*
* SHA256 hash implementation and interface functions
- * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2016, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -15,11 +15,11 @@ int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac);
int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
size_t data_len, u8 *mac);
-void sha256_prf(const u8 *key, size_t key_len, const char *label,
- const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
-void sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
- const u8 *data, size_t data_len, u8 *buf,
- size_t buf_len_bits);
+int sha256_prf(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
+int sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf,
+ size_t buf_len_bits);
void tls_prf_sha256(const u8 *secret, size_t secret_len,
const char *label, const u8 *seed, size_t seed_len,
u8 *out, size_t outlen);
diff --git a/src/crypto/tls_openssl_ocsp.c b/src/crypto/tls_openssl_ocsp.c
index 4e1c6b94..8b37b34e 100644
--- a/src/crypto/tls_openssl_ocsp.c
+++ b/src/crypto/tls_openssl_ocsp.c
@@ -433,7 +433,8 @@ static int issuer_match(X509 *cert, X509 *issuer, CertID *certid)
}
ikey = X509_get0_pubkey_bitstr(issuer);
- if (!EVP_Digest(ikey->data, ikey->length, md, &len, dgst, NULL) ||
+ if (!ikey ||
+ !EVP_Digest(ikey->data, ikey->length, md, &len, dgst, NULL) ||
!ASN1_OCTET_STRING_set(hash, md, len)) {
ASN1_OCTET_STRING_free(hash);
return -1;
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 642276ce..b7e0d163 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -1958,6 +1958,14 @@ struct wpa_driver_ops {
void (*poll)(void *priv);
/**
+ * get_ifindex - Get interface index
+ * @priv: private driver interface data
+ *
+ * Returns: Interface index
+ */
+ unsigned int (*get_ifindex)(void *priv);
+
+ /**
* get_ifname - Get interface name
* @priv: private driver interface data
*
@@ -2091,6 +2099,7 @@ struct wpa_driver_ops {
/**
* global_init - Global driver initialization
+ * @ctx: wpa_global pointer
* Returns: Pointer to private data (global), %NULL on failure
*
* This optional function is called to initialize the driver wrapper
@@ -2100,7 +2109,7 @@ struct wpa_driver_ops {
* use init2() function instead of init() to get the pointer to global
* data available to per-interface initializer.
*/
- void * (*global_init)(void);
+ void * (*global_init)(void *ctx);
/**
* global_deinit - Global driver deinitialization
@@ -4269,6 +4278,7 @@ union wpa_event_data {
* struct interface_status - Data for EVENT_INTERFACE_STATUS
*/
struct interface_status {
+ unsigned int ifindex;
char ifname[100];
enum {
EVENT_INTERFACE_ADDED, EVENT_INTERFACE_REMOVED
@@ -4745,6 +4755,18 @@ union wpa_event_data {
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
union wpa_event_data *data);
+/**
+ * wpa_supplicant_event_global - Report a driver event for wpa_supplicant
+ * @ctx: Context pointer (wpa_s); this is the ctx variable registered
+ * with struct wpa_driver_ops::init()
+ * @event: event type (defined above)
+ * @data: possible extra data for the event
+ *
+ * Same as wpa_supplicant_event(), but we search for the interface in
+ * wpa_global.
+ */
+void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event,
+ union wpa_event_data *data);
/*
* The following inline functions are provided for convenience to simplify
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index a5a379eb..ba3cad0b 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -855,16 +855,15 @@ static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
(int) len);
if (stype == WLAN_FC_STYPE_PROBE_REQ) {
- if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
+ if (len < IEEE80211_HDRLEN)
return;
os_memset(&event, 0, sizeof(event));
event.rx_probe_req.sa = mgmt->sa;
event.rx_probe_req.da = mgmt->da;
event.rx_probe_req.bssid = mgmt->bssid;
- event.rx_probe_req.ie = mgmt->u.probe_req.variable;
- event.rx_probe_req.ie_len =
- len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
+ event.rx_probe_req.ie = buf + IEEE80211_HDRLEN;
+ event.rx_probe_req.ie_len = len - IEEE80211_HDRLEN;
wpa_supplicant_event(drv->hapd, EVENT_RX_PROBE_REQ, &event);
return;
}
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index 99f35040..fd73f2e5 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -48,6 +48,7 @@
#include "l2_packet/l2_packet.h"
struct bsd_driver_global {
+ void *ctx;
int sock; /* socket for 802.11 ioctls */
int route; /* routing socket for events */
char *event_buf;
@@ -64,6 +65,7 @@ struct bsd_driver_data {
char ifname[IFNAMSIZ+1]; /* interface name */
int flags;
unsigned int ifindex; /* interface index */
+ int if_removed; /* has the interface been removed? */
void *ctx;
struct wpa_driver_capa capa; /* driver capability */
int is_ap; /* Access point mode */
@@ -88,13 +90,28 @@ bsd_get_drvindex(void *priv, unsigned int ifindex)
return NULL;
}
+#ifndef HOSTAPD
+static struct bsd_driver_data *
+bsd_get_drvname(void *priv, const char *ifname)
+{
+ struct bsd_driver_global *global = priv;
+ struct bsd_driver_data *drv;
+
+ dl_list_for_each(drv, &global->ifaces, struct bsd_driver_data, list) {
+ if (os_strcmp(drv->ifname, ifname) == 0)
+ return drv;
+ }
+ return NULL;
+}
+#endif /* HOSTAPD */
+
static int
bsd_set80211(void *priv, int op, int val, const void *arg, int arg_len)
{
struct bsd_driver_data *drv = priv;
struct ieee80211req ireq;
- if (drv->ifindex == 0)
+ if (drv->ifindex == 0 || drv->if_removed)
return -1;
os_memset(&ireq, 0, sizeof(ireq));
@@ -1222,24 +1239,45 @@ wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
switch (rtm->rtm_type) {
case RTM_IFANNOUNCE:
ifan = (struct if_announcemsghdr *) rtm;
- drv = bsd_get_drvindex(global, ifan->ifan_index);
- if (drv == NULL)
- return;
- os_strlcpy(event.interface_status.ifname, drv->ifname,
- sizeof(event.interface_status.ifname));
switch (ifan->ifan_what) {
case IFAN_DEPARTURE:
+ drv = bsd_get_drvindex(global, ifan->ifan_index);
+ if (drv)
+ drv->if_removed = 1;
event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
- drv->ifindex = 0;
+ break;
+ case IFAN_ARRIVAL:
+ drv = bsd_get_drvname(global, ifan->ifan_name);
+ if (drv) {
+ drv->ifindex = ifan->ifan_index;
+ drv->if_removed = 0;
+ }
+ event.interface_status.ievent = EVENT_INTERFACE_ADDED;
break;
default:
+ wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: unknown action");
return;
}
wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s",
- event.interface_status.ifname,
+ ifan->ifan_name,
ifan->ifan_what == IFAN_DEPARTURE ?
"removed" : "added");
- wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
+ os_strlcpy(event.interface_status.ifname, ifan->ifan_name,
+ sizeof(event.interface_status.ifname));
+ if (drv) {
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS,
+ &event);
+ /*
+ * Set ifindex to zero after sending the event as the
+ * event might query the driver to ensure a match.
+ */
+ if (ifan->ifan_what == IFAN_DEPARTURE)
+ drv->ifindex = 0;
+ } else {
+ wpa_supplicant_event_global(global->ctx,
+ EVENT_INTERFACE_STATUS,
+ &event);
+ }
break;
case RTM_IEEE80211:
ifan = (struct if_announcemsghdr *) rtm;
@@ -1542,11 +1580,7 @@ wpa_driver_bsd_init(void *ctx, const char *ifname, void *priv)
drv->ctx = ctx;
drv->global = priv;
-
os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
- /* Down interface during setup. */
- if (bsd_ctrl_iface(drv, 0) < 0)
- goto fail;
if (!GETPARAM(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming)) {
wpa_printf(MSG_DEBUG, "%s: failed to get roaming state: %s",
@@ -1567,6 +1601,10 @@ wpa_driver_bsd_init(void *ctx, const char *ifname, void *priv)
if (wpa_driver_bsd_capa(drv))
goto fail;
+ /* Down interface during setup. */
+ if (bsd_ctrl_iface(drv, 0) < 0)
+ goto fail;
+
drv->opmode = get80211opmode(drv);
dl_list_add(&drv->global->ifaces, &drv->list);
@@ -1582,7 +1620,7 @@ wpa_driver_bsd_deinit(void *priv)
{
struct bsd_driver_data *drv = priv;
- if (drv->ifindex != 0) {
+ if (drv->ifindex != 0 && !drv->if_removed) {
wpa_driver_bsd_set_wpa(drv, 0);
/* NB: mark interface down */
@@ -1615,7 +1653,7 @@ wpa_driver_bsd_get_capa(void *priv, struct wpa_driver_capa *capa)
#endif /* HOSTAPD */
static void *
-bsd_global_init(void)
+bsd_global_init(void *ctx)
{
struct bsd_driver_global *global;
@@ -1623,6 +1661,7 @@ bsd_global_init(void)
if (global == NULL)
return NULL;
+ global->ctx = ctx;
dl_list_init(&global->ifaces);
global->sock = socket(PF_INET, SOCK_DGRAM, 0);
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 5fb6652a..798e6947 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -763,6 +763,15 @@ static void nl80211_put_wiphy_data_ap(struct i802_bss *bss)
}
+static unsigned int nl80211_get_ifindex(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
+ return drv->ifindex;
+}
+
+
static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid)
{
struct i802_bss *bss = priv;
@@ -786,11 +795,12 @@ static int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid)
static void wpa_driver_nl80211_event_newlink(
- struct wpa_driver_nl80211_data *drv, const char *ifname)
+ struct nl80211_global *global, struct wpa_driver_nl80211_data *drv,
+ int ifindex, const char *ifname)
{
union wpa_event_data event;
- if (os_strcmp(drv->first_bss->ifname, ifname) == 0) {
+ if (drv && os_strcmp(drv->first_bss->ifname, 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);
@@ -804,19 +814,25 @@ static void wpa_driver_nl80211_event_newlink(
}
os_memset(&event, 0, sizeof(event));
+ event.interface_status.ifindex = ifindex;
os_strlcpy(event.interface_status.ifname, ifname,
sizeof(event.interface_status.ifname));
event.interface_status.ievent = EVENT_INTERFACE_ADDED;
- wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
+ if (drv)
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
+ else
+ wpa_supplicant_event_global(global->ctx, EVENT_INTERFACE_STATUS,
+ &event);
}
static void wpa_driver_nl80211_event_dellink(
- struct wpa_driver_nl80211_data *drv, const char *ifname)
+ struct nl80211_global *global, struct wpa_driver_nl80211_data *drv,
+ int ifindex, const char *ifname)
{
union wpa_event_data event;
- if (os_strcmp(drv->first_bss->ifname, ifname) == 0) {
+ if (drv && os_strcmp(drv->first_bss->ifname, ifname) == 0) {
if (drv->if_removed) {
wpa_printf(MSG_DEBUG, "nl80211: if_removed already set - ignore RTM_DELLINK event for %s",
ifname);
@@ -831,10 +847,15 @@ static void wpa_driver_nl80211_event_dellink(
}
os_memset(&event, 0, sizeof(event));
+ event.interface_status.ifindex = ifindex;
os_strlcpy(event.interface_status.ifname, ifname,
sizeof(event.interface_status.ifname));
event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
- wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
+ if (drv)
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
+ else
+ wpa_supplicant_event_global(global->ctx, EVENT_INTERFACE_STATUS,
+ &event);
}
@@ -908,13 +929,6 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
char ifname[IFNAMSIZ + 1];
char extra[100], *pos, *end;
- drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
- if (!drv) {
- wpa_printf(MSG_DEBUG, "nl80211: Ignore RTM_NEWLINK event for foreign ifindex %d",
- ifi->ifi_index);
- return;
- }
-
extra[0] = '\0';
pos = extra;
end = pos + sizeof(extra);
@@ -958,6 +972,10 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
(ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
(ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
+ drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
+ if (!drv)
+ goto event_newlink;
+
if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) {
namebuf[0] = '\0';
if (if_indextoname(ifi->ifi_index, namebuf) &&
@@ -1052,10 +1070,12 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
-1, IF_OPER_UP);
}
+event_newlink:
if (ifname[0])
- wpa_driver_nl80211_event_newlink(drv, ifname);
+ wpa_driver_nl80211_event_newlink(global, drv, ifi->ifi_index,
+ ifname);
- if (ifi->ifi_family == AF_BRIDGE && brid) {
+ if (ifi->ifi_family == AF_BRIDGE && brid && drv) {
struct i802_bss *bss;
/* device has been added to bridge */
@@ -1091,13 +1111,6 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
char ifname[IFNAMSIZ + 1];
char extra[100], *pos, *end;
- drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
- if (!drv) {
- wpa_printf(MSG_DEBUG, "nl80211: Ignore RTM_DELLINK event for foreign ifindex %d",
- ifi->ifi_index);
- return;
- }
-
extra[0] = '\0';
pos = extra;
end = pos + sizeof(extra);
@@ -1138,10 +1151,9 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
(ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
(ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
- if (ifname[0] && (ifi->ifi_family != AF_BRIDGE || !brid))
- wpa_driver_nl80211_event_dellink(drv, ifname);
+ drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
- if (ifi->ifi_family == AF_BRIDGE && brid) {
+ if (ifi->ifi_family == AF_BRIDGE && brid && drv) {
/* device has been removed from bridge */
char namebuf[IFNAMSIZ];
@@ -1156,6 +1168,10 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
}
del_ifidx(drv, brid, ifi->ifi_index);
}
+
+ if (ifi->ifi_family != AF_BRIDGE || !brid)
+ wpa_driver_nl80211_event_dellink(global, drv, ifi->ifi_index,
+ ifname);
}
@@ -3526,24 +3542,26 @@ static int wpa_driver_nl80211_set_ap(void *priv,
nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, suite))
goto fail;
- switch (params->smps_mode) {
- case HT_CAP_INFO_SMPS_DYNAMIC:
- wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - dynamic");
- smps_mode = NL80211_SMPS_DYNAMIC;
- break;
- case HT_CAP_INFO_SMPS_STATIC:
- wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - static");
- smps_mode = NL80211_SMPS_STATIC;
- break;
- default:
- /* invalid - fallback to smps off */
- case HT_CAP_INFO_SMPS_DISABLED:
- wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - off");
- smps_mode = NL80211_SMPS_OFF;
- break;
+ if (params->ht_opmode != -1) {
+ switch (params->smps_mode) {
+ case HT_CAP_INFO_SMPS_DYNAMIC:
+ wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - dynamic");
+ smps_mode = NL80211_SMPS_DYNAMIC;
+ break;
+ case HT_CAP_INFO_SMPS_STATIC:
+ wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - static");
+ smps_mode = NL80211_SMPS_STATIC;
+ break;
+ default:
+ /* invalid - fallback to smps off */
+ case HT_CAP_INFO_SMPS_DISABLED:
+ wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - off");
+ smps_mode = NL80211_SMPS_OFF;
+ break;
+ }
+ if (nla_put_u32(msg, NL80211_ATTR_SMPS_MODE, smps_mode))
+ goto fail;
}
- if (nla_put_u32(msg, NL80211_ATTR_SMPS_MODE, smps_mode))
- goto fail;
if (params->beacon_ies) {
wpa_hexdump_buf(MSG_DEBUG, "nl80211: beacon_ies",
@@ -4823,6 +4841,16 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
return -1;
}
+ drv->connect_reassoc = 0;
+ if (params->prev_bssid) {
+ wpa_printf(MSG_DEBUG, " * prev_bssid=" MACSTR,
+ MAC2STR(params->prev_bssid));
+ if (nla_put(msg, NL80211_ATTR_PREV_BSSID, ETH_ALEN,
+ params->prev_bssid))
+ return -1;
+ drv->connect_reassoc = 1;
+ }
+
return 0;
}
@@ -4975,14 +5003,6 @@ static int wpa_driver_nl80211_associate(
if (ret)
goto fail;
- if (params->prev_bssid) {
- wpa_printf(MSG_DEBUG, " * prev_bssid=" MACSTR,
- MAC2STR(params->prev_bssid));
- if (nla_put(msg, NL80211_ATTR_PREV_BSSID, ETH_ALEN,
- params->prev_bssid))
- goto fail;
- }
-
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
msg = NULL;
if (ret) {
@@ -5710,7 +5730,7 @@ static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
if (!old_reason)
drv->if_indices_reason = drv->default_if_indices_reason;
else
- drv->if_indices = old_reason;
+ drv->if_indices_reason = old_reason;
}
if (!drv->if_indices || !drv->if_indices_reason) {
wpa_printf(MSG_ERROR, "Failed to reallocate memory for "
@@ -6856,7 +6876,7 @@ static int nl80211_set_param(void *priv, const char *param)
}
-static void * nl80211_global_init(void)
+static void * nl80211_global_init(void *ctx)
{
struct nl80211_global *global;
struct netlink_config *cfg;
@@ -6864,6 +6884,7 @@ static void * nl80211_global_init(void)
global = os_zalloc(sizeof(*global));
if (global == NULL)
return NULL;
+ global->ctx = ctx;
global->ioctl_sock = -1;
dl_list_init(&global->interfaces);
global->if_add_ifindex = -1;
@@ -9141,6 +9162,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.br_set_net_param = wpa_driver_br_set_net_param,
.add_tx_ts = nl80211_add_ts,
.del_tx_ts = nl80211_del_ts,
+ .get_ifindex = nl80211_get_ifindex,
#ifdef CONFIG_DRIVER_NL80211_QCA
.do_acs = wpa_driver_do_acs,
.set_band = nl80211_set_band,
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index 430369f3..b0d2b6d7 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -25,6 +25,7 @@
#endif /* CONFIG_LIBNL20 */
struct nl80211_global {
+ void *ctx;
struct dl_list interfaces;
int if_add_ifindex;
u64 if_add_wdevid;
@@ -150,6 +151,7 @@ struct wpa_driver_nl80211_data {
unsigned int get_pref_freq_list:1;
unsigned int set_prob_oper_freq:1;
unsigned int scan_vendor_cmd_avail:1;
+ unsigned int connect_reassoc:1;
u64 vendor_scan_cookie;
u64 remain_on_chan_cookie;
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index dae203a1..bd16edbd 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -285,6 +285,8 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
return;
}
+ drv->connect_reassoc = 0;
+
status_code = status ? nla_get_u16(status) : WLAN_STATUS_SUCCESS;
if (cmd == NL80211_CMD_CONNECT) {
@@ -670,6 +672,24 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
return;
}
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
+ drv->connect_reassoc && drv->associated &&
+ os_memcmp(bssid, drv->prev_bssid, ETH_ALEN) == 0 &&
+ os_memcmp(bssid, drv->auth_attempt_bssid, ETH_ALEN) != 0) {
+ /*
+ * Avoid issues with some roaming cases where
+ * disconnection event for the old AP may show up after
+ * we have started connection with the new AP.
+ */
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignore deauth/disassoc event from old AP "
+ MACSTR
+ " when already connecting with " MACSTR,
+ MAC2STR(bssid),
+ MAC2STR(drv->auth_attempt_bssid));
+ return;
+ }
+
if (drv->associated != 0 &&
os_memcmp(bssid, drv->bssid, ETH_ALEN) != 0 &&
os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0) {
diff --git a/src/drivers/driver_privsep.c b/src/drivers/driver_privsep.c
index 762c12ff..43d41937 100644
--- a/src/drivers/driver_privsep.c
+++ b/src/drivers/driver_privsep.c
@@ -161,7 +161,7 @@ wpa_driver_privsep_get_scan_results2(void *priv)
return NULL;
}
- while (results->num < (size_t) num && end - pos > sizeof(int)) {
+ while (results->num < (size_t) num && end - pos > (int) sizeof(int)) {
int len;
os_memcpy(&len, pos, sizeof(int));
pos += sizeof(int);
diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak
index c4f5f974..c1bfff1f 100644
--- a/src/drivers/drivers.mak
+++ b/src/drivers/drivers.mak
@@ -63,7 +63,9 @@ else
endif
ifdef CONFIG_LIBNL20
- DRV_LIBS += -lnl-genl
+ ifndef CONFIG_LIBNL_TINY
+ DRV_LIBS += -lnl-genl
+ endif
DRV_CFLAGS += -DCONFIG_LIBNL20
endif
endif
diff --git a/src/drivers/drivers.mk b/src/drivers/drivers.mk
index 0a05a244..0444e523 100644
--- a/src/drivers/drivers.mk
+++ b/src/drivers/drivers.mk
@@ -51,7 +51,9 @@ else
endif
ifdef CONFIG_LIBNL20
- DRV_LIBS += -lnl-genl
+ ifndef CONFIG_LIBNL_TINY
+ DRV_LIBS += -lnl-genl
+ endif
DRV_CFLAGS += -DCONFIG_LIBNL20
endif
endif
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index fc545b41..0feafd31 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -1716,6 +1716,12 @@ struct p2p_group_config {
int freq;
/**
+ * ip_addr_alloc - Whether IP address allocation within 4-way handshake
+ * is supported
+ */
+ int ip_addr_alloc;
+
+ /**
* cb_ctx - Context to use with callback functions
*/
void *cb_ctx;
diff --git a/src/p2p/p2p_group.c b/src/p2p/p2p_group.c
index 2cf24507..eac73ef0 100644
--- a/src/p2p/p2p_group.c
+++ b/src/p2p/p2p_group.c
@@ -155,7 +155,8 @@ static void p2p_group_add_common_ies(struct p2p_group *group,
group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
if (group->num_members >= group->cfg->max_clients)
group_capab |= P2P_GROUP_CAPAB_GROUP_LIMIT;
- group_capab |= P2P_GROUP_CAPAB_IP_ADDR_ALLOCATION;
+ if (group->cfg->ip_addr_alloc)
+ group_capab |= P2P_GROUP_CAPAB_IP_ADDR_ALLOCATION;
p2p_buf_add_capability(ie, dev_capab, group_capab);
}
diff --git a/src/utils/common.h b/src/utils/common.h
index 0b9cc3d8..6f0de699 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -313,6 +313,9 @@ static inline void WPA_PUT_LE64(u8 *a, u64 val)
#ifndef ETH_P_ALL
#define ETH_P_ALL 0x0003
#endif
+#ifndef ETH_P_IP
+#define ETH_P_IP 0x0800
+#endif
#ifndef ETH_P_80211_ENCAP
#define ETH_P_80211_ENCAP 0x890d /* TDLS comes under this category */
#endif
diff --git a/src/utils/xml_libxml2.c b/src/utils/xml_libxml2.c
index c9283946..7b6d2764 100644
--- a/src/utils/xml_libxml2.c
+++ b/src/utils/xml_libxml2.c
@@ -212,6 +212,8 @@ char * xml_node_to_str(struct xml_node_ctx *ctx, xml_node_t *node)
xmlDocSetRootElement(doc, n);
xmlDocDumpFormatMemory(doc, &buf, &bufsiz, 0);
xmlFreeDoc(doc);
+ if (!buf)
+ return NULL;
pos = (char *) buf;
if (strncmp(pos, "<?xml", 5) == 0) {
pos = strchr(pos, '>');
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 4f0319ef..f65076c7 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -269,6 +269,7 @@ endif
ifdef CONFIG_IBSS_RSN
NEED_RSN_AUTHENTICATOR=y
L_CFLAGS += -DCONFIG_IBSS_RSN
+L_CFLAGS += -DCONFIG_NO_VLAN
OBJS += ibss_rsn.c
endif
@@ -1345,6 +1346,16 @@ endif
OBJS += $(DBUS_OBJS)
L_CFLAGS += $(DBUS_CFLAGS)
+ifdef CONFIG_CTRL_IFACE_BINDER
+BINDER=y
+L_CFLAGS += -DCONFIG_BINDER -DCONFIG_CTRL_IFACE_BINDER
+OBJS += binder/binder.cpp binder/binder_manager.cpp
+OBJS += binder/supplicant.cpp binder/iface.cpp
+OBJS += binder/fi/w1/wpa_supplicant/ISupplicant.aidl
+OBJS += binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl
+OBJS += binder/fi/w1/wpa_supplicant/IIface.aidl
+endif
+
ifdef CONFIG_READLINE
OBJS_c += src/utils/edit_readline.c
LIBS_c += -lncurses -lreadline
@@ -1582,6 +1593,10 @@ LOCAL_C_INCLUDES := $(INCLUDES)
ifeq ($(DBUS), y)
LOCAL_SHARED_LIBRARIES += libdbus
endif
+ifeq ($(BINDER), y)
+LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/binder frameworks/native/aidl/binder
+LOCAL_SHARED_LIBRARIES += libutils libbinder
+endif
include $(BUILD_EXECUTABLE)
########################
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 8fa2b5ac..550d44b2 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -312,9 +312,14 @@ endif
ifdef CONFIG_IBSS_RSN
NEED_RSN_AUTHENTICATOR=y
CFLAGS += -DCONFIG_IBSS_RSN
+CFLAGS += -DCONFIG_NO_VLAN
OBJS += ibss_rsn.o
endif
+ifdef CONFIG_MATCH_IFACE
+CFLAGS += -DCONFIG_MATCH_IFACE
+endif
+
ifdef CONFIG_P2P
OBJS += p2p_supplicant.o
OBJS += p2p_supplicant_sd.o
@@ -1637,6 +1642,7 @@ endif
OBJS += $(FST_OBJS)
OBJS_t += $(FST_OBJS)
OBJS_t2 += $(FST_OBJS)
+OBJS_nfc += $(FST_OBJS)
endif
ifndef LDO
diff --git a/wpa_supplicant/README b/wpa_supplicant/README
index fefc0d37..11ab01a9 100644
--- a/wpa_supplicant/README
+++ b/wpa_supplicant/README
@@ -410,7 +410,7 @@ usage:
wpa_supplicant [-BddfhKLqqtuvW] [-P<pid file>] [-g<global ctrl>] \
[-G<group>] \
-i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] [-p<driver_param>] \
- [-b<br_ifname> [-N -i<ifname> -c<conf> [-C<ctrl>] [-D<driver>] \
+ [-b<br_ifname> [-MN -i<ifname> -c<conf> [-C<ctrl>] [-D<driver>] \
[-p<driver_param>] [-b<br_ifname>] [-m<P2P Device config file>] ...
options:
@@ -434,6 +434,7 @@ options:
-u = enable DBus control interface
-v = show version
-W = wait for a control interface monitor before starting
+ -M = start describing matching interface
-N = start describing new interface
-m = Configuration file for the P2P Device
@@ -476,6 +477,22 @@ wpa_supplicant \
-c wpa2.conf -i wlan1 -D wext
+If the interfaces on which wpa_supplicant is to run are not known or do
+not exist, wpa_supplicant can match an interface when it arrives. Each
+matched interface is separated with -M argument and the -i argument now
+allows for pattern matching.
+
+As an example, the following command would start wpa_supplicant for a
+specific wired interface called lan0, any interface starting with wlan
+and lastly any other interface. Each match has its own configuration
+file, and for the wired interface a specific driver has also been given.
+
+wpa_supplicant \
+ -M -c wpa_wired.conf -ilan0 -D wired \
+ -M -c wpa1.conf -iwlan* \
+ -M -c wpa2.conf
+
+
If the interface is added in a Linux bridge (e.g., br0), the bridge
interface needs to be configured to wpa_supplicant in addition to the
main interface:
diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config
index 190bc5ac..0a8bf981 100644
--- a/wpa_supplicant/android.config
+++ b/wpa_supplicant/android.config
@@ -324,6 +324,10 @@ CONFIG_IEEE80211W=y
# Add introspection support for new DBus control interface
#CONFIG_CTRL_IFACE_DBUS_INTRO=y
+# Add support for Binder control interface
+# Only applicable for Android platforms.
+#CONFIG_CTRL_IFACE_BINDER=y
+
# Add support for loading EAP methods dynamically as shared libraries.
# When this option is enabled, each EAP method can be either included
# statically (CONFIG_EAP_<method>=y) or dynamically (CONFIG_EAP_<method>=dyn).
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index fd5b03fd..b133d038 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -1366,6 +1366,58 @@ int wpas_ap_stop_ap(struct wpa_supplicant *wpa_s)
#endif /* CONFIG_CTRL_IFACE */
+int wpas_ap_pmksa_cache_list(struct wpa_supplicant *wpa_s, char *buf,
+ size_t len)
+{
+ size_t reply_len = 0, i;
+ char ap_delimiter[] = "---- AP ----\n";
+ char mesh_delimiter[] = "---- mesh ----\n";
+ size_t dlen;
+
+ if (wpa_s->ap_iface) {
+ dlen = os_strlen(ap_delimiter);
+ if (dlen > len - reply_len)
+ return reply_len;
+ os_memcpy(&buf[reply_len], ap_delimiter, dlen);
+ reply_len += dlen;
+
+ for (i = 0; i < wpa_s->ap_iface->num_bss; i++) {
+ reply_len += hostapd_ctrl_iface_pmksa_list(
+ wpa_s->ap_iface->bss[i],
+ &buf[reply_len], len - reply_len);
+ }
+ }
+
+ if (wpa_s->ifmsh) {
+ dlen = os_strlen(mesh_delimiter);
+ if (dlen > len - reply_len)
+ return reply_len;
+ os_memcpy(&buf[reply_len], mesh_delimiter, dlen);
+ reply_len += dlen;
+
+ reply_len += hostapd_ctrl_iface_pmksa_list(
+ wpa_s->ifmsh->bss[0], &buf[reply_len],
+ len - reply_len);
+ }
+
+ return reply_len;
+}
+
+
+void wpas_ap_pmksa_cache_flush(struct wpa_supplicant *wpa_s)
+{
+ size_t i;
+
+ if (wpa_s->ap_iface) {
+ for (i = 0; i < wpa_s->ap_iface->num_bss; i++)
+ hostapd_ctrl_iface_pmksa_flush(wpa_s->ap_iface->bss[i]);
+ }
+
+ if (wpa_s->ifmsh)
+ hostapd_ctrl_iface_pmksa_flush(wpa_s->ifmsh->bss[0]);
+}
+
+
#ifdef NEED_AP_MLME
void wpas_event_dfs_radar_detected(struct wpa_supplicant *wpa_s,
struct dfs_event *radar)
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index 2b8a1d42..5a59ddcc 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -82,6 +82,10 @@ int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
int wpas_ap_stop_ap(struct wpa_supplicant *wpa_s);
+int wpas_ap_pmksa_cache_list(struct wpa_supplicant *wpa_s, char *buf,
+ size_t len);
+void wpas_ap_pmksa_cache_flush(struct wpa_supplicant *wpa_s);
+
void wpas_event_dfs_radar_detected(struct wpa_supplicant *wpa_s,
struct dfs_event *radar);
void wpas_event_dfs_cac_started(struct wpa_supplicant *wpa_s,
diff --git a/wpa_supplicant/binder/binder.cpp b/wpa_supplicant/binder/binder.cpp
new file mode 100644
index 00000000..28f7a2bf
--- /dev/null
+++ b/wpa_supplicant/binder/binder.cpp
@@ -0,0 +1,108 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
+
+#include "binder_manager.h"
+
+extern "C" {
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "binder.h"
+#include "binder_i.h"
+}
+
+void wpas_binder_sock_handler(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct wpa_global *global = (wpa_global *) eloop_ctx;
+ struct wpas_binder_priv *priv = (wpas_binder_priv *) sock_ctx;
+
+ wpa_printf(MSG_DEBUG, "Processing binder events on FD %d",
+ priv->binder_fd);
+ android::IPCThreadState::self()->handlePolledCommands();
+}
+
+
+struct wpas_binder_priv * wpas_binder_init(struct wpa_global *global)
+{
+ struct wpas_binder_priv *priv;
+ wpa_supplicant_binder::BinderManager *binder_manager;
+
+ priv = (wpas_binder_priv *) os_zalloc(sizeof(*priv));
+ if (!priv)
+ return NULL;
+ priv->global = global;
+
+ android::ProcessState::self()->setThreadPoolMaxThreadCount(0);
+ android::IPCThreadState::self()->disableBackgroundScheduling(true);
+ android::IPCThreadState::self()->setupPolling(&priv->binder_fd);
+ wpa_printf(MSG_INFO, "Process binder events on FD %d", priv->binder_fd);
+ if (priv->binder_fd < 0)
+ goto err;
+ /* Look for read events from the binder socket in the eloop. */
+ if (eloop_register_read_sock(priv->binder_fd, wpas_binder_sock_handler,
+ global, priv) < 0)
+ goto err;
+
+ binder_manager = wpa_supplicant_binder::BinderManager::getInstance();
+ if (!binder_manager)
+ goto err;
+ binder_manager->registerBinderService(global);
+ /* We may not need to store this binder manager reference in the
+ * global data strucure because we've made it a singleton class. */
+ priv->binder_manager = (void *) binder_manager;
+
+ return priv;
+
+err:
+ wpas_binder_deinit(priv);
+ return NULL;
+}
+
+
+void wpas_binder_deinit(struct wpas_binder_priv *priv)
+{
+ if (!priv)
+ return;
+
+ wpa_supplicant_binder::BinderManager::destroyInstance();
+ eloop_unregister_read_sock(priv->binder_fd);
+ android::IPCThreadState::shutdown();
+}
+
+
+int wpas_binder_register_interface(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->global->binder)
+ return 1;
+
+ wpa_supplicant_binder::BinderManager *binder_manager =
+ wpa_supplicant_binder::BinderManager::getInstance();
+ if (!binder_manager)
+ return 1;
+
+ return binder_manager->registerInterface(wpa_s);
+}
+
+
+int wpas_binder_unregister_interface(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->global->binder)
+ return 1;
+
+ wpa_supplicant_binder::BinderManager *binder_manager =
+ wpa_supplicant_binder::BinderManager::getInstance();
+ if (!binder_manager)
+ return 1;
+
+ return binder_manager->unregisterInterface(wpa_s);
+}
diff --git a/wpa_supplicant/binder/binder.h b/wpa_supplicant/binder/binder.h
new file mode 100644
index 00000000..a1650749
--- /dev/null
+++ b/wpa_supplicant/binder/binder.h
@@ -0,0 +1,46 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef BINDER_H
+#define BINDER_H
+
+#ifdef _cplusplus
+extern "C" {
+#endif /* _cplusplus */
+
+/**
+ * This is the binder RPC interface entry point to the wpa_supplicant core.
+ * This initializes the binder driver & BinderManager instance and then forwards
+ * all the notifcations from the supplicant core to the BinderManager.
+ */
+struct wpas_binder_priv;
+struct wpa_global;
+
+struct wpas_binder_priv * wpas_binder_init(struct wpa_global *global);
+void wpas_binder_deinit(struct wpas_binder_priv *priv);
+
+#ifdef CONFIG_CTRL_IFACE_BINDER
+int wpas_binder_register_interface(struct wpa_supplicant *wpa_s);
+int wpas_binder_unregister_interface(struct wpa_supplicant *wpa_s);
+#else /* CONFIG_CTRL_IFACE_BINDER */
+static inline int wpas_binder_register_interface(struct wpa_supplicant *wpa_s)
+{
+ return 0;
+}
+static inline int wpas_binder_unregister_interface(struct wpa_supplicant *wpa_s)
+{
+ return 0;
+}
+#endif /* CONFIG_CTRL_IFACE_BINDER */
+
+#ifdef _cplusplus
+}
+#endif /* _cplusplus */
+
+#endif /* BINDER_H */
diff --git a/wpa_supplicant/binder/binder_i.h b/wpa_supplicant/binder/binder_i.h
new file mode 100644
index 00000000..e8087b65
--- /dev/null
+++ b/wpa_supplicant/binder/binder_i.h
@@ -0,0 +1,27 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef BINDER_I_H
+#define BINDER_I_H
+
+#ifdef _cplusplus
+extern "C" {
+#endif // _cplusplus
+
+struct wpas_binder_priv {
+ int binder_fd;
+ struct wpa_global *global;
+ void *binder_manager;
+};
+
+#ifdef _cplusplus
+}
+#endif /* _cplusplus */
+
+#endif /* BINDER_I_H */
diff --git a/wpa_supplicant/binder/binder_manager.cpp b/wpa_supplicant/binder/binder_manager.cpp
new file mode 100644
index 00000000..728f4b7e
--- /dev/null
+++ b/wpa_supplicant/binder/binder_manager.cpp
@@ -0,0 +1,107 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include <binder/IServiceManager.h>
+
+#include "binder_manager.h"
+
+extern "C" {
+#include "utils/includes.h"
+#include "utils/common.h"
+}
+
+namespace wpa_supplicant_binder {
+
+const char BinderManager::kBinderServiceName[] = "fi.w1.wpa_supplicant";
+BinderManager *BinderManager::instance_ = NULL;
+
+
+BinderManager * BinderManager::getInstance()
+{
+ if (!instance_)
+ instance_ = new BinderManager();
+ return instance_;
+}
+
+
+void BinderManager::destroyInstance()
+{
+ if (instance_)
+ delete instance_;
+ instance_ = NULL;
+}
+
+
+int BinderManager::registerBinderService(struct wpa_global *global)
+{
+ /* Create the main binder service object and register with
+ * system service manager. */
+ supplicant_object_ = new Supplicant(global);
+ android::String16 service_name(kBinderServiceName);
+ android::defaultServiceManager()->addService(
+ service_name,
+ android::IInterface::asBinder(supplicant_object_));
+ return 0;
+}
+
+
+int BinderManager::registerInterface(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s)
+ return 1;
+
+ /* Using the corresponding wpa_supplicant pointer as key to our
+ * object map. */
+ const void *iface_key = wpa_s;
+
+ /* Return failure if we already have an object for that iface_key. */
+ if (iface_object_map_.find(iface_key) != iface_object_map_.end())
+ return 1;
+
+ iface_object_map_[iface_key] = new Iface(wpa_s);
+ if (!iface_object_map_[iface_key].get())
+ return 1;
+
+ wpa_s->binder_object_key = iface_key;
+
+ return 0;
+}
+
+
+int BinderManager::unregisterInterface(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s || !wpa_s->binder_object_key)
+ return 1;
+
+ const void *iface_key = wpa_s;
+ if (iface_object_map_.find(iface_key) == iface_object_map_.end())
+ return 1;
+
+ /* Delete the corresponding iface object from our map. */
+ iface_object_map_.erase(iface_key);
+ wpa_s->binder_object_key = NULL;
+ return 0;
+}
+
+
+int BinderManager::getIfaceBinderObjectByKey(
+ const void *iface_object_key,
+ android::sp<fi::w1::wpa_supplicant::IIface> *iface_object)
+{
+ if (!iface_object_key || !iface_object)
+ return 1;
+
+ if (iface_object_map_.find(iface_object_key) == iface_object_map_.end())
+ return 1;
+
+ *iface_object = iface_object_map_[iface_object_key];
+ return 0;
+}
+
+} /* namespace wpa_supplicant_binder */
diff --git a/wpa_supplicant/binder/binder_manager.h b/wpa_supplicant/binder/binder_manager.h
new file mode 100644
index 00000000..687e7404
--- /dev/null
+++ b/wpa_supplicant/binder/binder_manager.h
@@ -0,0 +1,59 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef BINDER_MANAGER_H
+#define BINDER_MANAGER_H
+
+#include <map>
+#include <string>
+
+#include "supplicant.h"
+#include "iface.h"
+
+struct wpa_global;
+struct wpa_supplicant;
+
+namespace wpa_supplicant_binder {
+
+/**
+ * BinderManager is responsible for managing the lifetime of all
+ * binder objects created by wpa_supplicant. This is a singleton
+ * class which is created by the supplicant core and can be used
+ * to get references to the binder objects.
+ */
+class BinderManager {
+public:
+ static const char kBinderServiceName[];
+
+ static BinderManager * getInstance();
+ static void destroyInstance();
+ int registerBinderService(struct wpa_global *global);
+ int registerInterface(struct wpa_supplicant *wpa_s);
+ int unregisterInterface(struct wpa_supplicant *wpa_s);
+ int getIfaceBinderObjectByKey(
+ const void *iface_object_key,
+ android::sp<fi::w1::wpa_supplicant::IIface> *iface_object);
+
+private:
+ BinderManager() = default;
+ ~BinderManager() = default;
+
+ /* Singleton instance of this class. */
+ static BinderManager *instance_;
+ /* The main binder service object. */
+ android::sp<Supplicant> supplicant_object_;
+ /* Map of all the interface specific binder objects controlled by
+ * wpa_supplicant. This map is keyed in by the corresponding
+ * wpa_supplicant structure pointer. */
+ std::map<const void *, android::sp<Iface>> iface_object_map_;
+};
+
+} /* namespace wpa_supplicant_binder */
+
+#endif /* BINDER_MANAGER_H */
diff --git a/wpa_supplicant/binder/fi/w1/wpa_supplicant/IIface.aidl b/wpa_supplicant/binder/fi/w1/wpa_supplicant/IIface.aidl
new file mode 100644
index 00000000..ea11d426
--- /dev/null
+++ b/wpa_supplicant/binder/fi/w1/wpa_supplicant/IIface.aidl
@@ -0,0 +1,16 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+package fi.w1.wpa_supplicant;
+
+/**
+ * Interface exposed by wpa_supplicant for each network interface it controls.
+ */
+interface IIface {
+}
diff --git a/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicant.aidl b/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicant.aidl
new file mode 100644
index 00000000..1cbee20a
--- /dev/null
+++ b/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicant.aidl
@@ -0,0 +1,59 @@
+/*
+ * WPA Supplicant - binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+package fi.w1.wpa_supplicant;
+
+import android.os.PersistableBundle;
+import fi.w1.wpa_supplicant.IIface;
+
+/**
+ * Interface exposed by the wpa_supplicant binder service registered
+ * with the service manager with name: fi.w1.wpa_supplicant.
+ */
+interface ISupplicant {
+ /* Error values returned by the service to RPC method calls. */
+ const int ERROR_INVALID_ARGS = 1;
+ const int ERROR_UNKNOWN = 2;
+ const int ERROR_IFACE_EXISTS = 3;
+ const int ERROR_IFACE_UNKNOWN = 4;
+
+ /**
+ * Registers a wireless interface in wpa_supplicant.
+ *
+ * @param args A dictionary with arguments used to add the interface to
+ * wpa_supplicant.
+ * The dictionary may contain the following entries:
+ * Ifname(String) Name of the network interface to control, e.g.,
+ * wlan0.
+ * BridgeIfname(String) Name of the bridge interface to control, e.g.,
+ * br0.
+ * Driver(String) Driver name which the interface uses, e.g., nl80211.
+ * ConfigFile(String) Configuration file path.
+ *
+ * @return Binder object representing the interface.
+ */
+ IIface CreateInterface(in PersistableBundle args);
+
+ /**
+ * Deregisters a wireless interface from wpa_supplicant.
+ *
+ * @param ifname Name of the network interface, e.g., wlan0
+ */
+ void RemoveInterface(in @utf8InCpp String ifname);
+
+ /**
+ * Gets a binder object for the interface corresponding to ifname
+ * which wpa_supplicant already controls.
+ *
+ * @param ifname Name of the network interface, e.g., wlan0
+ *
+ * @return Binder object representing the interface.
+ */
+ IIface GetInterface(in @utf8InCpp String ifname);
+}
diff --git a/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl b/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl
new file mode 100644
index 00000000..d624d913
--- /dev/null
+++ b/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl
@@ -0,0 +1,20 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+package fi.w1.wpa_supplicant;
+
+import android.os.PersistableBundle;
+
+/**
+ * Callback Interface exposed by the wpa_supplicant service. Clients need
+ * to host an instance of this binder object and pass a reference of the object
+ * to wpa_supplicant via the registerCallbacksObject method.
+ */
+interface ISupplicantCallbacks {
+}
diff --git a/wpa_supplicant/binder/iface.cpp b/wpa_supplicant/binder/iface.cpp
new file mode 100644
index 00000000..af2548d8
--- /dev/null
+++ b/wpa_supplicant/binder/iface.cpp
@@ -0,0 +1,19 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "iface.h"
+
+namespace wpa_supplicant_binder {
+
+Iface::Iface(struct wpa_supplicant *wpa_s)
+ : wpa_s_(wpa_s)
+{
+}
+
+} /* namespace wpa_supplicant_binder */
diff --git a/wpa_supplicant/binder/iface.h b/wpa_supplicant/binder/iface.h
new file mode 100644
index 00000000..acc8e55e
--- /dev/null
+++ b/wpa_supplicant/binder/iface.h
@@ -0,0 +1,42 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef IFACE_H
+#define IFACE_H
+
+#include "fi/w1/wpa_supplicant/BnIface.h"
+
+extern "C" {
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "../wpa_supplicant_i.h"
+}
+
+namespace wpa_supplicant_binder {
+
+/**
+ * Implementation of Iface binder object. Each unique binder
+ * object is used for control operations on a specific interface
+ * controlled by wpa_supplicant.
+ */
+class Iface : public fi::w1::wpa_supplicant::BnIface
+{
+public:
+ Iface(struct wpa_supplicant *wpa_s);
+ virtual ~Iface() = default;
+
+private:
+ /* Raw pointer to the structure maintained by the core for this
+ * interface. */
+ struct wpa_supplicant *wpa_s_;
+};
+
+} /* namespace wpa_supplicant_binder */
+
+#endif /* IFACE_H */
diff --git a/wpa_supplicant/binder/supplicant.cpp b/wpa_supplicant/binder/supplicant.cpp
new file mode 100644
index 00000000..6844e5a3
--- /dev/null
+++ b/wpa_supplicant/binder/supplicant.cpp
@@ -0,0 +1,125 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "binder_manager.h"
+#include "supplicant.h"
+
+namespace wpa_supplicant_binder {
+
+Supplicant::Supplicant(struct wpa_global *global)
+ : wpa_global_(global)
+{
+}
+
+
+android::binder::Status Supplicant::CreateInterface(
+ const android::os::PersistableBundle &params,
+ android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return)
+{
+ android::String16 driver, ifname, confname, bridge_ifname;
+
+ /* Check if required Ifname argument is missing */
+ if (!params.getString(android::String16("Ifname"), &ifname))
+ return android::binder::Status::fromServiceSpecificError(
+ ERROR_INVALID_ARGS,
+ android::String8("Ifname missing in params."));
+ /* Retrieve the remaining params from the dictionary */
+ params.getString(android::String16("Driver"), &driver);
+ params.getString(android::String16("ConfigFile"), &confname);
+ params.getString(android::String16("BridgeIfname"), &bridge_ifname);
+
+ /*
+ * Try to get the wpa_supplicant record for this iface, return
+ * an error if we already control it.
+ */
+ if (wpa_supplicant_get_iface(wpa_global_,
+ android::String8(ifname).string()) != NULL)
+ return android::binder::Status::fromServiceSpecificError(
+ ERROR_IFACE_EXISTS,
+ android::String8("wpa_supplicant already controls this interface."));
+
+ android::binder::Status status;
+ struct wpa_supplicant *wpa_s = NULL;
+ struct wpa_interface iface;
+
+ os_memset(&iface, 0, sizeof(iface));
+ iface.driver = os_strdup(android::String8(driver).string());
+ iface.ifname = os_strdup(android::String8(ifname).string());
+ iface.confname = os_strdup(android::String8(confname).string());
+ iface.bridge_ifname = os_strdup(
+ android::String8(bridge_ifname).string());
+ /* Otherwise, have wpa_supplicant attach to it. */
+ wpa_s = wpa_supplicant_add_iface(wpa_global_, &iface, NULL);
+ /* The supplicant core creates a corresponding binder object via
+ * BinderManager when |wpa_supplicant_add_iface| is called. */
+ if (!wpa_s || !wpa_s->binder_object_key) {
+ status = android::binder::Status::fromServiceSpecificError(
+ ERROR_UNKNOWN,
+ android::String8("wpa_supplicant couldn't grab this interface."));
+ } else {
+ BinderManager *binder_manager = BinderManager::getInstance();
+
+ if (!binder_manager ||
+ binder_manager->getIfaceBinderObjectByKey(
+ wpa_s->binder_object_key, aidl_return))
+ status = android::binder::Status::fromServiceSpecificError(
+ ERROR_UNKNOWN,
+ android::String8("wpa_supplicant encountered a binder error."));
+ else
+ status = android::binder::Status::ok();
+ }
+ os_free((void *) iface.driver);
+ os_free((void *) iface.ifname);
+ os_free((void *) iface.confname);
+ os_free((void *) iface.bridge_ifname);
+ return status;
+}
+
+
+android::binder::Status Supplicant::RemoveInterface(const std::string &ifname)
+{
+ struct wpa_supplicant *wpa_s;
+
+ wpa_s = wpa_supplicant_get_iface(wpa_global_, ifname.c_str());
+ if (!wpa_s || !wpa_s->binder_object_key)
+ return android::binder::Status::fromServiceSpecificError(
+ ERROR_IFACE_UNKNOWN,
+ android::String8("wpa_supplicant does not control this interface."));
+ if (wpa_supplicant_remove_iface(wpa_global_, wpa_s, 0))
+ return android::binder::Status::fromServiceSpecificError(
+ ERROR_UNKNOWN,
+ android::String8("wpa_supplicant couldn't remove this interface."));
+ return android::binder::Status::ok();
+}
+
+
+android::binder::Status Supplicant::GetInterface(
+ const std::string &ifname,
+ android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return)
+{
+ struct wpa_supplicant *wpa_s;
+
+ wpa_s = wpa_supplicant_get_iface(wpa_global_, ifname.c_str());
+ if (!wpa_s || !wpa_s->binder_object_key)
+ return android::binder::Status::fromServiceSpecificError(
+ ERROR_IFACE_UNKNOWN,
+ android::String8("wpa_supplicant does not control this interface."));
+
+ BinderManager *binder_manager = BinderManager::getInstance();
+ if (!binder_manager ||
+ binder_manager->getIfaceBinderObjectByKey(wpa_s->binder_object_key,
+ aidl_return))
+ return android::binder::Status::fromServiceSpecificError(
+ ERROR_UNKNOWN,
+ android::String8("wpa_supplicant encountered a binder error."));
+
+ return android::binder::Status::ok();
+}
+
+} /* namespace wpa_supplicant_binder */
diff --git a/wpa_supplicant/binder/supplicant.h b/wpa_supplicant/binder/supplicant.h
new file mode 100644
index 00000000..b96f4e6a
--- /dev/null
+++ b/wpa_supplicant/binder/supplicant.h
@@ -0,0 +1,57 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SUPPLICANT_H
+#define SUPPLICANT_H
+
+#include "fi/w1/wpa_supplicant/BnSupplicant.h"
+#include "fi/w1/wpa_supplicant/IIface.h"
+#include "fi/w1/wpa_supplicant/ISupplicantCallbacks.h"
+
+extern "C" {
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "../wpa_supplicant_i.h"
+}
+
+namespace wpa_supplicant_binder {
+
+/**
+ * Implementation of the supplicant binder object. This binder
+ * object is used core for global control operations on
+ * wpa_supplicant.
+ */
+class Supplicant : public fi::w1::wpa_supplicant::BnSupplicant
+{
+public:
+ Supplicant(struct wpa_global *global);
+ virtual ~Supplicant() = default;
+
+ android::binder::Status CreateInterface(
+ const android::os::PersistableBundle &params,
+ android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return)
+ override;
+ android::binder::Status RemoveInterface(
+ const std::string &ifname) override;
+ android::binder::Status GetInterface(
+ const std::string &ifname,
+ android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return)
+ override;
+
+private:
+ /* Raw pointer to the global structure maintained by the core. */
+ struct wpa_global *wpa_global_;
+ /* All the callback objects registered by the clients. */
+ std::vector<android::sp<fi::w1::wpa_supplicant::ISupplicantCallbacks>>
+ callbacks_;
+};
+
+} /* namespace wpa_supplicant_binder */
+
+#endif /* SUPPLICANT_H */
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 796977b0..43766763 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -32,7 +32,11 @@ struct parse_data {
/* Configuration variable name */
char *name;
- /* Parser function for this variable */
+ /* Parser function for this variable. The parser functions return 0 or 1
+ * to indicate success. Value 0 indicates that the parameter value may
+ * have changed while value 1 means that the value did not change.
+ * Error cases (failure to parse the string) are indicated by returning
+ * -1. */
int (*parser)(const struct parse_data *data, struct wpa_ssid *ssid,
int line, const char *value);
@@ -59,7 +63,7 @@ static int wpa_config_parse_str(const struct parse_data *data,
struct wpa_ssid *ssid,
int line, const char *value)
{
- size_t res_len, *dst_len;
+ size_t res_len, *dst_len, prev_len;
char **dst, *tmp;
if (os_strcmp(value, "NULL") == 0) {
@@ -105,6 +109,21 @@ static int wpa_config_parse_str(const struct parse_data *data,
set:
dst = (char **) (((u8 *) ssid) + (long) data->param1);
dst_len = (size_t *) (((u8 *) ssid) + (long) data->param2);
+
+ if (data->param2)
+ prev_len = *dst_len;
+ else if (*dst)
+ prev_len = os_strlen(*dst);
+ else
+ prev_len = 0;
+ if ((*dst == NULL && tmp == NULL) ||
+ (*dst && tmp && prev_len == res_len &&
+ os_memcmp(*dst, tmp, res_len) == 0)) {
+ /* No change to the previously configured value */
+ os_free(tmp);
+ return 1;
+ }
+
os_free(*dst);
*dst = tmp;
if (data->param2)
@@ -190,6 +209,9 @@ static int wpa_config_parse_int(const struct parse_data *data,
line, value);
return -1;
}
+
+ if (*dst == val)
+ return 1;
*dst = val;
wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst);
@@ -457,8 +479,10 @@ static int wpa_config_parse_psk(const struct parse_data *data,
wpa_hexdump_ascii_key(MSG_MSGDUMP, "PSK (ASCII passphrase)",
(u8 *) value, len);
if (ssid->passphrase && os_strlen(ssid->passphrase) == len &&
- os_memcmp(ssid->passphrase, value, len) == 0)
- return 0;
+ os_memcmp(ssid->passphrase, value, len) == 0) {
+ /* No change to the previously configured value */
+ return 1;
+ }
ssid->psk_set = 0;
str_clear_free(ssid->passphrase);
ssid->passphrase = dup_binstr(value, len);
@@ -569,6 +593,8 @@ static int wpa_config_parse_proto(const struct parse_data *data,
errors++;
}
+ if (!errors && ssid->proto == val)
+ return 1;
wpa_printf(MSG_MSGDUMP, "proto: 0x%x", val);
ssid->proto = val;
return errors ? -1 : 0;
@@ -705,6 +731,8 @@ static int wpa_config_parse_key_mgmt(const struct parse_data *data,
errors++;
}
+ if (!errors && ssid->key_mgmt == val)
+ return 1;
wpa_printf(MSG_MSGDUMP, "key_mgmt: 0x%x", val);
ssid->key_mgmt = val;
return errors ? -1 : 0;
@@ -953,6 +981,8 @@ static int wpa_config_parse_pairwise(const struct parse_data *data,
return -1;
}
+ if (ssid->pairwise_cipher == val)
+ return 1;
wpa_printf(MSG_MSGDUMP, "pairwise: 0x%x", val);
ssid->pairwise_cipher = val;
return 0;
@@ -989,6 +1019,8 @@ static int wpa_config_parse_group(const struct parse_data *data,
return -1;
}
+ if (ssid->group_cipher == val)
+ return 1;
wpa_printf(MSG_MSGDUMP, "group: 0x%x", val);
ssid->group_cipher = val;
return 0;
@@ -1050,6 +1082,8 @@ static int wpa_config_parse_auth_alg(const struct parse_data *data,
errors++;
}
+ if (!errors && ssid->auth_alg == val)
+ return 1;
wpa_printf(MSG_MSGDUMP, "auth_alg: 0x%x", val);
ssid->auth_alg = val;
return errors ? -1 : 0;
@@ -1304,6 +1338,32 @@ static int wpa_config_parse_eap(const struct parse_data *data,
methods[num_methods].method = EAP_TYPE_NONE;
num_methods++;
+ if (!errors && ssid->eap.eap_methods) {
+ struct eap_method_type *prev_m;
+ size_t i, j, prev_methods, match = 0;
+
+ prev_m = ssid->eap.eap_methods;
+ for (i = 0; prev_m[i].vendor != EAP_VENDOR_IETF ||
+ prev_m[i].method != EAP_TYPE_NONE; i++) {
+ /* Count the methods */
+ }
+ prev_methods = i + 1;
+
+ for (i = 0; prev_methods == num_methods && i < prev_methods;
+ i++) {
+ for (j = 0; j < num_methods; j++) {
+ if (prev_m[i].vendor == methods[j].vendor &&
+ prev_m[i].method == methods[j].method) {
+ match++;
+ break;
+ }
+ }
+ }
+ if (match == num_methods) {
+ os_free(methods);
+ return 1;
+ }
+ }
wpa_hexdump(MSG_MSGDUMP, "eap methods",
(u8 *) methods, num_methods * sizeof(*methods));
os_free(ssid->eap.eap_methods);
@@ -1356,6 +1416,8 @@ static int wpa_config_parse_password(const struct parse_data *data,
u8 *hash;
if (os_strcmp(value, "NULL") == 0) {
+ if (!ssid->eap.password)
+ return 1; /* Already unset */
wpa_printf(MSG_DEBUG, "Unset configuration string 'password'");
bin_clear_free(ssid->eap.password, ssid->eap.password_len);
ssid->eap.password = NULL;
@@ -1419,6 +1481,12 @@ static int wpa_config_parse_password(const struct parse_data *data,
wpa_hexdump_key(MSG_MSGDUMP, data->name, hash, 16);
+ if (ssid->eap.password && ssid->eap.password_len == 16 &&
+ os_memcmp(ssid->eap.password, hash, 16) == 0 &&
+ (ssid->eap.flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH)) {
+ bin_clear_free(hash, 16);
+ return 1;
+ }
bin_clear_free(ssid->eap.password, ssid->eap.password_len);
ssid->eap.password = hash;
ssid->eap.password_len = 16;
@@ -2472,7 +2540,8 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
* @var: Variable name, e.g., "ssid"
* @value: Variable value
* @line: Line number in configuration file or 0 if not used
- * Returns: 0 on success, -1 on failure
+ * Returns: 0 on success with possible change in the value, 1 on success with
+ * no change to previously configured value, or -1 on failure
*
* This function can be used to set network configuration variables based on
* both the configuration file and management interface input. The value
@@ -2493,7 +2562,8 @@ int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value,
if (os_strcmp(var, field->name) != 0)
continue;
- if (field->parser(field, ssid, line, value)) {
+ ret = field->parser(field, ssid, line, value);
+ if (ret < 0) {
if (line) {
wpa_printf(MSG_ERROR, "Line %d: failed to "
"parse %s '%s'.", line, var, value);
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 4e169871..85744379 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -2727,6 +2727,40 @@ static int wpa_supplicant_ctrl_iface_mesh_group_remove(
return 0;
}
+
+static int wpa_supplicant_ctrl_iface_mesh_peer_remove(
+ struct wpa_supplicant *wpa_s, char *cmd)
+{
+ u8 addr[ETH_ALEN];
+
+ if (hwaddr_aton(cmd, addr) < 0)
+ return -1;
+
+ return wpas_mesh_peer_remove(wpa_s, addr);
+}
+
+
+static int wpa_supplicant_ctrl_iface_mesh_peer_add(
+ struct wpa_supplicant *wpa_s, char *cmd)
+{
+ u8 addr[ETH_ALEN];
+ int duration;
+ char *pos;
+
+ pos = os_strstr(cmd, " duration=");
+ if (pos) {
+ *pos = '\0';
+ duration = atoi(pos + 10);
+ } else {
+ duration = -1;
+ }
+
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+
+ return wpas_mesh_peer_add(wpa_s, addr, duration);
+}
+
#endif /* CONFIG_MESH */
@@ -2969,22 +3003,29 @@ static int wpa_supplicant_ctrl_iface_update_network(
struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
char *name, char *value)
{
- if (wpa_config_set(ssid, name, value, 0) < 0) {
+ int ret;
+
+ ret = wpa_config_set(ssid, name, value, 0);
+ if (ret < 0) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network "
"variable '%s'", name);
return -1;
}
+ if (ret == 1)
+ return 0; /* No change to the previously configured value */
if (os_strcmp(name, "bssid") != 0 &&
- os_strcmp(name, "priority") != 0)
+ os_strcmp(name, "priority") != 0) {
wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
- if (wpa_s->current_ssid == ssid || wpa_s->current_ssid == NULL) {
- /*
- * Invalidate the EAP session cache if anything in the current
- * or previously used configuration changes.
- */
- eapol_sm_invalidate_cached_session(wpa_s->eapol);
+ if (wpa_s->current_ssid == ssid ||
+ wpa_s->current_ssid == NULL) {
+ /*
+ * Invalidate the EAP session cache if anything in the
+ * current or previously used configuration changes.
+ */
+ eapol_sm_invalidate_cached_session(wpa_s->eapol);
+ }
}
if ((os_strcmp(name, "psk") == 0 &&
@@ -8328,6 +8369,29 @@ static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s,
}
+static int wpas_ctrl_iface_pmksa(struct wpa_supplicant *wpa_s,
+ char *buf, size_t buflen)
+{
+ size_t reply_len;
+
+ reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, buf, buflen);
+#ifdef CONFIG_AP
+ reply_len += wpas_ap_pmksa_cache_list(wpa_s, &buf[reply_len],
+ buflen - reply_len);
+#endif /* CONFIG_AP */
+ return reply_len;
+}
+
+
+static void wpas_ctrl_iface_pmksa_flush(struct wpa_supplicant *wpa_s)
+{
+ wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
+#ifdef CONFIG_AP
+ wpas_ap_pmksa_cache_flush(wpa_s);
+#endif /* CONFIG_AP */
+}
+
+
static int wpas_ctrl_cmd_debug_level(const char *cmd)
{
if (os_strcmp(cmd, "PING") == 0 ||
@@ -8399,10 +8463,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
reply_len = wpa_supplicant_ctrl_iface_status(
wpa_s, buf + 6, reply, reply_size);
} else if (os_strcmp(buf, "PMKSA") == 0) {
- reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, reply,
- reply_size);
+ reply_len = wpas_ctrl_iface_pmksa(wpa_s, reply, reply_size);
} else if (os_strcmp(buf, "PMKSA_FLUSH") == 0) {
- wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
+ wpas_ctrl_iface_pmksa_flush(wpa_s);
} else if (os_strncmp(buf, "SET ", 4) == 0) {
if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
reply_len = -1;
@@ -8570,6 +8633,12 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
if (wpa_supplicant_ctrl_iface_mesh_group_remove(wpa_s,
buf + 18))
reply_len = -1;
+ } else if (os_strncmp(buf, "MESH_PEER_REMOVE ", 17) == 0) {
+ if (wpa_supplicant_ctrl_iface_mesh_peer_remove(wpa_s, buf + 17))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "MESH_PEER_ADD ", 14) == 0) {
+ if (wpa_supplicant_ctrl_iface_mesh_peer_add(wpa_s, buf + 14))
+ reply_len = -1;
#endif /* CONFIG_MESH */
#ifdef CONFIG_P2P
} else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) {
diff --git a/wpa_supplicant/ctrl_iface_udp.c b/wpa_supplicant/ctrl_iface_udp.c
index 503052a6..0dc0937f 100644
--- a/wpa_supplicant/ctrl_iface_udp.c
+++ b/wpa_supplicant/ctrl_iface_udp.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / UDP socket -based control interface
- * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -378,6 +378,7 @@ struct ctrl_iface_priv *
wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
{
struct ctrl_iface_priv *priv;
+ char port_str[40];
int port = WPA_CTRL_IFACE_PORT;
char *pos;
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
@@ -439,13 +440,21 @@ try_again:
#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
port--;
- if ((WPA_CTRL_IFACE_PORT - port) < WPA_CTRL_IFACE_PORT_LIMIT &&
- !pos)
+ if ((WPA_CTRL_IFACE_PORT - port) < WPA_CTRL_IFACE_PORT_LIMIT)
goto try_again;
wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
goto fail;
}
+ /* Update the ctrl_interface value to match the selected port */
+ os_snprintf(port_str, sizeof(port_str), "udp:%d", port);
+ os_free(wpa_s->conf->ctrl_interface);
+ wpa_s->conf->ctrl_interface = os_strdup(port_str);
+ if (!wpa_s->conf->ctrl_interface) {
+ wpa_msg(wpa_s, MSG_ERROR, "Failed to malloc ctrl_interface");
+ goto fail;
+ }
+
#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
wpa_msg(wpa_s, MSG_DEBUG, "ctrl_iface_init UDP port: %d", port);
#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
@@ -593,7 +602,11 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
struct ctrl_iface_global_priv *priv = sock_ctx;
char buf[256], *pos;
int res;
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+ struct sockaddr_in6 from;
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
struct sockaddr_in from;
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
socklen_t fromlen = sizeof(from);
char *reply = NULL;
size_t reply_len;
@@ -608,6 +621,7 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
}
#ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
+#ifndef CONFIG_CTRL_IFACE_UDP_IPV6
if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
/*
* The OS networking stack is expected to drop this kind of
@@ -619,6 +633,7 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
"source %s", inet_ntoa(from.sin_addr));
return;
}
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
buf[res] = '\0';
diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c
index 2fc89a92..4db712ff 100644
--- a/wpa_supplicant/ctrl_iface_unix.c
+++ b/wpa_supplicant/ctrl_iface_unix.c
@@ -15,7 +15,6 @@
#include <fcntl.h>
#ifdef __linux__
#include <sys/ioctl.h>
-#include <linux/sockios.h>
#endif /* __linux__ */
#ifdef ANDROID
#include <cutils/sockets.h>
@@ -90,7 +89,7 @@ static void wpas_ctrl_sock_debug(const char *title, int sock, const char *buf,
if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sndbuf, &optlen) < 0)
sndbuf = -1;
- if (ioctl(sock, SIOCOUTQ, &outq) < 0)
+ if (ioctl(sock, TIOCOUTQ, &outq) < 0)
outq = -1;
wpa_printf(level,
@@ -289,7 +288,7 @@ static int wpas_ctrl_iface_throttle(int sock)
optlen = sizeof(sndbuf);
sndbuf = 0;
if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sndbuf, &optlen) < 0 ||
- ioctl(sock, SIOCOUTQ, &outq) < 0 ||
+ ioctl(sock, TIOCOUTQ, &outq) < 0 ||
sndbuf <= 0 || outq < 0)
return 0;
return outq > sndbuf / 2;
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index 79632e68..1d05198f 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -467,6 +467,9 @@ CONFIG_PEERKEY=y
# Hotspot 2.0
#CONFIG_HS20=y
+# Enable interface matching in wpa_supplicant
+#CONFIG_MATCH_IFACE=y
+
# Disable roaming in wpa_supplicant
#CONFIG_NO_ROAMING=y
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index a84ba2dc..6b3a2c06 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -1346,6 +1346,7 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
struct wpa_bss *current_bss = NULL;
#ifndef CONFIG_NO_ROAMING
int min_diff;
+ int to_5ghz;
#endif /* CONFIG_NO_ROAMING */
if (wpa_s->reassociate)
@@ -1401,7 +1402,10 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
return 1;
}
- if (current_bss->level < 0 && current_bss->level > selected->level) {
+ to_5ghz = selected->freq > 4000 && current_bss->freq < 4000;
+
+ if (current_bss->level < 0 &&
+ current_bss->level > selected->level + to_5ghz * 2) {
wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - Current BSS has better "
"signal level");
return 0;
@@ -1420,6 +1424,13 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
else
min_diff = 5;
}
+ if (to_5ghz) {
+ /* Make it easier to move to 5 GHz band */
+ if (min_diff > 2)
+ min_diff -= 2;
+ else
+ min_diff = 0;
+ }
if (abs(current_bss->level - selected->level) < min_diff) {
wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - too small difference "
"in signal level");
@@ -1984,6 +1995,8 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
}
if ((p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 &&
(os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0)) ||
+ (p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 4 &&
+ (os_memcmp(&p[2], "\x50\x6F\x9A\x12", 4) == 0)) ||
(p[0] == WLAN_EID_RSN && p[1] >= 2)) {
if (wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, p, len))
break;
@@ -2760,6 +2773,13 @@ wpa_supplicant_event_interface_status(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_MATCH_IFACE
+ if (wpa_s->matched) {
+ wpa_supplicant_remove_iface(wpa_s->global, wpa_s, 0);
+ break;
+ }
+#endif /* CONFIG_MATCH_IFACE */
+
#ifdef CONFIG_TERMINATE_ONLASTIF
/* check if last interface */
if (!any_interfaces(wpa_s->global->ifaces))
@@ -3690,12 +3710,14 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
#endif /* CONFIG_AP */
#ifdef CONFIG_P2P
if (stype == WLAN_FC_STYPE_PROBE_REQ &&
- data->rx_mgmt.frame_len > 24) {
+ data->rx_mgmt.frame_len > IEEE80211_HDRLEN) {
const u8 *src = mgmt->sa;
- const u8 *ie = mgmt->u.probe_req.variable;
- size_t ie_len = data->rx_mgmt.frame_len -
- (mgmt->u.probe_req.variable -
- data->rx_mgmt.frame);
+ const u8 *ie;
+ size_t ie_len;
+
+ ie = data->rx_mgmt.frame + IEEE80211_HDRLEN;
+ ie_len = data->rx_mgmt.frame_len -
+ IEEE80211_HDRLEN;
wpas_p2p_probe_req_rx(
wpa_s, src, mgmt->da,
mgmt->bssid, ie, ie_len,
@@ -3735,11 +3757,12 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
}
if (stype == WLAN_FC_STYPE_PROBE_REQ &&
- data->rx_mgmt.frame_len > 24) {
- const u8 *ie = mgmt->u.probe_req.variable;
- size_t ie_len = data->rx_mgmt.frame_len -
- (mgmt->u.probe_req.variable -
- data->rx_mgmt.frame);
+ data->rx_mgmt.frame_len > IEEE80211_HDRLEN) {
+ const u8 *ie;
+ size_t ie_len;
+
+ ie = data->rx_mgmt.frame + IEEE80211_HDRLEN;
+ ie_len = data->rx_mgmt.frame_len - IEEE80211_HDRLEN;
wpas_notify_preq(wpa_s, mgmt->sa, mgmt->da,
mgmt->bssid, ie, ie_len,
@@ -4010,3 +4033,43 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
break;
}
}
+
+
+void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event,
+ union wpa_event_data *data)
+{
+ struct wpa_supplicant *wpa_s;
+
+ if (event != EVENT_INTERFACE_STATUS)
+ return;
+
+ wpa_s = wpa_supplicant_get_iface(ctx, data->interface_status.ifname);
+ if (wpa_s && wpa_s->driver->get_ifindex) {
+ unsigned int ifindex;
+
+ ifindex = wpa_s->driver->get_ifindex(wpa_s->drv_priv);
+ if (ifindex != data->interface_status.ifindex) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "interface status ifindex %d mismatch (%d)",
+ ifindex, data->interface_status.ifindex);
+ return;
+ }
+ }
+#ifdef CONFIG_MATCH_IFACE
+ else if (data->interface_status.ievent == EVENT_INTERFACE_ADDED) {
+ struct wpa_interface *wpa_i;
+
+ wpa_i = wpa_supplicant_match_iface(
+ ctx, data->interface_status.ifname);
+ if (!wpa_i)
+ return;
+ wpa_s = wpa_supplicant_add_iface(ctx, wpa_i, NULL);
+ os_free(wpa_i);
+ if (wpa_s)
+ wpa_s->matched = 1;
+ }
+#endif /* CONFIG_MATCH_IFACE */
+
+ if (wpa_s)
+ wpa_supplicant_event(wpa_s, event, data);
+}
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index 9df1607e..589ee57b 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -1451,7 +1451,24 @@ static int interworking_set_eap_params(struct wpa_ssid *ssid,
os_free(anon);
}
- if (cred->username && cred->username[0] &&
+ if (!ttls && cred->username && cred->username[0] && cred->realm &&
+ !os_strchr(cred->username, '@')) {
+ char *id;
+ size_t buflen;
+ int res;
+
+ buflen = os_strlen(cred->username) + 1 +
+ os_strlen(cred->realm) + 1;
+
+ id = os_malloc(buflen);
+ if (!id)
+ return -1;
+ os_snprintf(id, buflen, "%s@%s", cred->username, cred->realm);
+ res = wpa_config_set_quoted(ssid, "identity", id);
+ os_free(id);
+ if (res < 0)
+ return -1;
+ } else if (cred->username && cred->username[0] &&
wpa_config_set_quoted(ssid, "identity", cred->username) < 0)
return -1;
diff --git a/wpa_supplicant/main.c b/wpa_supplicant/main.c
index 3ab80a57..e08c2fd2 100644
--- a/wpa_supplicant/main.c
+++ b/wpa_supplicant/main.c
@@ -81,6 +81,9 @@ static void usage(void)
#ifdef CONFIG_P2P
" -m = Configuration file for the P2P Device interface\n"
#endif /* CONFIG_P2P */
+#ifdef CONFIG_MATCH_IFACE
+ " -M = start describing new matching interface\n"
+#endif /* CONFIG_MATCH_IFACE */
" -N = start describing new interface\n"
" -o = override driver parameter for new interfaces\n"
" -O = override ctrl_interface parameter for new interfaces\n"
@@ -153,6 +156,28 @@ static void wpa_supplicant_fd_workaround(int start)
}
+#ifdef CONFIG_MATCH_IFACE
+static int wpa_supplicant_init_match(struct wpa_global *global)
+{
+ /*
+ * The assumption is that the first driver is the primary driver and
+ * will handle the arrival / departure of interfaces.
+ */
+ if (wpa_drivers[0]->global_init && !global->drv_priv[0]) {
+ global->drv_priv[0] = wpa_drivers[0]->global_init(global);
+ if (!global->drv_priv[0]) {
+ wpa_printf(MSG_ERROR,
+ "Failed to initialize driver '%s'",
+ wpa_drivers[0]->name);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+#endif /* CONFIG_MATCH_IFACE */
+
+
int main(int argc, char *argv[])
{
int c, i;
@@ -176,7 +201,7 @@ int main(int argc, char *argv[])
for (;;) {
c = getopt(argc, argv,
- "b:Bc:C:D:de:f:g:G:hi:I:KLm:No:O:p:P:qsTtuvW");
+ "b:Bc:C:D:de:f:g:G:hi:I:KLMm:No:O:p:P:qsTtuvW");
if (c < 0)
break;
switch (c) {
@@ -282,6 +307,20 @@ int main(int argc, char *argv[])
case 'W':
params.wait_for_monitor++;
break;
+#ifdef CONFIG_MATCH_IFACE
+ case 'M':
+ params.match_iface_count++;
+ iface = os_realloc_array(params.match_ifaces,
+ params.match_iface_count,
+ sizeof(struct wpa_interface));
+ if (!iface)
+ goto out;
+ params.match_ifaces = iface;
+ iface = &params.match_ifaces[params.match_iface_count -
+ 1];
+ os_memset(iface, 0, sizeof(*iface));
+ break;
+#endif /* CONFIG_MATCH_IFACE */
case 'N':
iface_count++;
iface = os_realloc_array(ifaces, iface_count,
@@ -328,6 +367,9 @@ int main(int argc, char *argv[])
ifaces[i].ctrl_interface == NULL) ||
ifaces[i].ifname == NULL) {
if (iface_count == 1 && (params.ctrl_interface ||
+#ifdef CONFIG_MATCH_IFACE
+ params.match_iface_count ||
+#endif /* CONFIG_MATCH_IFACE */
params.dbus_ctrl_interface))
break;
usage();
@@ -341,6 +383,11 @@ int main(int argc, char *argv[])
}
}
+#ifdef CONFIG_MATCH_IFACE
+ if (exitcode == 0)
+ exitcode = wpa_supplicant_init_match(global);
+#endif /* CONFIG_MATCH_IFACE */
+
if (exitcode == 0)
exitcode = wpa_supplicant_run(global);
@@ -351,6 +398,9 @@ int main(int argc, char *argv[])
out:
wpa_supplicant_fd_workaround(0);
os_free(ifaces);
+#ifdef CONFIG_MATCH_IFACE
+ os_free(params.match_ifaces);
+#endif /* CONFIG_MATCH_IFACE */
os_free(params.pid_file);
os_program_deinit();
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index 7925aa91..89b033bc 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -597,3 +597,16 @@ int wpas_mesh_add_interface(struct wpa_supplicant *wpa_s, char *ifname,
mesh_wpa_s->mesh_if_created = 1;
return 0;
}
+
+
+int wpas_mesh_peer_remove(struct wpa_supplicant *wpa_s, const u8 *addr)
+{
+ return mesh_mpm_close_peer(wpa_s, addr);
+}
+
+
+int wpas_mesh_peer_add(struct wpa_supplicant *wpa_s, const u8 *addr,
+ int duration)
+{
+ return mesh_mpm_connect_peer(wpa_s, addr, duration);
+}
diff --git a/wpa_supplicant/mesh.h b/wpa_supplicant/mesh.h
index 3cb7f1b1..7317083c 100644
--- a/wpa_supplicant/mesh.h
+++ b/wpa_supplicant/mesh.h
@@ -18,6 +18,9 @@ int wpas_mesh_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
char *end);
int wpas_mesh_add_interface(struct wpa_supplicant *wpa_s, char *ifname,
size_t len);
+int wpas_mesh_peer_remove(struct wpa_supplicant *wpa_s, const u8 *addr);
+int wpas_mesh_peer_add(struct wpa_supplicant *wpa_s, const u8 *addr,
+ int duration);
#ifdef CONFIG_MESH
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index 27be46cd..c014eaf8 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -14,6 +14,7 @@
#include "ap/hostapd.h"
#include "ap/sta_info.h"
#include "ap/ieee802_11.h"
+#include "ap/wpa_auth.h"
#include "wpa_supplicant_i.h"
#include "driver_i.h"
#include "mesh_mpm.h"
@@ -419,6 +420,7 @@ static void plink_timer(void *eloop_ctx, void *user_data)
struct sta_info *sta = user_data;
u16 reason = 0;
struct mesh_conf *conf = wpa_s->ifmsh->mconf;
+ struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
switch (sta->plink_state) {
case PLINK_OPEN_RCVD:
@@ -448,6 +450,13 @@ static void plink_timer(void *eloop_ctx, void *user_data)
break;
case PLINK_HOLDING:
/* holding timer */
+
+ if (sta->mesh_sae_pmksa_caching) {
+ wpa_printf(MSG_DEBUG, "MPM: Peer " MACSTR
+ " looks like it does not support mesh SAE PMKSA caching, so remove the cached entry for it",
+ MAC2STR(sta->addr));
+ wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
+ }
mesh_mpm_fsm_restart(wpa_s, sta);
break;
default:
@@ -472,8 +481,8 @@ mesh_mpm_plink_open(struct wpa_supplicant *wpa_s, struct sta_info *sta,
}
-int mesh_mpm_plink_close(struct hostapd_data *hapd,
- struct sta_info *sta, void *ctx)
+static int mesh_mpm_plink_close(struct hostapd_data *hapd, struct sta_info *sta,
+ void *ctx)
{
struct wpa_supplicant *wpa_s = ctx;
int reason = WLAN_REASON_MESH_PEERING_CANCELLED;
@@ -491,6 +500,85 @@ int mesh_mpm_plink_close(struct hostapd_data *hapd,
}
+int mesh_mpm_close_peer(struct wpa_supplicant *wpa_s, const u8 *addr)
+{
+ struct hostapd_data *hapd;
+ struct sta_info *sta;
+
+ if (!wpa_s->ifmsh) {
+ wpa_msg(wpa_s, MSG_INFO, "Mesh is not prepared yet");
+ return -1;
+ }
+
+ hapd = wpa_s->ifmsh->bss[0];
+ sta = ap_get_sta(hapd, addr);
+ if (!sta) {
+ wpa_msg(wpa_s, MSG_INFO, "No such mesh peer");
+ return -1;
+ }
+
+ return mesh_mpm_plink_close(hapd, sta, wpa_s) == 0 ? 0 : -1;
+}
+
+
+static void peer_add_timer(void *eloop_ctx, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
+
+ os_memset(hapd->mesh_required_peer, 0, ETH_ALEN);
+}
+
+
+int mesh_mpm_connect_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
+ int duration)
+{
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ struct hostapd_data *hapd;
+ struct sta_info *sta;
+ struct mesh_conf *conf;
+
+ if (!wpa_s->ifmsh) {
+ wpa_msg(wpa_s, MSG_INFO, "Mesh is not prepared yet");
+ return -1;
+ }
+
+ if (!ssid || !ssid->no_auto_peer) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "This command is available only with no_auto_peer mesh network");
+ return -1;
+ }
+
+ hapd = wpa_s->ifmsh->bss[0];
+ conf = wpa_s->ifmsh->mconf;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta) {
+ wpa_msg(wpa_s, MSG_INFO, "No such mesh peer");
+ return -1;
+ }
+
+ if ((PLINK_OPEN_SENT <= sta->plink_state &&
+ sta->plink_state <= PLINK_ESTAB) ||
+ (sta->sae && sta->sae->state > SAE_NOTHING)) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Specified peer is connecting/connected");
+ return -1;
+ }
+
+ if (conf->security == MESH_CONF_SEC_NONE) {
+ mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
+ } else {
+ mesh_rsn_auth_sae_sta(wpa_s, sta);
+ os_memcpy(hapd->mesh_required_peer, addr, ETH_ALEN);
+ eloop_register_timeout(duration == -1 ? 10 : duration, 0,
+ peer_add_timer, wpa_s, NULL);
+ }
+
+ return 0;
+}
+
+
void mesh_mpm_deinit(struct wpa_supplicant *wpa_s, struct hostapd_iface *ifmsh)
{
struct hostapd_data *hapd = ifmsh->bss[0];
@@ -500,6 +588,7 @@ void mesh_mpm_deinit(struct wpa_supplicant *wpa_s, struct hostapd_iface *ifmsh)
hapd->num_plinks = 0;
hostapd_free_stas(hapd);
+ eloop_cancel_timeout(peer_add_timer, wpa_s, NULL);
}
@@ -640,7 +729,9 @@ void wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
if (!sta)
return;
- if (ssid && ssid->no_auto_peer) {
+ if (ssid && ssid->no_auto_peer &&
+ (is_zero_ether_addr(data->mesh_required_peer) ||
+ os_memcmp(data->mesh_required_peer, addr, ETH_ALEN) != 0)) {
wpa_msg(wpa_s, MSG_INFO, "will not initiate new peer link with "
MACSTR " because of no_auto_peer", MAC2STR(addr));
if (data->mesh_pending_auth) {
@@ -720,7 +811,10 @@ static void mesh_mpm_plink_estab(struct wpa_supplicant *wpa_s,
hapd->num_plinks++;
sta->flags |= WLAN_STA_ASSOC;
+ sta->mesh_sae_pmksa_caching = 0;
+ eloop_cancel_timeout(peer_add_timer, wpa_s, NULL);
+ peer_add_timer(wpa_s, NULL);
eloop_cancel_timeout(plink_timer, wpa_s, sta);
/* Send ctrl event */
@@ -1000,7 +1094,8 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
* open mesh, then go ahead and add the peer before proceeding.
*/
if (!sta && action_field == PLINK_OPEN &&
- !(mconf->security & MESH_CONF_SEC_AMPE))
+ (!(mconf->security & MESH_CONF_SEC_AMPE) ||
+ wpa_auth_pmksa_get(hapd->wpa_auth, mgmt->sa)))
sta = mesh_mpm_add_peer(wpa_s, mgmt->sa, &elems);
if (!sta) {
diff --git a/wpa_supplicant/mesh_mpm.h b/wpa_supplicant/mesh_mpm.h
index 9af75635..5fc1e618 100644
--- a/wpa_supplicant/mesh_mpm.h
+++ b/wpa_supplicant/mesh_mpm.h
@@ -18,6 +18,9 @@ void mesh_mpm_free_sta(struct hostapd_data *hapd, struct sta_info *sta);
void wpa_mesh_set_plink_state(struct wpa_supplicant *wpa_s,
struct sta_info *sta,
enum mesh_plink_state state);
+int mesh_mpm_close_peer(struct wpa_supplicant *wpa_s, const u8 *addr);
+int mesh_mpm_connect_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
+ int duration);
#ifdef CONFIG_MESH
diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c
index 5d88274b..1994f3f5 100644
--- a/wpa_supplicant/mesh_rsn.c
+++ b/wpa_supplicant/mesh_rsn.c
@@ -27,12 +27,12 @@
#define MESH_AUTH_TIMEOUT 10
#define MESH_AUTH_RETRY 3
-#define MESH_AUTH_BLOCK_DURATION 3600
void mesh_auth_timer(void *eloop_ctx, void *user_data)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
struct sta_info *sta = user_data;
+ struct hostapd_data *hapd;
if (sta->sae->state != SAE_ACCEPTED) {
wpa_printf(MSG_DEBUG, "AUTH: Re-authenticate with " MACSTR
@@ -43,23 +43,20 @@ void mesh_auth_timer(void *eloop_ctx, void *user_data)
if (sta->sae_auth_retry < MESH_AUTH_RETRY) {
mesh_rsn_auth_sae_sta(wpa_s, sta);
} else {
+ hapd = wpa_s->ifmsh->bss[0];
+
if (sta->sae_auth_retry > MESH_AUTH_RETRY) {
- ap_free_sta(wpa_s->ifmsh->bss[0], sta);
+ ap_free_sta(hapd, sta);
return;
}
/* block the STA if exceeded the number of attempts */
wpa_mesh_set_plink_state(wpa_s, sta, PLINK_BLOCKED);
sta->sae->state = SAE_NOTHING;
- if (wpa_s->mesh_auth_block_duration <
- MESH_AUTH_BLOCK_DURATION)
- wpa_s->mesh_auth_block_duration += 60;
- eloop_register_timeout(wpa_s->mesh_auth_block_duration,
- 0, mesh_auth_timer, wpa_s, sta);
wpa_msg(wpa_s, MSG_INFO, MESH_SAE_AUTH_BLOCKED "addr="
MACSTR " duration=%d",
MAC2STR(sta->addr),
- wpa_s->mesh_auth_block_duration);
+ hapd->conf->ap_max_inactivity);
}
sta->sae_auth_retry++;
}
@@ -291,6 +288,7 @@ int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s,
{
struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
struct wpa_ssid *ssid = wpa_s->current_ssid;
+ struct rsn_pmksa_cache_entry *pmksa;
unsigned int rnd;
int ret;
@@ -306,6 +304,29 @@ int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s,
return -1;
}
+ pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr);
+ if (pmksa) {
+ if (!sta->wpa_sm)
+ sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
+ sta->addr, NULL);
+ if (!sta->wpa_sm) {
+ wpa_printf(MSG_ERROR,
+ "mesh: Failed to initialize RSN state machine");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "AUTH: Mesh PMKSA cache entry found for " MACSTR
+ " - try to use PMKSA caching instead of new SAE authentication",
+ MAC2STR(sta->addr));
+ wpa_auth_pmksa_set_to_sm(pmksa, sta->wpa_sm, hapd->wpa_auth,
+ sta->sae->pmkid, sta->sae->pmk);
+ sae_accept_sta(hapd, sta);
+ sta->mesh_sae_pmksa_caching = 1;
+ return 0;
+ }
+ sta->mesh_sae_pmksa_caching = 0;
+
if (mesh_rsn_build_sae_commit(wpa_s, ssid, sta))
return -1;
@@ -514,6 +535,17 @@ int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s, struct sta_info *sta,
const size_t aad_len[] = { ETH_ALEN, ETH_ALEN,
(elems->mic - 2) - cat };
+ if (!sta->sae) {
+ struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
+
+ if (!wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr)) {
+ wpa_printf(MSG_INFO,
+ "Mesh RSN: SAE is not prepared yet");
+ return -1;
+ }
+ mesh_rsn_auth_sae_sta(wpa_s, sta);
+ }
+
if (chosen_pmk && os_memcmp(chosen_pmk, sta->sae->pmkid, PMKID_LEN)) {
wpa_msg(wpa_s, MSG_DEBUG,
"Mesh RSN: Invalid PMKID (Chosen PMK did not match calculated PMKID)");
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index 325883dd..e7393638 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -13,6 +13,7 @@
#include "config.h"
#include "wpa_supplicant_i.h"
#include "wps_supplicant.h"
+#include "binder/binder.h"
#include "dbus/dbus_common.h"
#include "dbus/dbus_old.h"
#include "dbus/dbus_new.h"
@@ -34,6 +35,12 @@ int wpas_notify_supplicant_initialized(struct wpa_global *global)
}
#endif /* CONFIG_DBUS */
+#ifdef CONFIG_BINDER
+ global->binder = wpas_binder_init(global);
+ if (!global->binder)
+ return -1;
+#endif /* CONFIG_BINDER */
+
return 0;
}
@@ -44,6 +51,11 @@ void wpas_notify_supplicant_deinitialized(struct wpa_global *global)
if (global->dbus)
wpas_dbus_deinit(global->dbus);
#endif /* CONFIG_DBUS */
+
+#ifdef CONFIG_BINDER
+ if (global->binder)
+ wpas_binder_deinit(global->binder);
+#endif /* CONFIG_BINDER */
}
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 5ff758f6..b3108858 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -1134,7 +1134,8 @@ static int wpas_p2p_store_persistent_group(struct wpa_supplicant *wpa_s,
s->auth_alg = WPA_AUTH_ALG_OPEN;
s->key_mgmt = WPA_KEY_MGMT_PSK;
s->proto = WPA_PROTO_RSN;
- s->pairwise_cipher = WPA_CIPHER_CCMP;
+ s->pbss = ssid->pbss;
+ s->pairwise_cipher = ssid->pbss ? WPA_CIPHER_GCMP : WPA_CIPHER_CCMP;
s->export_keys = 1;
if (ssid->passphrase) {
os_free(s->passphrase);
@@ -6107,8 +6108,10 @@ static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s,
wpa_config_set_network_defaults(ssid);
ssid->temporary = 1;
ssid->proto = WPA_PROTO_RSN;
- ssid->pairwise_cipher = WPA_CIPHER_CCMP;
- ssid->group_cipher = WPA_CIPHER_CCMP;
+ ssid->pbss = params->pbss;
+ ssid->pairwise_cipher = params->pbss ? WPA_CIPHER_GCMP :
+ WPA_CIPHER_CCMP;
+ ssid->group_cipher = params->pbss ? WPA_CIPHER_GCMP : WPA_CIPHER_CCMP;
ssid->key_mgmt = WPA_KEY_MGMT_PSK;
ssid->ssid = os_malloc(params->ssid_len);
if (ssid->ssid == NULL) {
@@ -6328,6 +6331,8 @@ struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
cfg->cb_ctx = wpa_s;
cfg->ie_update = wpas_p2p_ie_update;
cfg->idle_update = wpas_p2p_idle_update;
+ cfg->ip_addr_alloc = WPA_GET_BE32(wpa_s->p2pdev->conf->ip_addr_start)
+ != 0;
group = p2p_group_init(wpa_s->global->p2p, cfg);
if (group == NULL)
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 3463dd92..7a528262 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -1895,7 +1895,7 @@ static void filter_scan_res(struct wpa_supplicant *wpa_s,
/*
* Noise floor values to use when we have signal strength
- * measurements, but no noise floor measurments. These values were
+ * measurements, but no noise floor measurements. These values were
* measured in an office environment with many APs.
*/
#define DEFAULT_NOISE_FLOOR_2GHZ (-89)
@@ -2334,10 +2334,18 @@ int wpas_start_pno(struct wpa_supplicant *wpa_s)
struct wpa_ssid *ssid;
struct wpa_driver_scan_params params;
struct sched_scan_plan scan_plan;
+ unsigned int max_sched_scan_ssids;
if (!wpa_s->sched_scan_supported)
return -1;
+ if (wpa_s->max_sched_scan_ssids > WPAS_MAX_SCAN_SSIDS)
+ max_sched_scan_ssids = WPAS_MAX_SCAN_SSIDS;
+ else
+ max_sched_scan_ssids = wpa_s->max_sched_scan_ssids;
+ if (max_sched_scan_ssids < 1)
+ return -1;
+
if (wpa_s->pno || wpa_s->pno_sched_pending)
return 0;
@@ -2381,10 +2389,10 @@ int wpas_start_pno(struct wpa_supplicant *wpa_s)
num_ssid++;
}
- if (num_ssid > WPAS_MAX_SCAN_SSIDS) {
+ if (num_ssid > max_sched_scan_ssids) {
wpa_printf(MSG_DEBUG, "PNO: Use only the first %u SSIDs from "
- "%u", WPAS_MAX_SCAN_SSIDS, (unsigned int) num_ssid);
- num_ssid = WPAS_MAX_SCAN_SSIDS;
+ "%u", max_sched_scan_ssids, (unsigned int) num_ssid);
+ num_ssid = max_sched_scan_ssids;
}
if (num_match_ssid > wpa_s->max_match_sets) {
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index 7d2a92fa..f77d51ae 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -546,6 +546,17 @@ compare_scan_neighbor_results(struct wpa_supplicant *wpa_s)
continue;
}
+ if (wpa_s->current_ssid &&
+ !wpa_scan_res_match(wpa_s, 0, target, wpa_s->current_ssid,
+ 1)) {
+ wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
+ " (pref %d) does not match the current network profile",
+ MAC2STR(nei->bssid),
+ nei->preference_present ? nei->preference :
+ -1);
+ continue;
+ }
+
if (wpa_is_bss_tmp_disallowed(wpa_s, target->bssid)) {
wpa_printf(MSG_DEBUG,
"MBO: Candidate BSS " MACSTR
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index eecb1dca..36a7a4eb 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -2042,6 +2042,20 @@ static int wpa_cli_cmd_mesh_group_remove(struct wpa_ctrl *ctrl, int argc,
return wpa_cli_cmd(ctrl, "MESH_GROUP_REMOVE", 1, argc, argv);
}
+
+static int wpa_cli_cmd_mesh_peer_remove(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "MESH_PEER_REMOVE", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_mesh_peer_add(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "MESH_PEER_ADD", 1, argc, argv);
+}
+
#endif /* CONFIG_MESH */
@@ -3210,6 +3224,12 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
{ "mesh_group_remove", wpa_cli_cmd_mesh_group_remove, NULL,
cli_cmd_flag_none,
"<ifname> = Remove mesh group interface" },
+ { "mesh_peer_remove", wpa_cli_cmd_mesh_peer_remove, NULL,
+ cli_cmd_flag_none,
+ "<addr> = Remove a mesh peer" },
+ { "mesh_peer_add", wpa_cli_cmd_mesh_peer_add, NULL,
+ cli_cmd_flag_none,
+ "<addr> [duration=<seconds>] = Add a mesh peer" },
#endif /* CONFIG_MESH */
#ifdef CONFIG_P2P
{ "p2p_find", wpa_cli_cmd_p2p_find, wpa_cli_complete_p2p_find,
diff --git a/wpa_supplicant/wpa_priv.c b/wpa_supplicant/wpa_priv.c
index 3f91cc16..511df4f1 100644
--- a/wpa_supplicant/wpa_priv.c
+++ b/wpa_supplicant/wpa_priv.c
@@ -29,6 +29,8 @@ struct wpa_priv_interface {
char *sock_name;
int fd;
+ void *ctx;
+
const struct wpa_driver_ops *driver;
void *drv_priv;
void *drv_global_priv;
@@ -40,6 +42,10 @@ struct wpa_priv_interface {
struct sockaddr_un l2_addr;
};
+struct wpa_priv_global {
+ struct wpa_priv_interface *interfaces;
+};
+
static void wpa_priv_cmd_register(struct wpa_priv_interface *iface,
struct sockaddr_un *from)
@@ -65,7 +71,8 @@ static void wpa_priv_cmd_register(struct wpa_priv_interface *iface,
if (iface->driver->init2) {
if (iface->driver->global_init) {
- iface->drv_global_priv = iface->driver->global_init();
+ iface->drv_global_priv =
+ iface->driver->global_init(iface->ctx);
if (!iface->drv_global_priv) {
wpa_printf(MSG_INFO,
"Failed to initialize driver global context");
@@ -638,7 +645,7 @@ static void wpa_priv_interface_deinit(struct wpa_priv_interface *iface)
static struct wpa_priv_interface *
-wpa_priv_interface_init(const char *dir, const char *params)
+wpa_priv_interface_init(void *ctx, const char *dir, const char *params)
{
struct wpa_priv_interface *iface;
char *pos;
@@ -654,6 +661,7 @@ wpa_priv_interface_init(const char *dir, const char *params)
if (iface == NULL)
return NULL;
iface->fd = -1;
+ iface->ctx = ctx;
len = pos - params;
iface->driver_name = dup_binstr(params, len);
@@ -1002,6 +1010,37 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
}
+void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event,
+ union wpa_event_data *data)
+{
+ struct wpa_priv_global *global = ctx;
+ struct wpa_priv_interface *iface;
+
+ if (event != EVENT_INTERFACE_STATUS)
+ return;
+
+ for (iface = global->interfaces; iface; iface = iface->next) {
+ if (os_strcmp(iface->ifname, data->interface_status.ifname) ==
+ 0)
+ break;
+ }
+ if (iface && iface->driver->get_ifindex) {
+ unsigned int ifindex;
+
+ ifindex = iface->driver->get_ifindex(iface->drv_priv);
+ if (ifindex != data->interface_status.ifindex) {
+ wpa_printf(MSG_DEBUG,
+ "%s: interface status ifindex %d mismatch (%d)",
+ iface->ifname, ifindex,
+ data->interface_status.ifindex);
+ return;
+ }
+ }
+ if (iface)
+ wpa_supplicant_event(iface, event, data);
+}
+
+
void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
const u8 *buf, size_t len)
{
@@ -1077,13 +1116,17 @@ int main(int argc, char *argv[])
char *pid_file = NULL;
int daemonize = 0;
char *ctrl_dir = "/var/run/wpa_priv";
- struct wpa_priv_interface *interfaces = NULL, *iface;
+ struct wpa_priv_global global;
+ struct wpa_priv_interface *iface;
if (os_program_init())
return -1;
wpa_priv_fd_workaround();
+ os_memset(&global, 0, sizeof(global));
+ global.interfaces = NULL;
+
for (;;) {
c = getopt(argc, argv, "Bc:dP:");
if (c < 0)
@@ -1121,11 +1164,11 @@ int main(int argc, char *argv[])
for (i = optind; i < argc; i++) {
wpa_printf(MSG_DEBUG, "Adding driver:interface %s", argv[i]);
- iface = wpa_priv_interface_init(ctrl_dir, argv[i]);
+ iface = wpa_priv_interface_init(&global, ctrl_dir, argv[i]);
if (iface == NULL)
goto out;
- iface->next = interfaces;
- interfaces = iface;
+ iface->next = global.interfaces;
+ global.interfaces = iface;
}
if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue())
@@ -1137,7 +1180,7 @@ int main(int argc, char *argv[])
ret = 0;
out:
- iface = interfaces;
+ iface = global.interfaces;
while (iface) {
struct wpa_priv_interface *prev = iface;
iface = iface->next;
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 136cb58e..51bb2457 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -11,6 +11,10 @@
*/
#include "includes.h"
+#ifdef CONFIG_MATCH_IFACE
+#include <net/if.h>
+#include <fnmatch.h>
+#endif /* CONFIG_MATCH_IFACE */
#include "common.h"
#include "crypto/random.h"
@@ -1642,9 +1646,11 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
wmm_ac_clear_saved_tspecs(wpa_s);
wpa_s->reassoc_same_bss = 0;
+ wpa_s->reassoc_same_ess = 0;
if (wpa_s->last_ssid == ssid) {
wpa_dbg(wpa_s, MSG_DEBUG, "Re-association to the same ESS");
+ wpa_s->reassoc_same_ess = 1;
if (wpa_s->current_bss && wpa_s->current_bss == bss) {
wmm_ac_save_tspecs(wpa_s);
wpa_s->reassoc_same_bss = 1;
@@ -2059,6 +2065,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
int wep_keys_set = 0;
int assoc_failed = 0;
struct wpa_ssid *old_ssid;
+ u8 prev_bssid[ETH_ALEN];
#ifdef CONFIG_HT_OVERRIDES
struct ieee80211_ht_capabilities htcaps;
struct ieee80211_ht_capabilities htcaps_mask;
@@ -2092,6 +2099,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
return;
}
+ os_memcpy(prev_bssid, wpa_s->bssid, ETH_ALEN);
os_memset(&params, 0, sizeof(params));
wpa_s->reassociate = 0;
wpa_s->eap_expected_failure = 0;
@@ -2532,6 +2540,10 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
}
#endif /* CONFIG_P2P */
+ if (wpa_s->reassoc_same_ess && !is_zero_ether_addr(prev_bssid) &&
+ wpa_s->current_ssid)
+ params.prev_bssid = prev_bssid;
+
ret = wpa_drv_associate(wpa_s, &params);
if (ret < 0) {
wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "
@@ -3143,7 +3155,7 @@ static int select_driver(struct wpa_supplicant *wpa_s, int i)
struct wpa_global *global = wpa_s->global;
if (wpa_drivers[i]->global_init && global->drv_priv[i] == NULL) {
- global->drv_priv[i] = wpa_drivers[i]->global_init();
+ global->drv_priv[i] = wpa_drivers[i]->global_init(global);
if (global->drv_priv[i] == NULL) {
wpa_printf(MSG_ERROR, "Failed to initialize driver "
"'%s'", wpa_drivers[i]->name);
@@ -4911,6 +4923,74 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
}
+#ifdef CONFIG_MATCH_IFACE
+
+/**
+ * wpa_supplicant_match_iface - Match an interface description to a name
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * @ifname: Name of the interface to match
+ * Returns: Pointer to the created interface description or %NULL on failure
+ */
+struct wpa_interface * wpa_supplicant_match_iface(struct wpa_global *global,
+ const char *ifname)
+{
+ int i;
+ struct wpa_interface *iface, *miface;
+
+ for (i = 0; i < global->params.match_iface_count; i++) {
+ miface = &global->params.match_ifaces[i];
+ if (!miface->ifname ||
+ fnmatch(miface->ifname, ifname, 0) == 0) {
+ iface = os_zalloc(sizeof(*iface));
+ if (!iface)
+ return NULL;
+ *iface = *miface;
+ iface->ifname = ifname;
+ return iface;
+ }
+ }
+
+ return NULL;
+}
+
+
+/**
+ * wpa_supplicant_match_existing - Match existing interfaces
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * Returns: 0 on success, -1 on failure
+ */
+static int wpa_supplicant_match_existing(struct wpa_global *global)
+{
+ struct if_nameindex *ifi, *ifp;
+ struct wpa_supplicant *wpa_s;
+ struct wpa_interface *iface;
+
+ ifp = if_nameindex();
+ if (!ifp) {
+ wpa_printf(MSG_ERROR, "if_nameindex: %s", strerror(errno));
+ return -1;
+ }
+
+ for (ifi = ifp; ifi->if_name; ifi++) {
+ wpa_s = wpa_supplicant_get_iface(global, ifi->if_name);
+ if (wpa_s)
+ continue;
+ iface = wpa_supplicant_match_iface(global, ifi->if_name);
+ if (iface) {
+ wpa_s = wpa_supplicant_add_iface(global, iface, NULL);
+ os_free(iface);
+ if (wpa_s)
+ wpa_s->matched = 1;
+ }
+ }
+
+ if_freenameindex(ifp);
+ return 0;
+}
+
+#endif /* CONFIG_MATCH_IFACE */
+
+
/**
* wpa_supplicant_add_iface - Add a new network interface
* @global: Pointer to global data from wpa_supplicant_init()
@@ -5212,6 +5292,18 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
if (params->override_ctrl_interface)
global->params.override_ctrl_interface =
os_strdup(params->override_ctrl_interface);
+#ifdef CONFIG_MATCH_IFACE
+ global->params.match_iface_count = params->match_iface_count;
+ if (params->match_iface_count) {
+ global->params.match_ifaces =
+ os_calloc(params->match_iface_count,
+ sizeof(struct wpa_interface));
+ os_memcpy(global->params.match_ifaces,
+ params->match_ifaces,
+ params->match_iface_count *
+ sizeof(struct wpa_interface));
+ }
+#endif /* CONFIG_MATCH_IFACE */
#ifdef CONFIG_P2P
if (params->conf_p2p_dev)
global->params.conf_p2p_dev =
@@ -5291,6 +5383,11 @@ int wpa_supplicant_run(struct wpa_global *global)
eloop_sock_requeue()))
return -1;
+#ifdef CONFIG_MATCH_IFACE
+ if (wpa_supplicant_match_existing(global))
+ return -1;
+#endif
+
if (global->params.wait_for_monitor) {
for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
if (wpa_s->ctrl_iface && !wpa_s->p2p_mgmt)
@@ -5359,6 +5456,9 @@ void wpa_supplicant_deinit(struct wpa_global *global)
os_free(global->params.ctrl_interface_group);
os_free(global->params.override_driver);
os_free(global->params.override_ctrl_interface);
+#ifdef CONFIG_MATCH_IFACE
+ os_free(global->params.match_ifaces);
+#endif /* CONFIG_MATCH_IFACE */
#ifdef CONFIG_P2P
os_free(global->params.conf_p2p_dev);
#endif /* CONFIG_P2P */
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 269bac0f..c4858917 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -44,6 +44,7 @@ struct wpa_driver_associate_params;
struct ctrl_iface_priv;
struct ctrl_iface_global_priv;
struct wpas_dbus_priv;
+struct wpas_binder_priv;
/**
* struct wpa_interface - Parameters for wpa_supplicant_add_iface()
@@ -228,6 +229,17 @@ struct wpa_params {
char *conf_p2p_dev;
#endif /* CONFIG_P2P */
+#ifdef CONFIG_MATCH_IFACE
+ /**
+ * match_ifaces - Interface descriptions to match
+ */
+ struct wpa_interface *match_ifaces;
+
+ /**
+ * match_iface_count - Number of defined matching interfaces
+ */
+ int match_iface_count;
+#endif /* CONFIG_MATCH_IFACE */
};
struct p2p_srv_bonjour {
@@ -253,6 +265,7 @@ struct wpa_global {
struct wpa_params params;
struct ctrl_iface_global_priv *ctrl_iface;
struct wpas_dbus_priv *dbus;
+ struct wpas_binder_priv *binder;
void **drv_priv;
size_t drv_count;
struct os_time suspend_time;
@@ -458,6 +471,9 @@ struct wpa_supplicant {
unsigned char own_addr[ETH_ALEN];
unsigned char perm_addr[ETH_ALEN];
char ifname[100];
+#ifdef CONFIG_MATCH_IFACE
+ int matched;
+#endif /* CONFIG_MATCH_IFACE */
#ifdef CONFIG_CTRL_IFACE_DBUS
char *dbus_path;
#endif /* CONFIG_CTRL_IFACE_DBUS */
@@ -468,6 +484,9 @@ struct wpa_supplicant {
char *preq_notify_peer;
#endif /* CONFIG_AP */
#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
+#ifdef CONFIG_CTRL_IFACE_BINDER
+ const void *binder_object_key;
+#endif /* CONFIG_CTRL_IFACE_BINDER */
char bridge_ifname[16];
char *confname;
@@ -480,7 +499,8 @@ struct wpa_supplicant {
u8 pending_bssid[ETH_ALEN]; /* If wpa_state == WPA_ASSOCIATING, this
* field contains the target BSSID. */
int reassociate; /* reassociation requested */
- int reassoc_same_bss; /* reassociating to the same bss */
+ unsigned int reassoc_same_bss:1; /* reassociating to the same BSS */
+ unsigned int reassoc_same_ess:1; /* reassociating to the same ESS */
int disconnected; /* all connections disabled; i.e., do no reassociate
* before this has been cleared */
struct wpa_ssid *current_ssid;
@@ -754,7 +774,6 @@ struct wpa_supplicant {
unsigned int mesh_if_created:1;
unsigned int mesh_ht_enabled:1;
unsigned int mesh_vht_enabled:1;
- int mesh_auth_block_duration; /* sec */
#endif /* CONFIG_MESH */
unsigned int off_channel_freq;
@@ -1109,6 +1128,8 @@ void free_hw_features(struct wpa_supplicant *wpa_s);
void wpa_show_license(void);
+struct wpa_interface * wpa_supplicant_match_iface(struct wpa_global *global,
+ const char *ifname);
struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
struct wpa_interface *iface,
struct wpa_supplicant *parent);