Merge "Cumulative patch from commit ed0a4ddc22526361a138c6b145561fcaac24e2a5"
am: 21c780dfa7
Change-Id: I7aba849186bec09237c876060340e7973279444e
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 7795015..832ff55 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -685,12 +685,12 @@
val |= WPA_KEY_MGMT_PSK;
else if (os_strcmp(start, "WPA-EAP") == 0)
val |= WPA_KEY_MGMT_IEEE8021X;
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
else if (os_strcmp(start, "FT-PSK") == 0)
val |= WPA_KEY_MGMT_FT_PSK;
else if (os_strcmp(start, "FT-EAP") == 0)
val |= WPA_KEY_MGMT_FT_IEEE8021X;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_IEEE80211W
else if (os_strcmp(start, "WPA-PSK-SHA256") == 0)
val |= WPA_KEY_MGMT_PSK_SHA256;
@@ -716,12 +716,12 @@
val |= WPA_KEY_MGMT_FILS_SHA256;
else if (os_strcmp(start, "FILS-SHA384") == 0)
val |= WPA_KEY_MGMT_FILS_SHA384;
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
else if (os_strcmp(start, "FT-FILS-SHA256") == 0)
val |= WPA_KEY_MGMT_FT_FILS_SHA256;
else if (os_strcmp(start, "FT-FILS-SHA384") == 0)
val |= WPA_KEY_MGMT_FT_FILS_SHA384;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#endif /* CONFIG_FILS */
else {
wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
@@ -991,7 +991,7 @@
}
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
static int add_r0kh(struct hostapd_bss_config *bss, char *value)
{
struct ft_remote_r0kh *r0kh;
@@ -1081,7 +1081,7 @@
return 0;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_IEEE80211N
@@ -2534,7 +2534,7 @@
} else if (os_strcmp(buf, "peerkey") == 0) {
bss->peerkey = atoi(pos);
#endif /* CONFIG_PEERKEY */
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
} else if (os_strcmp(buf, "mobility_domain") == 0) {
if (os_strlen(pos) != 2 * MOBILITY_DOMAIN_ID_LEN ||
hexstr2bin(pos, bss->mobility_domain,
@@ -2574,7 +2574,7 @@
bss->ft_over_ds = atoi(pos);
} else if (os_strcmp(buf, "ft_psk_generate_local") == 0) {
bss->ft_psk_generate_local = atoi(pos);
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifndef CONFIG_NO_CTRL_IFACE
} else if (os_strcmp(buf, "ctrl_interface") == 0) {
os_free(bss->ctrl_interface);
@@ -2756,6 +2756,40 @@
line);
return 1;
}
+ } else if (os_strcmp(buf, "beacon_rate") == 0) {
+ int val;
+
+ if (os_strncmp(pos, "ht:", 3) == 0) {
+ val = atoi(pos + 3);
+ if (val < 0 || val > 31) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid beacon_rate HT-MCS %d",
+ line, val);
+ return 1;
+ }
+ conf->rate_type = BEACON_RATE_HT;
+ conf->beacon_rate = val;
+ } else if (os_strncmp(pos, "vht:", 4) == 0) {
+ val = atoi(pos + 4);
+ if (val < 0 || val > 9) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid beacon_rate VHT-MCS %d",
+ line, val);
+ return 1;
+ }
+ conf->rate_type = BEACON_RATE_VHT;
+ conf->beacon_rate = val;
+ } else {
+ val = atoi(pos);
+ if (val < 10 || val > 10000) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid legacy beacon_rate %d",
+ line, val);
+ return 1;
+ }
+ conf->rate_type = BEACON_RATE_LEGACY;
+ conf->beacon_rate = val;
+ }
} else if (os_strcmp(buf, "preamble") == 0) {
if (atoi(pos))
conf->preamble = SHORT_PREAMBLE;
@@ -3526,6 +3560,8 @@
}
bss->fils_cache_id_set = 1;
#endif /* CONFIG_FILS */
+ } else if (os_strcmp(buf, "multicast_to_unicast") == 0) {
+ bss->multicast_to_unicast = atoi(pos);
} else {
wpa_printf(MSG_ERROR,
"Line %d: unknown configuration item '%s'",
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 0d86b4a..b9d9411 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -1096,7 +1096,7 @@
return pos - buf;
pos += ret;
}
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
ret = os_snprintf(pos, end - pos, "FT-PSK ");
if (os_snprintf_error(end - pos, ret))
@@ -1131,7 +1131,7 @@
pos += ret;
}
#endif /* CONFIG_FILS */
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_IEEE80211W
if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
ret = os_snprintf(pos, end - pos, "WPA-PSK-SHA256 ");
@@ -1562,6 +1562,76 @@
}
+static int hostapd_ctrl_iface_mgmt_rx_process(struct hostapd_data *hapd,
+ char *cmd)
+{
+ char *pos, *param;
+ size_t len;
+ u8 *buf;
+ int freq = 0, datarate = 0, ssi_signal = 0;
+ union wpa_event_data event;
+
+ if (!hapd->ext_mgmt_frame_handling)
+ return -1;
+
+ /* freq=<MHz> datarate=<val> ssi_signal=<val> frame=<frame hexdump> */
+
+ wpa_printf(MSG_DEBUG, "External MGMT RX process: %s", cmd);
+
+ pos = cmd;
+ param = os_strstr(pos, "freq=");
+ if (param) {
+ param += 5;
+ freq = atoi(param);
+ }
+
+ param = os_strstr(pos, " datarate=");
+ if (param) {
+ param += 10;
+ datarate = atoi(param);
+ }
+
+ param = os_strstr(pos, " ssi_signal=");
+ if (param) {
+ param += 12;
+ ssi_signal = atoi(param);
+ }
+
+ param = os_strstr(pos, " frame=");
+ if (param == NULL)
+ return -1;
+ param += 7;
+
+ len = os_strlen(param);
+ if (len & 1)
+ return -1;
+ len /= 2;
+
+ buf = os_malloc(len);
+ if (buf == NULL)
+ return -1;
+
+ if (hexstr2bin(param, buf, len) < 0) {
+ os_free(buf);
+ return -1;
+ }
+
+ os_memset(&event, 0, sizeof(event));
+ event.rx_mgmt.freq = freq;
+ event.rx_mgmt.frame = buf;
+ event.rx_mgmt.frame_len = len;
+ event.rx_mgmt.ssi_signal = ssi_signal;
+ event.rx_mgmt.datarate = datarate;
+ hapd->ext_mgmt_frame_handling = 0;
+ wpa_supplicant_event(hapd, EVENT_RX_MGMT, &event);
+ hapd->ext_mgmt_frame_handling = 1;
+
+ os_free(buf);
+
+ return 0;
+}
+
+
static int hostapd_ctrl_iface_eapol_rx(struct hostapd_data *hapd, char *cmd)
{
char *pos;
@@ -2517,6 +2587,9 @@
} else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) {
if (hostapd_ctrl_iface_mgmt_tx(hapd, buf + 8))
reply_len = -1;
+ } else if (os_strncmp(buf, "MGMT_RX_PROCESS ", 16) == 0) {
+ if (hostapd_ctrl_iface_mgmt_rx_process(hapd, buf + 16) < 0)
+ reply_len = -1;
} else if (os_strncmp(buf, "EAPOL_RX ", 9) == 0) {
if (hostapd_ctrl_iface_eapol_rx(hapd, buf + 9) < 0)
reply_len = -1;
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 54c8b95..1fd4fcc 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -227,6 +227,19 @@
#basic_rates=10 20 55 110
#basic_rates=60 120 240
+# Beacon frame TX rate configuration
+# This sets the TX rate that is used to transmit Beacon frames. If this item is
+# not included, the driver default rate (likely lowest rate) is used.
+# Legacy (CCK/OFDM rates):
+# beacon_rate=<legacy rate in 100 kbps>
+# HT:
+# beacon_rate=ht:<HT MCS>
+# VHT:
+# beacon_rate=vht:<VHT MCS>
+#
+# For example, beacon_rate=10 for 1 Mbps or beacon_rate=60 for 6 Mbps (OFDM).
+#beacon_rate=10
+
# Short Preamble
# This parameter can be used to enable optional use of short preamble for
# frames sent at 2 Mbps, 5.5 Mbps, and 11 Mbps to improve network performance.
@@ -482,6 +495,22 @@
# <station count>:<channel utilization>:<available admission capacity>
#bss_load_test=12:80:20000
+# Multicast to unicast conversion
+# Request that the AP will do multicast-to-unicast conversion for ARP, IPv4, and
+# IPv6 frames (possibly within 802.1Q). If enabled, such frames are to be sent
+# to each station separately, with the DA replaced by their own MAC address
+# rather than the group address.
+#
+# Note that this may break certain expectations of the receiver, such as the
+# ability to drop unicast IP packets received within multicast L2 frames, or the
+# ability to not send ICMP destination unreachable messages for packets received
+# in L2 multicast (which is required, but the receiver can't tell the difference
+# if this new option is enabled).
+#
+# This also doesn't implement the 802.11 DMS (directed multicast service).
+#
+#multicast_to_unicast=0
+
##### IEEE 802.11n related configuration ######################################
# ieee80211n: Whether IEEE 802.11n (HT) is enabled
diff --git a/hostapd/main.c b/hostapd/main.c
index 2c8dbd3..bcc47a4 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -480,7 +480,7 @@
" -f log output to debug file instead of stdout\n"
#endif /* CONFIG_DEBUG_FILE */
#ifdef CONFIG_DEBUG_LINUX_TRACING
- " -T = record to Linux tracing in addition to logging\n"
+ " -T record to Linux tracing in addition to logging\n"
" (records all messages regardless of debug verbosity)\n"
#endif /* CONFIG_DEBUG_LINUX_TRACING */
" -i list of interface names to use\n"
@@ -549,14 +549,14 @@
static int hostapd_get_interface_names(char ***if_names,
size_t *if_names_size,
- char *optarg)
+ char *arg)
{
char *if_name, *tmp, **nnames;
size_t i;
- if (!optarg)
+ if (!arg)
return -1;
- if_name = strtok_r(optarg, ",", &tmp);
+ if_name = strtok_r(arg, ",", &tmp);
while (if_name) {
nnames = os_realloc_array(*if_names, 1 + *if_names_size,
diff --git a/src/ap/Makefile b/src/ap/Makefile
index 3b01e63..1c65bd6 100644
--- a/src/ap/Makefile
+++ b/src/ap/Makefile
@@ -12,10 +12,12 @@
CFLAGS += -DNEED_AP_MLME
CFLAGS += -DCONFIG_HS20
CFLAGS += -DCONFIG_INTERWORKING
+CFLAGS += -DCONFIG_IEEE80211R
CFLAGS += -DCONFIG_IEEE80211R_AP
CFLAGS += -DCONFIG_IEEE80211W
CFLAGS += -DCONFIG_WPS
CFLAGS += -DCONFIG_PROXYARP
+CFLAGS += -DCONFIG_IPV6
CFLAGS += -DCONFIG_IAPP
LIB_OBJS= \
@@ -43,14 +45,18 @@
ieee802_11_shared.o \
ieee802_11_vht.o \
ieee802_1x.o \
+ neighbor_db.o \
ndisc_snoop.o \
p2p_hostapd.o \
peerkey_auth.o \
pmksa_cache_auth.o \
preauth_auth.o \
+ rrm.o \
sta_info.o \
tkip_countermeasures.o \
utils.o \
+ vlan.o \
+ vlan_ifconfig.o \
vlan_init.o \
wmm.o \
wnm_ap.o \
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index cace34c..7d8f283 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -601,6 +601,8 @@
u8 fils_cache_id[FILS_CACHE_ID_LEN];
int fils_cache_id_set;
#endif /* CONFIG_FILS */
+
+ int multicast_to_unicast;
};
@@ -626,6 +628,8 @@
int *supported_rates;
int *basic_rates;
+ unsigned int beacon_rate;
+ enum beacon_rate_type rate_type;
const struct wpa_driver_ops *driver;
char *driver_params;
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 811bede..3788a97 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -1223,6 +1223,8 @@
params->dtim_period = hapd->conf->dtim_period;
params->beacon_int = hapd->iconf->beacon_int;
params->basic_rates = hapd->iface->basic_rates;
+ params->beacon_rate = hapd->iconf->beacon_rate;
+ params->rate_type = hapd->iconf->rate_type;
params->ssid = hapd->conf->ssid.ssid;
params->ssid_len = hapd->conf->ssid.ssid_len;
if ((hapd->conf->wpa & (WPA_PROTO_WPA | WPA_PROTO_RSN)) ==
@@ -1286,6 +1288,7 @@
params->osen = 1;
}
#endif /* CONFIG_HS20 */
+ params->multicast_to_unicast = hapd->conf->multicast_to_unicast;
params->pbss = hapd->conf->pbss;
return 0;
}
diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
index 6ce178d..b4306c6 100644
--- a/src/ap/gas_serv.c
+++ b/src/ap/gas_serv.c
@@ -255,6 +255,8 @@
wpabuf_put_le16(buf, ANQP_DOMAIN_NAME);
if (get_anqp_elem(hapd, ANQP_EMERGENCY_ALERT_URI))
wpabuf_put_le16(buf, ANQP_EMERGENCY_ALERT_URI);
+ if (get_anqp_elem(hapd, ANQP_TDLS_CAPABILITY))
+ wpabuf_put_le16(buf, ANQP_TDLS_CAPABILITY);
if (get_anqp_elem(hapd, ANQP_EMERGENCY_NAI))
wpabuf_put_le16(buf, ANQP_EMERGENCY_NAI);
if (get_anqp_elem(hapd, ANQP_NEIGHBOR_REPORT))
@@ -269,6 +271,10 @@
wpabuf_put_le16(buf, ANQP_ADVICE_OF_CHARGE);
if (get_anqp_elem(hapd, ANQP_LOCAL_CONTENT))
wpabuf_put_le16(buf, ANQP_LOCAL_CONTENT);
+ for (id = 280; id < 300; id++) {
+ if (get_anqp_elem(hapd, id))
+ wpabuf_put_le16(buf, id);
+ }
#ifdef CONFIG_HS20
anqp_add_hs_capab_list(hapd, buf);
#endif /* CONFIG_HS20 */
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 21a5408..7c40379 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -2832,7 +2832,16 @@
} else
wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm);
- if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
+ if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED) {
+ if (eloop_cancel_timeout(ap_handle_timer, hapd, sta) > 0) {
+ wpa_printf(MSG_DEBUG,
+ "%s: %s: canceled wired ap_handle_timer timeout for "
+ MACSTR,
+ hapd->conf->iface, __func__,
+ MAC2STR(sta->addr));
+ }
+ } else if (!(hapd->iface->drv_flags &
+ WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
wpa_printf(MSG_DEBUG,
"%s: %s: reschedule ap_handle_timer timeout for "
MACSTR " (%d seconds - ap_max_inactivity)",
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 0b3d2f2..1cecc80 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -1580,8 +1580,15 @@
*
* In mesh mode, the station was already added to the driver when the
* NEW_PEER_CANDIDATE event is received.
+ *
+ * If PMF was negotiated for the existing association, skip this to
+ * avoid dropping the STA entry and the associated keys. This is needed
+ * to allow the original connection work until the attempt can complete
+ * (re)association, so that unprotected Authentication frame cannot be
+ * used to bypass PMF protection.
*/
if (FULL_AP_CLIENT_STATE_SUPP(hapd->iface->drv_flags) &&
+ (!(sta->flags & WLAN_STA_MFP) || !ap_sta_is_authorized(sta)) &&
!(hapd->conf->mesh & MESH_ENABLED) &&
!(sta->added_unassoc)) {
/*
@@ -3225,16 +3232,6 @@
sta->sa_query_timed_out = 0;
#endif /* CONFIG_IEEE80211W */
- if (sta->flags & WLAN_STA_WDS) {
- int ret;
- char ifname_wds[IFNAMSIZ + 1];
-
- ret = hostapd_set_wds_sta(hapd, ifname_wds, sta->addr,
- sta->aid, 1);
- if (!ret)
- hostapd_set_wds_encryption(hapd, sta, ifname_wds);
- }
-
if (sta->eapol_sm == NULL) {
/*
* This STA does not use RADIUS server for EAP authentication,
@@ -3251,6 +3248,19 @@
hostapd_set_sta_flags(hapd, sta);
+ if (sta->flags & WLAN_STA_WDS) {
+ int ret;
+ char ifname_wds[IFNAMSIZ + 1];
+
+ wpa_printf(MSG_DEBUG, "Reenable 4-address WDS mode for STA "
+ MACSTR " (aid %u)",
+ MAC2STR(sta->addr), sta->aid);
+ ret = hostapd_set_wds_sta(hapd, ifname_wds, sta->addr,
+ sta->aid, 1);
+ if (!ret)
+ hostapd_set_wds_encryption(hapd, sta, ifname_wds);
+ }
+
if (sta->auth_alg == WLAN_AUTH_FT)
wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
else
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index 1df3009..c770d62 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -716,6 +716,10 @@
"MDIE", mdie, MOBILITY_DOMAIN_ID_LEN);
return WPA_INVALID_MDIE;
}
+ } else if (mdie != NULL) {
+ wpa_printf(MSG_DEBUG,
+ "RSN: Trying to use non-FT AKM suite, but MDIE included");
+ return WPA_INVALID_AKMP;
}
#endif /* CONFIG_IEEE80211R_AP */
diff --git a/src/common/defs.h b/src/common/defs.h
index 4dd5690..672bdf6 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -370,4 +370,10 @@
BAND_60_GHZ = BIT(2),
};
+enum beacon_rate_type {
+ BEACON_RATE_LEGACY,
+ BEACON_RATE_HT,
+ BEACON_RATE_VHT
+};
+
#endif /* DEFS_H */
diff --git a/src/common/ieee802_1x_defs.h b/src/common/ieee802_1x_defs.h
index a0c1d1b..280c439 100644
--- a/src/common/ieee802_1x_defs.h
+++ b/src/common/ieee802_1x_defs.h
@@ -25,6 +25,12 @@
* Disabled MACsec - do not secure sessions.
*/
DO_NOT_SECURE,
+
+ /**
+ * Should secure sessions, and try to use encryption.
+ * Like @SHOULD_SECURE, this follows the key server's decision.
+ */
+ SHOULD_ENCRYPT,
};
diff --git a/src/common/privsep_commands.h b/src/common/privsep_commands.h
index f017f08..0f47518 100644
--- a/src/common/privsep_commands.h
+++ b/src/common/privsep_commands.h
@@ -9,6 +9,7 @@
#ifndef PRIVSEP_COMMANDS_H
#define PRIVSEP_COMMANDS_H
+#include "drivers/driver.h"
#include "common/ieee802_11_defs.h"
enum privsep_cmd {
@@ -29,8 +30,17 @@
PRIVSEP_CMD_AUTHENTICATE,
};
-struct privsep_cmd_authenticate
-{
+#define PRIVSEP_MAX_SCAN_FREQS 50
+
+struct privsep_cmd_scan {
+ unsigned int num_ssids;
+ u8 ssids[WPAS_MAX_SCAN_SSIDS][32];
+ u8 ssid_lens[WPAS_MAX_SCAN_SSIDS];
+ unsigned int num_freqs;
+ u16 freqs[PRIVSEP_MAX_SCAN_FREQS];
+};
+
+struct privsep_cmd_authenticate {
int freq;
u8 bssid[ETH_ALEN];
u8 ssid[SSID_MAX_LEN];
@@ -47,8 +57,7 @@
/* followed by auth_data_len bytes of auth_data */
};
-struct privsep_cmd_associate
-{
+struct privsep_cmd_associate {
u8 bssid[ETH_ALEN];
u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
@@ -64,8 +73,7 @@
/* followed by wpa_ie_len bytes of wpa_ie */
};
-struct privsep_cmd_set_key
-{
+struct privsep_cmd_set_key {
int alg;
u8 addr[ETH_ALEN];
int key_idx;
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index fc391e0..2ce2a89 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -232,6 +232,11 @@
* @QCA_NL80211_VENDOR_SUBCMD_CONFIGURE_TDLS: Configure the TDLS behavior
* in the host driver. The different TDLS configurations are defined
* by the attributes in enum qca_wlan_vendor_attr_tdls_configuration.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_ABORT_SCAN: Abort an ongoing vendor scan that was
+ * started with QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN. This command
+ * carries the scan cookie of the corresponding scan request. The scan
+ * cookie is represented by QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE.
*/
enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
@@ -338,6 +343,8 @@
QCA_NL80211_VENDOR_SUBCMD_DMG_RF_GET_SELECTED_SECTOR = 141,
QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SELECTED_SECTOR = 142,
QCA_NL80211_VENDOR_SUBCMD_CONFIGURE_TDLS = 143,
+ /* 144 - reserved for QCA */
+ QCA_NL80211_VENDOR_SUBCMD_ABORT_SCAN = 145,
};
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 9a6db90..212f16c 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -458,6 +458,20 @@
*/
const u8 *bssid;
+ /**
+ * scan_cookie - Unique identification representing the scan request
+ *
+ * This scan_cookie carries a unique identification representing the
+ * scan request if the host driver/kernel supports concurrent scan
+ * requests. This cookie is returned from the corresponding driver
+ * interface.
+ *
+ * Note: Unlike other parameters in this structure, scan_cookie is used
+ * only to return information instead of setting parameters for the
+ * scan.
+ */
+ u64 scan_cookie;
+
/*
* NOTE: Whenever adding new parameters here, please make sure
* wpa_scan_clone_params() and wpa_scan_free_params() get updated with
@@ -965,6 +979,22 @@
int *basic_rates;
/**
+ * beacon_rate: Beacon frame data rate
+ *
+ * This parameter can be used to set a specific Beacon frame data rate
+ * for the BSS. The interpretation of this value depends on the
+ * rate_type (legacy: in 100 kbps units, HT: HT-MCS, VHT: VHT-MCS). If
+ * beacon_rate == 0 and rate_type == 0 (BEACON_RATE_LEGACY), the default
+ * Beacon frame data rate is used.
+ */
+ unsigned int beacon_rate;
+
+ /**
+ * beacon_rate_type: Beacon data rate type (legacy/HT/VHT)
+ */
+ enum beacon_rate_type rate_type;
+
+ /**
* proberesp - Probe Response template
*
* This is used by drivers that reply to Probe Requests internally in
@@ -1140,6 +1170,27 @@
* infrastructure BSS. Valid only for DMG network.
*/
int pbss;
+
+ /**
+ * multicast_to_unicast - Whether to use multicast_to_unicast
+ *
+ * If this is non-zero, the AP is requested to perform multicast to
+ * unicast conversion for ARP, IPv4, and IPv6 frames (possibly within
+ * 802.1Q). If enabled, such frames are to be sent to each station
+ * separately, with the DA replaced by their own MAC address rather
+ * than the group address.
+ *
+ * Note that this may break certain expectations of the receiver, such
+ * as the ability to drop unicast IP packets received within multicast
+ * L2 frames, or the ability to not send ICMP destination unreachable
+ * messages for packets received in L2 multicast (which is required,
+ * but the receiver can't tell the difference if this new option is
+ * enabled.)
+ *
+ * This also doesn't implement the 802.11 DMS (directed multicast
+ * service).
+ */
+ int multicast_to_unicast;
};
struct wpa_driver_mesh_bss_params {
@@ -1313,6 +1364,12 @@
#define WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD 0x0000020000000000ULL
/** Driver supports FILS */
#define WPA_DRIVER_FLAGS_SUPPORT_FILS 0x0000040000000000ULL
+/** Driver supports Beacon frame TX rate configuration (legacy rates) */
+#define WPA_DRIVER_FLAGS_BEACON_RATE_LEGACY 0x0000080000000000ULL
+/** Driver supports Beacon frame TX rate configuration (HT rates) */
+#define WPA_DRIVER_FLAGS_BEACON_RATE_HT 0x0000100000000000ULL
+/** Driver supports Beacon frame TX rate configuration (VHT rates) */
+#define WPA_DRIVER_FLAGS_BEACON_RATE_VHT 0x0000200000000000ULL
u64 flags;
#define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
@@ -3339,6 +3396,15 @@
int (*enable_protect_frames)(void *priv, Boolean enabled);
/**
+ * enable_encrypt - Set encryption status
+ * @priv: Private driver interface data
+ * @enabled: TRUE = encrypt outgoing traffic
+ * FALSE = integrity-only protection on outgoing traffic
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+ int (*enable_encrypt)(void *priv, Boolean enabled);
+
+ /**
* set_replay_protect - Set replay protect status and window size
* @priv: Private driver interface data
* @enabled: TRUE = replay protect enabled
@@ -3564,9 +3630,12 @@
/**
* abort_scan - Request the driver to abort an ongoing scan
* @priv: Private driver interface data
+ * @scan_cookie: Cookie identifying the scan request. This is used only
+ * when the vendor interface QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN
+ * was used to trigger scan. Otherwise, 0 is used.
* Returns 0 on success, -1 on failure
*/
- int (*abort_scan)(void *priv);
+ int (*abort_scan)(void *priv, u64 scan_cookie);
/**
* configure_data_frame_filters - Request to configure frame filters
@@ -5002,6 +5071,10 @@
/* driver_macsec_qca.c */
extern const struct wpa_driver_ops wpa_driver_macsec_qca_ops;
#endif /* CONFIG_DRIVER_MACSEC_QCA */
+#ifdef CONFIG_DRIVER_MACSEC_LINUX
+/* driver_macsec_linux.c */
+extern const struct wpa_driver_ops wpa_driver_macsec_linux_ops;
+#endif /* CONFIG_DRIVER_MACSEC_LINUX */
#ifdef CONFIG_DRIVER_ROBOSWITCH
/* driver_roboswitch.c */
extern const struct wpa_driver_ops wpa_driver_roboswitch_ops;
diff --git a/src/drivers/driver_macsec_linux.c b/src/drivers/driver_macsec_linux.c
new file mode 100644
index 0000000..5dab77a
--- /dev/null
+++ b/src/drivers/driver_macsec_linux.c
@@ -0,0 +1,1265 @@
+/*
+ * Driver interaction with Linux MACsec kernel module
+ * Copyright (c) 2016, Sabrina Dubroca <sd@queasysnail.net> and Red Hat, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <netpacket/packet.h>
+#include <net/if_arp.h>
+#include <net/if.h>
+#include <netlink/netlink.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/route/link.h>
+#include <netlink/route/link/macsec.h>
+#include <linux/if_macsec.h>
+#include <inttypes.h>
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "pae/ieee802_1x_kay.h"
+#include "driver.h"
+#include "driver_wired_common.h"
+
+#define DRV_PREFIX "macsec_linux: "
+
+#define UNUSED_SCI 0xffffffffffffffff
+
+struct cb_arg {
+ struct macsec_drv_data *drv;
+ u32 *pn;
+ int ifindex;
+ u8 txsa;
+ u8 rxsa;
+ u64 rxsci;
+};
+
+struct macsec_genl_ctx {
+ struct nl_sock *sk;
+ int macsec_genl_id;
+ struct cb_arg cb_arg;
+};
+
+struct macsec_drv_data {
+ struct driver_wired_common_data common;
+ struct rtnl_link *link;
+ struct nl_cache *link_cache;
+ struct nl_sock *sk;
+ struct macsec_genl_ctx ctx;
+
+ struct netlink_data *netlink;
+ struct nl_handle *nl;
+ char ifname[IFNAMSIZ + 1];
+ int ifi;
+ int parent_ifi;
+
+ Boolean created_link;
+
+ Boolean controlled_port_enabled;
+ Boolean controlled_port_enabled_set;
+
+ Boolean protect_frames;
+ Boolean protect_frames_set;
+
+ Boolean encrypt;
+ Boolean encrypt_set;
+
+ Boolean replay_protect;
+ Boolean replay_protect_set;
+
+ u32 replay_window;
+
+ u8 encoding_sa;
+ Boolean encoding_sa_set;
+};
+
+
+static int dump_callback(struct nl_msg *msg, void *argp);
+
+
+static struct nl_msg * msg_prepare(enum macsec_nl_commands cmd,
+ const struct macsec_genl_ctx *ctx,
+ unsigned int ifindex)
+{
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "failed to alloc message");
+ return NULL;
+ }
+
+ if (!genlmsg_put(msg, 0, 0, ctx->macsec_genl_id, 0, 0, cmd, 0)) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "failed to put header");
+ goto nla_put_failure;
+ }
+
+ NLA_PUT_U32(msg, MACSEC_ATTR_IFINDEX, ifindex);
+
+ return msg;
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return NULL;
+}
+
+
+static int nla_put_rxsc_config(struct nl_msg *msg, u64 sci)
+{
+ struct nlattr *nest = nla_nest_start(msg, MACSEC_ATTR_RXSC_CONFIG);
+
+ if (!nest)
+ return -1;
+
+ NLA_PUT_U64(msg, MACSEC_RXSC_ATTR_SCI, sci);
+
+ nla_nest_end(msg, nest);
+
+ return 0;
+
+nla_put_failure:
+ return -1;
+}
+
+
+static int init_genl_ctx(struct macsec_drv_data *drv)
+{
+ struct macsec_genl_ctx *ctx = &drv->ctx;
+
+ ctx->sk = nl_socket_alloc();
+ if (!ctx->sk) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "failed to alloc genl socket");
+ return -1;
+ }
+
+ if (genl_connect(ctx->sk) < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "connection to genl socket failed");
+ goto out_free;
+ }
+
+ ctx->macsec_genl_id = genl_ctrl_resolve(ctx->sk, "macsec");
+ if (ctx->macsec_genl_id < 0) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "genl resolve failed");
+ goto out_free;
+ }
+
+ memset(&ctx->cb_arg, 0, sizeof(ctx->cb_arg));
+ ctx->cb_arg.drv = drv;
+
+ nl_socket_modify_cb(ctx->sk, NL_CB_VALID, NL_CB_CUSTOM, dump_callback,
+ &ctx->cb_arg);
+
+ return 0;
+
+out_free:
+ nl_socket_free(ctx->sk);
+ ctx->sk = NULL;
+ return -1;
+}
+
+
+static int try_commit(struct macsec_drv_data *drv)
+{
+ int err;
+
+ if (!drv->link)
+ return 0;
+
+ if (drv->controlled_port_enabled_set) {
+ struct rtnl_link *change = rtnl_link_alloc();
+
+ if (!change)
+ return -1;
+
+ rtnl_link_set_name(change, drv->ifname);
+
+ if (drv->controlled_port_enabled)
+ rtnl_link_set_flags(change, IFF_UP);
+ else
+ rtnl_link_unset_flags(change, IFF_UP);
+
+ err = rtnl_link_change(drv->sk, change, change, 0);
+ if (err < 0)
+ return err;
+
+ rtnl_link_put(change);
+
+ drv->controlled_port_enabled_set = FALSE;
+ }
+
+ if (drv->protect_frames_set)
+ rtnl_link_macsec_set_protect(drv->link, drv->protect_frames);
+
+ if (drv->encrypt_set)
+ rtnl_link_macsec_set_encrypt(drv->link, drv->encrypt);
+
+ if (drv->replay_protect_set) {
+ rtnl_link_macsec_set_replay_protect(drv->link,
+ drv->replay_protect);
+ if (drv->replay_protect)
+ rtnl_link_macsec_set_window(drv->link,
+ drv->replay_window);
+ }
+
+ if (drv->encoding_sa_set)
+ rtnl_link_macsec_set_encoding_sa(drv->link, drv->encoding_sa);
+
+ err = rtnl_link_add(drv->sk, drv->link, 0);
+ if (err < 0)
+ return err;
+
+ drv->protect_frames_set = FALSE;
+ drv->encrypt_set = FALSE;
+ drv->replay_protect_set = FALSE;
+
+ return 0;
+}
+
+
+static void macsec_drv_wpa_deinit(void *priv)
+{
+ struct macsec_drv_data *drv = priv;
+
+ driver_wired_deinit_common(&drv->common);
+ os_free(drv);
+}
+
+
+static void * macsec_drv_wpa_init(void *ctx, const char *ifname)
+{
+ struct macsec_drv_data *drv;
+
+ drv = os_zalloc(sizeof(*drv));
+ if (!drv)
+ return NULL;
+
+ if (driver_wired_init_common(&drv->common, ifname, ctx) < 0) {
+ os_free(drv);
+ return NULL;
+ }
+
+ return drv;
+}
+
+
+static int macsec_drv_macsec_init(void *priv, struct macsec_init_params *params)
+{
+ struct macsec_drv_data *drv = priv;
+ int err;
+
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+
+ drv->sk = nl_socket_alloc();
+ if (!drv->sk)
+ return -1;
+
+ err = nl_connect(drv->sk, NETLINK_ROUTE);
+ if (err < 0) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX
+ "Unable to connect NETLINK_ROUTE socket: %s",
+ strerror(errno));
+ goto sock;
+ }
+
+ err = rtnl_link_alloc_cache(drv->sk, AF_UNSPEC, &drv->link_cache);
+ if (err < 0) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "Unable to get link cache: %s",
+ strerror(errno));
+ goto sock;
+ }
+
+ drv->parent_ifi = rtnl_link_name2i(drv->link_cache, drv->common.ifname);
+ if (drv->parent_ifi == 0) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX
+ "couldn't find ifindex for interface %s",
+ drv->common.ifname);
+ goto cache;
+ }
+
+ err = init_genl_ctx(drv);
+ if (err < 0)
+ goto cache;
+
+ return 0;
+
+cache:
+ nl_cache_free(drv->link_cache);
+ drv->link_cache = NULL;
+sock:
+ nl_socket_free(drv->sk);
+ drv->sk = NULL;
+ return -1;
+}
+
+
+static int macsec_drv_macsec_deinit(void *priv)
+{
+ struct macsec_drv_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+
+ if (drv->sk)
+ nl_socket_free(drv->sk);
+ drv->sk = NULL;
+
+ if (drv->link_cache)
+ nl_cache_free(drv->link_cache);
+ drv->link_cache = NULL;
+
+ if (drv->ctx.sk)
+ nl_socket_free(drv->ctx.sk);
+
+ return 0;
+}
+
+
+static int macsec_drv_get_capability(void *priv, enum macsec_cap *cap)
+{
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+
+ *cap = MACSEC_CAP_INTEG_AND_CONF;
+
+ return 0;
+}
+
+
+/**
+ * macsec_drv_enable_protect_frames - Set protect frames status
+ * @priv: Private driver interface data
+ * @enabled: TRUE = protect frames enabled
+ * FALSE = protect frames disabled
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+static int macsec_drv_enable_protect_frames(void *priv, Boolean enabled)
+{
+ struct macsec_drv_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s -> %s", __func__, enabled ? "TRUE" : "FALSE");
+
+ drv->protect_frames_set = TRUE;
+ drv->protect_frames = enabled;
+
+ return try_commit(drv);
+}
+
+
+/**
+ * macsec_drv_enable_encrypt - Set protect frames status
+ * @priv: Private driver interface data
+ * @enabled: TRUE = protect frames enabled
+ * FALSE = protect frames disabled
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+static int macsec_drv_enable_encrypt(void *priv, Boolean enabled)
+{
+ struct macsec_drv_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s -> %s", __func__, enabled ? "TRUE" : "FALSE");
+
+ drv->encrypt_set = TRUE;
+ drv->encrypt = enabled;
+
+ return try_commit(drv);
+}
+
+
+/**
+ * macsec_drv_set_replay_protect - Set replay protect status and window size
+ * @priv: Private driver interface data
+ * @enabled: TRUE = replay protect enabled
+ * FALSE = replay protect disabled
+ * @window: replay window size, valid only when replay protect enabled
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+static int macsec_drv_set_replay_protect(void *priv, Boolean enabled,
+ u32 window)
+{
+ struct macsec_drv_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s -> %s, %u", __func__,
+ enabled ? "TRUE" : "FALSE", window);
+
+ drv->replay_protect_set = TRUE;
+ drv->replay_protect = enabled;
+ if (enabled)
+ drv->replay_window = window;
+
+ return try_commit(drv);
+}
+
+
+/**
+ * macsec_drv_set_current_cipher_suite - Set current cipher suite
+ * @priv: Private driver interface data
+ * @cs: EUI64 identifier
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+static int macsec_drv_set_current_cipher_suite(void *priv, u64 cs)
+{
+ wpa_printf(MSG_DEBUG, "%s -> %016" PRIx64, __func__, cs);
+ return 0;
+}
+
+
+/**
+ * macsec_drv_enable_controlled_port - Set controlled port status
+ * @priv: Private driver interface data
+ * @enabled: TRUE = controlled port enabled
+ * FALSE = controlled port disabled
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+static int macsec_drv_enable_controlled_port(void *priv, Boolean enabled)
+{
+ struct macsec_drv_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s -> %s", __func__, enabled ? "TRUE" : "FALSE");
+
+ drv->controlled_port_enabled = enabled;
+ drv->controlled_port_enabled_set = TRUE;
+
+ return try_commit(drv);
+}
+
+
+static struct nla_policy sa_policy[MACSEC_SA_ATTR_MAX + 1] = {
+ [MACSEC_SA_ATTR_AN] = { .type = NLA_U8 },
+ [MACSEC_SA_ATTR_ACTIVE] = { .type = NLA_U8 },
+ [MACSEC_SA_ATTR_PN] = { .type = NLA_U32 },
+ [MACSEC_SA_ATTR_KEYID] = { .type = NLA_BINARY },
+};
+
+static struct nla_policy sc_policy[MACSEC_RXSC_ATTR_MAX + 1] = {
+ [MACSEC_RXSC_ATTR_SCI] = { .type = NLA_U64 },
+ [MACSEC_RXSC_ATTR_ACTIVE] = { .type = NLA_U8 },
+ [MACSEC_RXSC_ATTR_SA_LIST] = { .type = NLA_NESTED },
+};
+
+static struct nla_policy main_policy[MACSEC_ATTR_MAX + 1] = {
+ [MACSEC_ATTR_IFINDEX] = { .type = NLA_U32 },
+ [MACSEC_ATTR_SECY] = { .type = NLA_NESTED },
+ [MACSEC_ATTR_TXSA_LIST] = { .type = NLA_NESTED },
+ [MACSEC_ATTR_RXSC_LIST] = { .type = NLA_NESTED },
+};
+
+static int dump_callback(struct nl_msg *msg, void *argp)
+{
+ struct nlmsghdr *ret_hdr = nlmsg_hdr(msg);
+ struct nlattr *tb_msg[MACSEC_ATTR_MAX + 1];
+ struct cb_arg *arg = (struct cb_arg *) argp;
+ struct genlmsghdr *gnlh = (struct genlmsghdr *) nlmsg_data(ret_hdr);
+ int err;
+
+ if (ret_hdr->nlmsg_type != arg->drv->ctx.macsec_genl_id)
+ return 0;
+
+ err = nla_parse(tb_msg, MACSEC_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), main_policy);
+ if (err < 0)
+ return 0;
+
+ if (!tb_msg[MACSEC_ATTR_IFINDEX])
+ return 0;
+
+ if (nla_get_u32(tb_msg[MACSEC_ATTR_IFINDEX]) != (u32) arg->ifindex)
+ return 0;
+
+ if (arg->txsa < 4 && !tb_msg[MACSEC_ATTR_TXSA_LIST]) {
+ return 0;
+ } else if (arg->txsa < 4) {
+ struct nlattr *nla;
+ int rem;
+
+ nla_for_each_nested(nla, tb_msg[MACSEC_ATTR_TXSA_LIST], rem) {
+ struct nlattr *tb[MACSEC_SA_ATTR_MAX + 1];
+
+ err = nla_parse_nested(tb, MACSEC_SA_ATTR_MAX, nla,
+ sa_policy);
+ if (err < 0)
+ continue;
+ if (!tb[MACSEC_SA_ATTR_AN])
+ continue;
+ if (nla_get_u8(tb[MACSEC_SA_ATTR_AN]) != arg->txsa)
+ continue;
+ if (!tb[MACSEC_SA_ATTR_PN])
+ return 0;
+ *arg->pn = nla_get_u32(tb[MACSEC_SA_ATTR_PN]);
+ return 0;
+ }
+
+ return 0;
+ }
+
+ if (arg->rxsci == UNUSED_SCI)
+ return 0;
+
+ if (tb_msg[MACSEC_ATTR_RXSC_LIST]) {
+ struct nlattr *nla;
+ int rem;
+
+ nla_for_each_nested(nla, tb_msg[MACSEC_ATTR_RXSC_LIST], rem) {
+ struct nlattr *tb[MACSEC_RXSC_ATTR_MAX + 1];
+
+ err = nla_parse_nested(tb, MACSEC_RXSC_ATTR_MAX, nla,
+ sc_policy);
+ if (err < 0)
+ return 0;
+ if (!tb[MACSEC_RXSC_ATTR_SCI])
+ continue;
+ if (nla_get_u64(tb[MACSEC_RXSC_ATTR_SCI]) != arg->rxsci)
+ continue;
+ if (!tb[MACSEC_RXSC_ATTR_SA_LIST])
+ return 0;
+
+ nla_for_each_nested(nla, tb[MACSEC_RXSC_ATTR_SA_LIST],
+ rem) {
+ struct nlattr *tb_sa[MACSEC_SA_ATTR_MAX + 1];
+
+ err = nla_parse_nested(tb_sa,
+ MACSEC_SA_ATTR_MAX, nla,
+ sa_policy);
+ if (err < 0)
+ continue;
+ if (!tb_sa[MACSEC_SA_ATTR_AN])
+ continue;
+ if (nla_get_u8(tb_sa[MACSEC_SA_ATTR_AN]) !=
+ arg->rxsa)
+ continue;
+ if (!tb_sa[MACSEC_SA_ATTR_PN])
+ return 0;
+ *arg->pn =
+ nla_get_u32(tb_sa[MACSEC_SA_ATTR_PN]);
+
+ return 0;
+ }
+
+ return 0;
+ }
+
+ return 0;
+ }
+
+ return 0;
+}
+
+
+static int nl_send_recv(struct nl_sock *sk, struct nl_msg *msg)
+{
+ int ret;
+
+ ret = nl_send_auto_complete(sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "%s: failed to send: %d (%s)",
+ __func__, ret, nl_geterror(-ret));
+ return ret;
+ }
+
+ ret = nl_recvmsgs_default(sk);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "%s: failed to recv: %d (%s)",
+ __func__, ret, nl_geterror(-ret));
+ }
+
+ return ret;
+}
+
+
+static int do_dump(struct macsec_drv_data *drv, u8 txsa, u64 rxsci, u8 rxsa,
+ u32 *pn)
+{
+ struct macsec_genl_ctx *ctx = &drv->ctx;
+ struct nl_msg *msg;
+ int ret = 1;
+
+ ctx->cb_arg.ifindex = drv->ifi;
+ ctx->cb_arg.rxsci = rxsci;
+ ctx->cb_arg.rxsa = rxsa;
+ ctx->cb_arg.txsa = txsa;
+ ctx->cb_arg.pn = pn;
+
+ msg = nlmsg_alloc();
+ if (!msg) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "%s: failed to alloc message",
+ __func__);
+ return 1;
+ }
+
+ if (!genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, ctx->macsec_genl_id, 0,
+ NLM_F_DUMP, MACSEC_CMD_GET_TXSC, 0)) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "%s: failed to put header",
+ __func__);
+ goto out_free_msg;
+ }
+
+ ret = nl_send_recv(ctx->sk, msg);
+ if (ret < 0)
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "failed to communicate: %d (%s)",
+ ret, nl_geterror(-ret));
+
+ ctx->cb_arg.pn = 0;
+
+out_free_msg:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+/**
+ * macsec_drv_get_receive_lowest_pn - Get receive lowest PN
+ * @priv: Private driver interface data
+ * @sa: secure association
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+static int macsec_drv_get_receive_lowest_pn(void *priv, struct receive_sa *sa)
+{
+ struct macsec_drv_data *drv = priv;
+ int err;
+
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s", __func__);
+
+ err = do_dump(drv, 0xff, mka_sci_u64(&sa->sc->sci), sa->an,
+ &sa->lowest_pn);
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: result %d", __func__,
+ sa->lowest_pn);
+
+ return err;
+}
+
+
+/**
+ * macsec_drv_get_transmit_next_pn - Get transmit next PN
+ * @priv: Private driver interface data
+ * @sa: secure association
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+static int macsec_drv_get_transmit_next_pn(void *priv, struct transmit_sa *sa)
+{
+ struct macsec_drv_data *drv = priv;
+ int err;
+
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+
+ err = do_dump(drv, sa->an, UNUSED_SCI, 0xff, &sa->next_pn);
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: err %d result %d", __func__, err,
+ sa->next_pn);
+ return err;
+}
+
+
+/**
+ * macsec_drv_set_transmit_next_pn - Set transmit next pn
+ * @priv: Private driver interface data
+ * @sa: secure association
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+static int macsec_drv_set_transmit_next_pn(void *priv, struct transmit_sa *sa)
+{
+ struct macsec_drv_data *drv = priv;
+ struct macsec_genl_ctx *ctx = &drv->ctx;
+ struct nl_msg *msg;
+ struct nlattr *nest;
+ int ret = -1;
+
+ wpa_printf(MSG_DEBUG, "%s -> %d: %d", __func__, sa->an, sa->next_pn);
+
+ msg = msg_prepare(MACSEC_CMD_UPD_TXSA, ctx, drv->ifi);
+ if (!msg)
+ return ret;
+
+ nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG);
+ if (!nest)
+ goto nla_put_failure;
+
+ NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, sa->an);
+ NLA_PUT_U32(msg, MACSEC_SA_ATTR_PN, sa->next_pn);
+
+ nla_nest_end(msg, nest);
+
+ ret = nl_send_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "failed to communicate: %d (%s)",
+ ret, nl_geterror(-ret));
+ }
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+#define SCISTR MACSTR "::%hx"
+#define SCI2STR(addr, port) MAC2STR(addr), htons(port)
+
+/**
+ * macsec_drv_create_receive_sc - Create secure channel for receiving
+ * @priv: Private driver interface data
+ * @sc: secure channel
+ * @sci_addr: secure channel identifier - address
+ * @sci_port: secure channel identifier - port
+ * @conf_offset: confidentiality offset (0, 30, or 50)
+ * @validation: frame validation policy (0 = Disabled, 1 = Checked,
+ * 2 = Strict)
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+static int macsec_drv_create_receive_sc(void *priv, struct receive_sc *sc,
+ unsigned int conf_offset,
+ int validation)
+{
+ struct macsec_drv_data *drv = priv;
+ struct macsec_genl_ctx *ctx = &drv->ctx;
+ struct nl_msg *msg;
+ int ret = -1;
+
+ wpa_printf(MSG_DEBUG, "%s -> " SCISTR, __func__,
+ SCI2STR(sc->sci.addr, sc->sci.port));
+
+ msg = msg_prepare(MACSEC_CMD_ADD_RXSC, ctx, drv->ifi);
+ if (!msg)
+ return ret;
+
+ if (nla_put_rxsc_config(msg, mka_sci_u64(&sc->sci)))
+ goto nla_put_failure;
+
+ ret = nl_send_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "%s: failed to communicate: %d (%s)",
+ __func__, ret, nl_geterror(-ret));
+ }
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+/**
+ * macsec_drv_delete_receive_sc - Delete secure connection for receiving
+ * @priv: private driver interface data from init()
+ * @sc: secure channel
+ * Returns: 0 on success, -1 on failure
+ */
+static int macsec_drv_delete_receive_sc(void *priv, struct receive_sc *sc)
+{
+ struct macsec_drv_data *drv = priv;
+ struct macsec_genl_ctx *ctx = &drv->ctx;
+ struct nl_msg *msg;
+ int ret = -1;
+
+ wpa_printf(MSG_DEBUG, "%s -> " SCISTR, __func__,
+ SCI2STR(sc->sci.addr, sc->sci.port));
+
+ msg = msg_prepare(MACSEC_CMD_DEL_RXSC, ctx, drv->ifi);
+ if (!msg)
+ return ret;
+
+ if (nla_put_rxsc_config(msg, mka_sci_u64(&sc->sci)))
+ goto nla_put_failure;
+
+ ret = nl_send_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "%s: failed to communicate: %d (%s)",
+ __func__, ret, nl_geterror(-ret));
+ }
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+/**
+ * macsec_drv_create_receive_sa - Create secure association for receive
+ * @priv: private driver interface data from init()
+ * @sa: secure association
+ * Returns: 0 on success, -1 on failure
+ */
+static int macsec_drv_create_receive_sa(void *priv, struct receive_sa *sa)
+{
+ struct macsec_drv_data *drv = priv;
+ struct macsec_genl_ctx *ctx = &drv->ctx;
+ struct nl_msg *msg;
+ struct nlattr *nest;
+ int ret = -1;
+
+ wpa_printf(MSG_DEBUG, "%s -> %d on " SCISTR, __func__, sa->an,
+ SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
+
+ msg = msg_prepare(MACSEC_CMD_ADD_RXSA, ctx, drv->ifi);
+ if (!msg)
+ return ret;
+
+ if (nla_put_rxsc_config(msg, mka_sci_u64(&sa->sc->sci)))
+ goto nla_put_failure;
+
+ nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG);
+ if (!nest)
+ goto nla_put_failure;
+
+ NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, sa->an);
+ NLA_PUT_U8(msg, MACSEC_SA_ATTR_ACTIVE, sa->enable_receive);
+ NLA_PUT_U32(msg, MACSEC_SA_ATTR_PN, sa->next_pn);
+ NLA_PUT(msg, MACSEC_SA_ATTR_KEYID, sizeof(sa->pkey->key_identifier),
+ &sa->pkey->key_identifier);
+ NLA_PUT(msg, MACSEC_SA_ATTR_KEY, sa->pkey->key_len, sa->pkey->key);
+
+ nla_nest_end(msg, nest);
+
+ ret = nl_send_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "%s: failed to communicate: %d (%s)",
+ __func__, ret, nl_geterror(-ret));
+ }
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+/**
+ * macsec_drv_delete_receive_sa - Delete secure association for receive
+ * @priv: private driver interface data from init()
+ * @sa: secure association
+ * Returns: 0 on success, -1 on failure
+ */
+static int macsec_drv_delete_receive_sa(void *priv, struct receive_sa *sa)
+{
+ struct macsec_drv_data *drv = priv;
+ struct macsec_genl_ctx *ctx = &drv->ctx;
+ struct nl_msg *msg;
+ struct nlattr *nest;
+ int ret = -1;
+
+ wpa_printf(MSG_DEBUG, "%s -> %d on " SCISTR, __func__, sa->an,
+ SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
+
+ msg = msg_prepare(MACSEC_CMD_DEL_RXSA, ctx, drv->ifi);
+ if (!msg)
+ return ret;
+
+ if (nla_put_rxsc_config(msg, mka_sci_u64(&sa->sc->sci)))
+ goto nla_put_failure;
+
+ nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG);
+ if (!nest)
+ goto nla_put_failure;
+
+ NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, sa->an);
+
+ nla_nest_end(msg, nest);
+
+ ret = nl_send_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "%s: failed to communicate: %d (%s)",
+ __func__, ret, nl_geterror(-ret));
+ }
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static int set_active_rx_sa(const struct macsec_genl_ctx *ctx, int ifindex,
+ u64 sci, unsigned char an, Boolean state)
+{
+ struct nl_msg *msg;
+ struct nlattr *nest;
+ int ret = -1;
+
+ msg = msg_prepare(MACSEC_CMD_UPD_RXSA, ctx, ifindex);
+ if (!msg)
+ return ret;
+
+ if (nla_put_rxsc_config(msg, sci))
+ goto nla_put_failure;
+
+ nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG);
+ if (!nest)
+ goto nla_put_failure;
+
+ NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, an);
+ NLA_PUT_U8(msg, MACSEC_SA_ATTR_ACTIVE, !!state);
+
+ nla_nest_end(msg, nest);
+
+ ret = nl_send_recv(ctx->sk, msg);
+ if (ret < 0)
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "%s: failed to communicate: %d (%s)",
+ __func__, ret, nl_geterror(-ret));
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+/**
+ * macsec_drv_enable_receive_sa - Enable the SA for receive
+ * @priv: private driver interface data from init()
+ * @sa: secure association
+ * Returns: 0 on success, -1 on failure
+ */
+static int macsec_drv_enable_receive_sa(void *priv, struct receive_sa *sa)
+{
+ struct macsec_drv_data *drv = priv;
+ struct macsec_genl_ctx *ctx = &drv->ctx;
+
+ wpa_printf(MSG_DEBUG, "%s -> %d on " SCISTR, __func__, sa->an,
+ SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
+
+ return set_active_rx_sa(ctx, drv->ifi, mka_sci_u64(&sa->sc->sci),
+ sa->an, TRUE);
+}
+
+
+/**
+ * macsec_drv_disable_receive_sa - Disable SA for receive
+ * @priv: private driver interface data from init()
+ * @sa: secure association
+ * Returns: 0 on success, -1 on failure
+ */
+static int macsec_drv_disable_receive_sa(void *priv, struct receive_sa *sa)
+{
+ struct macsec_drv_data *drv = priv;
+ struct macsec_genl_ctx *ctx = &drv->ctx;
+
+ wpa_printf(MSG_DEBUG, "%s -> %d on " SCISTR, __func__, sa->an,
+ SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
+
+ return set_active_rx_sa(ctx, drv->ifi, mka_sci_u64(&sa->sc->sci),
+ sa->an, FALSE);
+}
+
+
+static struct rtnl_link * lookup_sc(struct nl_cache *cache, int parent, u64 sci)
+{
+ struct rtnl_link *needle;
+ void *match;
+
+ needle = rtnl_link_macsec_alloc();
+ if (!needle)
+ return NULL;
+
+ rtnl_link_set_link(needle, parent);
+ rtnl_link_macsec_set_sci(needle, sci);
+
+ match = nl_cache_find(cache, (struct nl_object *) needle);
+ rtnl_link_put(needle);
+
+ return (struct rtnl_link *) match;
+}
+
+
+/**
+ * macsec_drv_create_transmit_sc - Create secure connection for transmit
+ * @priv: private driver interface data from init()
+ * @sc: secure channel
+ * @conf_offset: confidentiality offset
+ * Returns: 0 on success, -1 on failure
+ */
+static int macsec_drv_create_transmit_sc(
+ void *priv, struct transmit_sc *sc,
+ enum confidentiality_offset conf_offset)
+{
+ struct macsec_drv_data *drv = priv;
+ struct rtnl_link *link;
+ char *ifname;
+ u64 sci;
+ int err;
+
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+
+ link = rtnl_link_macsec_alloc();
+ if (!link) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "couldn't allocate link");
+ return -1;
+ }
+
+ rtnl_link_set_link(link, drv->parent_ifi);
+
+ sci = mka_sci_u64(&sc->sci);
+ rtnl_link_macsec_set_sci(link, sci);
+
+ drv->created_link = TRUE;
+
+ err = rtnl_link_add(drv->sk, link, NLM_F_CREATE);
+ if (err == -NLE_BUSY) {
+ wpa_printf(MSG_INFO,
+ DRV_PREFIX "link already exists, using it");
+ drv->created_link = FALSE;
+ } else if (err < 0) {
+ rtnl_link_put(link);
+ wpa_printf(MSG_ERROR, DRV_PREFIX "couldn't create link: err %d",
+ err);
+ return err;
+ }
+
+ rtnl_link_put(link);
+
+ nl_cache_refill(drv->sk, drv->link_cache);
+ link = lookup_sc(drv->link_cache, drv->parent_ifi, sci);
+ if (!link) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "couldn't find link");
+ return -1;
+ }
+
+ drv->ifi = rtnl_link_get_ifindex(link);
+ ifname = rtnl_link_get_name(link);
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+ rtnl_link_put(link);
+
+ drv->link = rtnl_link_macsec_alloc();
+ if (!drv->link) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "couldn't allocate link");
+ return -1;
+ }
+
+ rtnl_link_set_name(drv->link, drv->ifname);
+
+ /* In case some settings have already been done but we couldn't apply
+ * them. */
+ return try_commit(drv);
+}
+
+
+/**
+ * macsec_drv_delete_transmit_sc - Delete secure connection for transmit
+ * @priv: private driver interface data from init()
+ * @sc: secure channel
+ * Returns: 0 on success, -1 on failure
+ */
+static int macsec_drv_delete_transmit_sc(void *priv, struct transmit_sc *sc)
+{
+ struct macsec_drv_data *drv = priv;
+ int err;
+
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+
+ if (!drv->created_link) {
+ rtnl_link_put(drv->link);
+ drv->link = NULL;
+ wpa_printf(MSG_DEBUG, DRV_PREFIX
+ "we didn't create the link, leave it alone");
+ return 0;
+ }
+
+ err = rtnl_link_delete(drv->sk, drv->link);
+ if (err < 0)
+ wpa_printf(MSG_ERROR, DRV_PREFIX "couldn't delete link");
+ rtnl_link_put(drv->link);
+ drv->link = NULL;
+
+ return err;
+}
+
+
+/**
+ * macsec_drv_create_transmit_sa - Create secure association for transmit
+ * @priv: private driver interface data from init()
+ * @sa: secure association
+ * Returns: 0 on success, -1 on failure
+ */
+static int macsec_drv_create_transmit_sa(void *priv, struct transmit_sa *sa)
+{
+ struct macsec_drv_data *drv = priv;
+ struct macsec_genl_ctx *ctx = &drv->ctx;
+ struct nl_msg *msg;
+ struct nlattr *nest;
+ int ret = -1;
+
+ wpa_printf(MSG_DEBUG, "%s -> %d", __func__, sa->an);
+
+ msg = msg_prepare(MACSEC_CMD_ADD_TXSA, ctx, drv->ifi);
+ if (!msg)
+ return ret;
+
+ nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG);
+ if (!nest)
+ goto nla_put_failure;
+
+ NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, sa->an);
+ NLA_PUT_U32(msg, MACSEC_SA_ATTR_PN, sa->next_pn);
+ NLA_PUT(msg, MACSEC_SA_ATTR_KEYID, sizeof(sa->pkey->key_identifier),
+ &sa->pkey->key_identifier);
+ NLA_PUT(msg, MACSEC_SA_ATTR_KEY, sa->pkey->key_len, sa->pkey->key);
+ NLA_PUT_U8(msg, MACSEC_SA_ATTR_ACTIVE, sa->enable_transmit);
+
+ nla_nest_end(msg, nest);
+
+ ret = nl_send_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "%s: failed to communicate: %d (%s)",
+ __func__, ret, nl_geterror(-ret));
+ }
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+/**
+ * macsec_drv_delete_transmit_sa - Delete secure association for transmit
+ * @priv: private driver interface data from init()
+ * @sa: secure association
+ * Returns: 0 on success, -1 on failure
+ */
+static int macsec_drv_delete_transmit_sa(void *priv, struct transmit_sa *sa)
+{
+ struct macsec_drv_data *drv = priv;
+ struct macsec_genl_ctx *ctx = &drv->ctx;
+ struct nl_msg *msg;
+ struct nlattr *nest;
+ int ret = -1;
+
+ wpa_printf(MSG_DEBUG, "%s -> %d", __func__, sa->an);
+
+ msg = msg_prepare(MACSEC_CMD_DEL_TXSA, ctx, drv->ifi);
+ if (!msg)
+ return ret;
+
+ nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG);
+ if (!nest)
+ goto nla_put_failure;
+
+ NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, sa->an);
+
+ nla_nest_end(msg, nest);
+
+ ret = nl_send_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "%s: failed to communicate: %d (%s)",
+ __func__, ret, nl_geterror(-ret));
+ }
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static int set_active_tx_sa(const struct macsec_genl_ctx *ctx, int ifindex,
+ unsigned char an, Boolean state)
+{
+ struct nl_msg *msg;
+ struct nlattr *nest;
+ int ret = -1;
+
+ msg = msg_prepare(MACSEC_CMD_UPD_TXSA, ctx, ifindex);
+ if (!msg)
+ return ret;
+
+ nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG);
+ if (!nest)
+ goto nla_put_failure;
+
+ NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, an);
+ NLA_PUT_U8(msg, MACSEC_SA_ATTR_ACTIVE, !!state);
+
+ nla_nest_end(msg, nest);
+
+ ret = nl_send_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "%s: failed to communicate: %d (%s)",
+ __func__, ret, nl_geterror(-ret));
+ }
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+/**
+ * macsec_drv_enable_transmit_sa - Enable SA for transmit
+ * @priv: private driver interface data from init()
+ * @sa: secure association
+ * Returns: 0 on success, -1 on failure
+ */
+static int macsec_drv_enable_transmit_sa(void *priv, struct transmit_sa *sa)
+{
+ struct macsec_drv_data *drv = priv;
+ struct macsec_genl_ctx *ctx = &drv->ctx;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "%s -> %d", __func__, sa->an);
+
+ ret = set_active_tx_sa(ctx, drv->ifi, sa->an, TRUE);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "failed to enable txsa");
+ return ret;
+ }
+
+ drv->encoding_sa_set = TRUE;
+ drv->encoding_sa = sa->an;
+
+ return try_commit(drv);
+}
+
+
+/**
+ * macsec_drv_disable_transmit_sa - Disable SA for transmit
+ * @priv: private driver interface data from init()
+ * @sa: secure association
+ * Returns: 0 on success, -1 on failure
+ */
+static int macsec_drv_disable_transmit_sa(void *priv, struct transmit_sa *sa)
+{
+ struct macsec_drv_data *drv = priv;
+ struct macsec_genl_ctx *ctx = &drv->ctx;
+
+ wpa_printf(MSG_DEBUG, "%s -> %d", __func__, sa->an);
+
+ return set_active_tx_sa(ctx, drv->ifi, sa->an, FALSE);
+}
+
+
+const struct wpa_driver_ops wpa_driver_macsec_linux_ops = {
+ .name = "macsec_linux",
+ .desc = "MACsec Ethernet driver for Linux",
+ .get_ssid = driver_wired_get_ssid,
+ .get_bssid = driver_wired_get_bssid,
+ .get_capa = driver_wired_get_capa,
+ .init = macsec_drv_wpa_init,
+ .deinit = macsec_drv_wpa_deinit,
+
+ .macsec_init = macsec_drv_macsec_init,
+ .macsec_deinit = macsec_drv_macsec_deinit,
+ .macsec_get_capability = macsec_drv_get_capability,
+ .enable_protect_frames = macsec_drv_enable_protect_frames,
+ .enable_encrypt = macsec_drv_enable_encrypt,
+ .set_replay_protect = macsec_drv_set_replay_protect,
+ .set_current_cipher_suite = macsec_drv_set_current_cipher_suite,
+ .enable_controlled_port = macsec_drv_enable_controlled_port,
+ .get_receive_lowest_pn = macsec_drv_get_receive_lowest_pn,
+ .get_transmit_next_pn = macsec_drv_get_transmit_next_pn,
+ .set_transmit_next_pn = macsec_drv_set_transmit_next_pn,
+ .create_receive_sc = macsec_drv_create_receive_sc,
+ .delete_receive_sc = macsec_drv_delete_receive_sc,
+ .create_receive_sa = macsec_drv_create_receive_sa,
+ .delete_receive_sa = macsec_drv_delete_receive_sa,
+ .enable_receive_sa = macsec_drv_enable_receive_sa,
+ .disable_receive_sa = macsec_drv_disable_receive_sa,
+ .create_transmit_sc = macsec_drv_create_transmit_sc,
+ .delete_transmit_sc = macsec_drv_delete_transmit_sc,
+ .create_transmit_sa = macsec_drv_create_transmit_sa,
+ .delete_transmit_sa = macsec_drv_delete_transmit_sa,
+ .enable_transmit_sa = macsec_drv_enable_transmit_sa,
+ .disable_transmit_sa = macsec_drv_disable_transmit_sa,
+};
diff --git a/src/drivers/driver_macsec_qca.c b/src/drivers/driver_macsec_qca.c
index 22d414c..d3be19c 100644
--- a/src/drivers/driver_macsec_qca.c
+++ b/src/drivers/driver_macsec_qca.c
@@ -31,6 +31,7 @@
#include "common/ieee802_1x_defs.h"
#include "pae/ieee802_1x_kay.h"
#include "driver.h"
+#include "driver_wired_common.h"
#include "nss_macsec_secy.h"
#include "nss_macsec_secy_rx.h"
@@ -53,21 +54,14 @@
#pragma pack(pop)
#endif /* _MSC_VER */
-static const u8 pae_group_addr[ETH_ALEN] =
-{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
-
struct channel_map {
struct ieee802_1x_mka_sci sci;
};
struct macsec_qca_data {
- char ifname[IFNAMSIZ + 1];
- u32 secy_id;
- void *ctx;
+ struct driver_wired_common_data common;
- int sock; /* raw packet socket for driver access */
- int pf_sock;
- int membership, multi, iff_allmulti, iff_up;
+ u32 secy_id;
/* shadow */
Boolean always_include_sci;
@@ -82,191 +76,6 @@
};
-static int macsec_qca_multicast_membership(int sock, int ifindex,
- const u8 *addr, int add)
-{
-#ifdef __linux__
- struct packet_mreq mreq;
-
- if (sock < 0)
- return -1;
-
- os_memset(&mreq, 0, sizeof(mreq));
- mreq.mr_ifindex = ifindex;
- mreq.mr_type = PACKET_MR_MULTICAST;
- mreq.mr_alen = ETH_ALEN;
- os_memcpy(mreq.mr_address, addr, ETH_ALEN);
-
- if (setsockopt(sock, SOL_PACKET,
- add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP,
- &mreq, sizeof(mreq)) < 0) {
- wpa_printf(MSG_ERROR, "setsockopt: %s", strerror(errno));
- return -1;
- }
- return 0;
-#else /* __linux__ */
- return -1;
-#endif /* __linux__ */
-}
-
-
-static int macsec_qca_get_ssid(void *priv, u8 *ssid)
-{
- ssid[0] = 0;
- return 0;
-}
-
-
-static int macsec_qca_get_bssid(void *priv, u8 *bssid)
-{
- /* Report PAE group address as the "BSSID" for macsec connection. */
- os_memcpy(bssid, pae_group_addr, ETH_ALEN);
- return 0;
-}
-
-
-static int macsec_qca_get_capa(void *priv, struct wpa_driver_capa *capa)
-{
- os_memset(capa, 0, sizeof(*capa));
- capa->flags = WPA_DRIVER_FLAGS_WIRED;
- return 0;
-}
-
-
-static int macsec_qca_get_ifflags(const char *ifname, int *flags)
-{
- struct ifreq ifr;
- int s;
-
- s = socket(PF_INET, SOCK_DGRAM, 0);
- if (s < 0) {
- wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
- return -1;
- }
-
- os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
- if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
- wpa_printf(MSG_ERROR, "ioctl[SIOCGIFFLAGS]: %s",
- strerror(errno));
- close(s);
- return -1;
- }
- close(s);
- *flags = ifr.ifr_flags & 0xffff;
- return 0;
-}
-
-
-static int macsec_qca_set_ifflags(const char *ifname, int flags)
-{
- struct ifreq ifr;
- int s;
-
- s = socket(PF_INET, SOCK_DGRAM, 0);
- if (s < 0) {
- wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
- return -1;
- }
-
- os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
- ifr.ifr_flags = flags & 0xffff;
- if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
- wpa_printf(MSG_ERROR, "ioctl[SIOCSIFFLAGS]: %s",
- strerror(errno));
- close(s);
- return -1;
- }
- close(s);
- return 0;
-}
-
-
-#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
-static int macsec_qca_get_ifstatus(const char *ifname, int *status)
-{
- struct ifmediareq ifmr;
- int s;
-
- s = socket(PF_INET, SOCK_DGRAM, 0);
- if (s < 0) {
- wpa_print(MSG_ERROR, "socket: %s", strerror(errno));
- return -1;
- }
-
- os_memset(&ifmr, 0, sizeof(ifmr));
- os_strlcpy(ifmr.ifm_name, ifname, IFNAMSIZ);
- if (ioctl(s, SIOCGIFMEDIA, (caddr_t) &ifmr) < 0) {
- wpa_printf(MSG_ERROR, "ioctl[SIOCGIFMEDIA]: %s",
- strerror(errno));
- close(s);
- return -1;
- }
- close(s);
- *status = (ifmr.ifm_status & (IFM_ACTIVE | IFM_AVALID)) ==
- (IFM_ACTIVE | IFM_AVALID);
-
- return 0;
-}
-#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
-
-
-static int macsec_qca_multi(const char *ifname, const u8 *addr, int add)
-{
- struct ifreq ifr;
- int s;
-
-#ifdef __sun__
- return -1;
-#endif /* __sun__ */
-
- s = socket(PF_INET, SOCK_DGRAM, 0);
- if (s < 0) {
- wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
- return -1;
- }
-
- os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
-#ifdef __linux__
- ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
- os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
-#endif /* __linux__ */
-#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
- {
- struct sockaddr_dl *dlp;
- dlp = (struct sockaddr_dl *) &ifr.ifr_addr;
- dlp->sdl_len = sizeof(struct sockaddr_dl);
- dlp->sdl_family = AF_LINK;
- dlp->sdl_index = 0;
- dlp->sdl_nlen = 0;
- dlp->sdl_alen = ETH_ALEN;
- dlp->sdl_slen = 0;
- os_memcpy(LLADDR(dlp), addr, ETH_ALEN);
- }
-#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
-#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
- {
- struct sockaddr *sap;
- sap = (struct sockaddr *) &ifr.ifr_addr;
- sap->sa_len = sizeof(struct sockaddr);
- sap->sa_family = AF_UNSPEC;
- os_memcpy(sap->sa_data, addr, ETH_ALEN);
- }
-#endif /* defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) */
-
- if (ioctl(s, add ? SIOCADDMULTI : SIOCDELMULTI, (caddr_t) &ifr) < 0) {
- wpa_printf(MSG_ERROR, "ioctl[SIOC{ADD/DEL}MULTI]: %s",
- strerror(errno));
- close(s);
- return -1;
- }
- close(s);
- return 0;
-}
-
-
static void __macsec_drv_init(struct macsec_qca_data *drv)
{
int ret = 0;
@@ -317,76 +126,23 @@
static void * macsec_qca_init(void *ctx, const char *ifname)
{
struct macsec_qca_data *drv;
- int flags;
drv = os_zalloc(sizeof(*drv));
if (drv == NULL)
return NULL;
- os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
- drv->ctx = ctx;
/* Board specific settings */
- if (os_memcmp("eth2", drv->ifname, 4) == 0)
+ if (os_memcmp("eth2", ifname, 4) == 0)
drv->secy_id = 1;
- else if (os_memcmp("eth3", drv->ifname, 4) == 0)
+ else if (os_memcmp("eth3", ifname, 4) == 0)
drv->secy_id = 2;
else
drv->secy_id = -1;
-#ifdef __linux__
- drv->pf_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
- if (drv->pf_sock < 0)
- wpa_printf(MSG_ERROR, "socket(PF_PACKET): %s", strerror(errno));
-#else /* __linux__ */
- drv->pf_sock = -1;
-#endif /* __linux__ */
-
- if (macsec_qca_get_ifflags(ifname, &flags) == 0 &&
- !(flags & IFF_UP) &&
- macsec_qca_set_ifflags(ifname, flags | IFF_UP) == 0) {
- drv->iff_up = 1;
- }
-
- if (macsec_qca_multicast_membership(drv->pf_sock,
- if_nametoindex(drv->ifname),
- pae_group_addr, 1) == 0) {
- wpa_printf(MSG_DEBUG,
- "%s: Added multicast membership with packet socket",
- __func__);
- drv->membership = 1;
- } else if (macsec_qca_multi(ifname, pae_group_addr, 1) == 0) {
- wpa_printf(MSG_DEBUG,
- "%s: Added multicast membership with SIOCADDMULTI",
- __func__);
- drv->multi = 1;
- } else if (macsec_qca_get_ifflags(ifname, &flags) < 0) {
- wpa_printf(MSG_INFO, "%s: Could not get interface flags",
- __func__);
+ if (driver_wired_init_common(&drv->common, ifname, ctx) < 0) {
os_free(drv);
return NULL;
- } else if (flags & IFF_ALLMULTI) {
- wpa_printf(MSG_DEBUG,
- "%s: Interface is already configured for multicast",
- __func__);
- } else if (macsec_qca_set_ifflags(ifname, flags | IFF_ALLMULTI) < 0) {
- wpa_printf(MSG_INFO, "%s: Failed to enable allmulti",
- __func__);
- os_free(drv);
- return NULL;
- } else {
- wpa_printf(MSG_DEBUG, "%s: Enabled allmulti mode", __func__);
- drv->iff_allmulti = 1;
}
-#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
- {
- int status;
- wpa_printf(MSG_DEBUG, "%s: waiting for link to become active",
- __func__);
- while (macsec_qca_get_ifstatus(ifname, &status) == 0 &&
- status == 0)
- sleep(1);
- }
-#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
return drv;
}
@@ -395,42 +151,8 @@
static void macsec_qca_deinit(void *priv)
{
struct macsec_qca_data *drv = priv;
- int flags;
- if (drv->membership &&
- macsec_qca_multicast_membership(drv->pf_sock,
- if_nametoindex(drv->ifname),
- pae_group_addr, 0) < 0) {
- wpa_printf(MSG_DEBUG,
- "%s: Failed to remove PAE multicast group (PACKET)",
- __func__);
- }
-
- if (drv->multi &&
- macsec_qca_multi(drv->ifname, pae_group_addr, 0) < 0) {
- wpa_printf(MSG_DEBUG,
- "%s: Failed to remove PAE multicast group (SIOCDELMULTI)",
- __func__);
- }
-
- if (drv->iff_allmulti &&
- (macsec_qca_get_ifflags(drv->ifname, &flags) < 0 ||
- macsec_qca_set_ifflags(drv->ifname, flags & ~IFF_ALLMULTI) < 0)) {
- wpa_printf(MSG_DEBUG, "%s: Failed to disable allmulti mode",
- __func__);
- }
-
- if (drv->iff_up &&
- macsec_qca_get_ifflags(drv->ifname, &flags) == 0 &&
- (flags & IFF_UP) &&
- macsec_qca_set_ifflags(drv->ifname, flags & ~IFF_UP) < 0) {
- wpa_printf(MSG_DEBUG, "%s: Failed to set the interface down",
- __func__);
- }
-
- if (drv->pf_sock != -1)
- close(drv->pf_sock);
-
+ driver_wired_deinit_common(&drv->common);
os_free(drv);
}
@@ -1011,9 +733,9 @@
const struct wpa_driver_ops wpa_driver_macsec_qca_ops = {
.name = "macsec_qca",
.desc = "QCA MACsec Ethernet driver",
- .get_ssid = macsec_qca_get_ssid,
- .get_bssid = macsec_qca_get_bssid,
- .get_capa = macsec_qca_get_capa,
+ .get_ssid = driver_wired_get_ssid,
+ .get_bssid = driver_wired_get_bssid,
+ .get_capa = driver_wired_get_capa,
.init = macsec_qca_init,
.deinit = macsec_qca_deinit,
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 75c4271..d5716db 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -1181,16 +1181,108 @@
}
-unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv)
+struct nl80211_get_assoc_freq_arg {
+ struct wpa_driver_nl80211_data *drv;
+ unsigned int assoc_freq;
+ unsigned int ibss_freq;
+ u8 assoc_bssid[ETH_ALEN];
+ u8 assoc_ssid[SSID_MAX_LEN];
+ u8 assoc_ssid_len;
+};
+
+static int nl80211_get_assoc_freq_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *bss[NL80211_BSS_MAX + 1];
+ static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
+ [NL80211_BSS_BSSID] = { .type = NLA_UNSPEC },
+ [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
+ [NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC },
+ [NL80211_BSS_STATUS] = { .type = NLA_U32 },
+ };
+ struct nl80211_get_assoc_freq_arg *ctx = arg;
+ enum nl80211_bss_status status;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+ if (!tb[NL80211_ATTR_BSS] ||
+ nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
+ bss_policy) ||
+ !bss[NL80211_BSS_STATUS])
+ return NL_SKIP;
+
+ status = nla_get_u32(bss[NL80211_BSS_STATUS]);
+ if (status == NL80211_BSS_STATUS_ASSOCIATED &&
+ bss[NL80211_BSS_FREQUENCY]) {
+ ctx->assoc_freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
+ wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz",
+ ctx->assoc_freq);
+ }
+ if (status == NL80211_BSS_STATUS_IBSS_JOINED &&
+ bss[NL80211_BSS_FREQUENCY]) {
+ ctx->ibss_freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
+ wpa_printf(MSG_DEBUG, "nl80211: IBSS-joined on %u MHz",
+ ctx->ibss_freq);
+ }
+ if (status == NL80211_BSS_STATUS_ASSOCIATED &&
+ bss[NL80211_BSS_BSSID]) {
+ os_memcpy(ctx->assoc_bssid,
+ nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN);
+ wpa_printf(MSG_DEBUG, "nl80211: Associated with "
+ MACSTR, MAC2STR(ctx->assoc_bssid));
+ }
+
+ if (status == NL80211_BSS_STATUS_ASSOCIATED &&
+ bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
+ const u8 *ie, *ssid;
+ size_t ie_len;
+
+ ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
+ ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
+ ssid = get_ie(ie, ie_len, WLAN_EID_SSID);
+ if (ssid && ssid[1] > 0 && ssid[1] <= SSID_MAX_LEN) {
+ ctx->assoc_ssid_len = ssid[1];
+ os_memcpy(ctx->assoc_ssid, ssid + 2, ssid[1]);
+ }
+ }
+
+ return NL_SKIP;
+}
+
+
+int nl80211_get_assoc_ssid(struct wpa_driver_nl80211_data *drv, u8 *ssid)
{
struct nl_msg *msg;
int ret;
- struct nl80211_bss_info_arg arg;
+ struct nl80211_get_assoc_freq_arg arg;
msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
os_memset(&arg, 0, sizeof(arg));
arg.drv = drv;
- ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
+ ret = send_and_recv_msgs(drv, msg, nl80211_get_assoc_freq_handler,
+ &arg);
+ if (ret == 0) {
+ os_memcpy(ssid, arg.assoc_ssid, arg.assoc_ssid_len);
+ return arg.assoc_ssid_len;
+ }
+ wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ return ret;
+}
+
+
+unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv)
+{
+ struct nl_msg *msg;
+ int ret;
+ struct nl80211_get_assoc_freq_arg arg;
+
+ msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
+ os_memset(&arg, 0, sizeof(arg));
+ arg.drv = drv;
+ ret = send_and_recv_msgs(drv, msg, nl80211_get_assoc_freq_handler,
+ &arg);
if (ret == 0) {
unsigned int freq = drv->nlmode == NL80211_IFTYPE_ADHOC ?
arg.ibss_freq : arg.assoc_freq;
@@ -3517,6 +3609,147 @@
#endif /* CONFIG_MESH */
+static int nl80211_put_beacon_rate(struct nl_msg *msg, const u64 flags,
+ struct wpa_driver_ap_params *params)
+{
+ struct nlattr *bands, *band;
+ struct nl80211_txrate_vht vht_rate;
+
+ if (!params->freq ||
+ (params->beacon_rate == 0 &&
+ params->rate_type == BEACON_RATE_LEGACY))
+ return 0;
+
+ bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES);
+ if (!bands)
+ return -1;
+
+ switch (params->freq->mode) {
+ case HOSTAPD_MODE_IEEE80211B:
+ case HOSTAPD_MODE_IEEE80211G:
+ band = nla_nest_start(msg, NL80211_BAND_2GHZ);
+ break;
+ case HOSTAPD_MODE_IEEE80211A:
+ band = nla_nest_start(msg, NL80211_BAND_5GHZ);
+ break;
+ case HOSTAPD_MODE_IEEE80211AD:
+ band = nla_nest_start(msg, NL80211_BAND_60GHZ);
+ break;
+ default:
+ return 0;
+ }
+
+ if (!band)
+ return -1;
+
+ os_memset(&vht_rate, 0, sizeof(vht_rate));
+
+ switch (params->rate_type) {
+ case BEACON_RATE_LEGACY:
+ if (!(flags & WPA_DRIVER_FLAGS_BEACON_RATE_LEGACY)) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Driver does not support setting Beacon frame rate (legacy)");
+ return -1;
+ }
+
+ if (nla_put_u8(msg, NL80211_TXRATE_LEGACY,
+ (u8) params->beacon_rate / 5) ||
+ nla_put(msg, NL80211_TXRATE_HT, 0, NULL) ||
+ (params->freq->vht_enabled &&
+ nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate),
+ &vht_rate)))
+ return -1;
+
+ wpa_printf(MSG_DEBUG, " * beacon_rate = legacy:%u (* 100 kbps)",
+ params->beacon_rate);
+ break;
+ case BEACON_RATE_HT:
+ if (!(flags & WPA_DRIVER_FLAGS_BEACON_RATE_HT)) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Driver does not support setting Beacon frame rate (HT)");
+ return -1;
+ }
+ if (nla_put(msg, NL80211_TXRATE_LEGACY, 0, NULL) ||
+ nla_put_u8(msg, NL80211_TXRATE_HT, params->beacon_rate) ||
+ (params->freq->vht_enabled &&
+ nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate),
+ &vht_rate)))
+ return -1;
+ wpa_printf(MSG_DEBUG, " * beacon_rate = HT-MCS %u",
+ params->beacon_rate);
+ break;
+ case BEACON_RATE_VHT:
+ if (!(flags & WPA_DRIVER_FLAGS_BEACON_RATE_VHT)) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Driver does not support setting Beacon frame rate (VHT)");
+ return -1;
+ }
+ vht_rate.mcs[0] = BIT(params->beacon_rate);
+ if (nla_put(msg, NL80211_TXRATE_LEGACY, 0, NULL))
+ return -1;
+ if (nla_put(msg, NL80211_TXRATE_HT, 0, NULL))
+ return -1;
+ if (nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate),
+ &vht_rate))
+ return -1;
+ wpa_printf(MSG_DEBUG, " * beacon_rate = VHT-MCS %u",
+ params->beacon_rate);
+ break;
+ }
+
+ nla_nest_end(msg, band);
+ nla_nest_end(msg, bands);
+
+ return 0;
+}
+
+
+static int nl80211_set_multicast_to_unicast(struct i802_bss *bss,
+ int multicast_to_unicast)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_MULTICAST_TO_UNICAST);
+ if (!msg ||
+ (multicast_to_unicast &&
+ nla_put_flag(msg, NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED))) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Failed to build NL80211_CMD_SET_MULTICAST_TO_UNICAST msg for %s",
+ bss->ifname);
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+
+ switch (ret) {
+ case 0:
+ wpa_printf(MSG_DEBUG,
+ "nl80211: multicast to unicast %s on interface %s",
+ multicast_to_unicast ? "enabled" : "disabled",
+ bss->ifname);
+ break;
+ case -EOPNOTSUPP:
+ if (!multicast_to_unicast)
+ break;
+ wpa_printf(MSG_INFO,
+ "nl80211: multicast to unicast not supported on interface %s",
+ bss->ifname);
+ break;
+ default:
+ wpa_printf(MSG_ERROR,
+ "nl80211: %s multicast to unicast failed with %d (%s) on interface %s",
+ multicast_to_unicast ? "enabling" : "disabling",
+ ret, strerror(-ret), bss->ifname);
+ break;
+ }
+
+ return ret;
+}
+
+
static int wpa_driver_nl80211_set_ap(void *priv,
struct wpa_driver_ap_params *params)
{
@@ -3547,6 +3780,8 @@
params->tail, params->tail_len);
wpa_printf(MSG_DEBUG, "nl80211: ifindex=%d", bss->ifindex);
wpa_printf(MSG_DEBUG, "nl80211: beacon_int=%d", params->beacon_int);
+ wpa_printf(MSG_DEBUG, "nl80211: beacon_rate=%u", params->beacon_rate);
+ wpa_printf(MSG_DEBUG, "nl80211: rate_type=%d", params->rate_type);
wpa_printf(MSG_DEBUG, "nl80211: dtim_period=%d", params->dtim_period);
wpa_hexdump_ascii(MSG_DEBUG, "nl80211: ssid",
params->ssid, params->ssid_len);
@@ -3556,6 +3791,7 @@
nla_put(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len,
params->tail) ||
nl80211_put_beacon_int(msg, params->beacon_int) ||
+ nl80211_put_beacon_rate(msg, drv->capa.flags, params) ||
nl80211_put_dtim_period(msg, params->dtim_period) ||
nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
goto fail;
@@ -3733,6 +3969,8 @@
nl80211_set_bss(bss, params->cts_protect, params->preamble,
params->short_slot_time, params->ht_opmode,
params->isolate, params->basic_rates);
+ nl80211_set_multicast_to_unicast(bss,
+ params->multicast_to_unicast);
if (beacon_set && params->freq &&
params->freq->bandwidth != bss->bandwidth) {
wpa_printf(MSG_DEBUG,
@@ -5647,8 +5885,6 @@
{
struct nl_msg *msg;
- os_memset(data, 0, sizeof(*data));
-
if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_GET_STATION)) ||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
nlmsg_free(msg);
@@ -5754,6 +5990,7 @@
struct hostap_sta_driver_data data;
int ret;
+ os_memset(&data, 0, sizeof(data));
data.inactive_msec = (unsigned long) -1;
ret = i802_read_sta_data(priv, &data, addr);
if (ret == -ENOENT)
@@ -7756,6 +7993,8 @@
const u8 *addr)
{
struct i802_bss *bss = priv;
+
+ os_memset(data, 0, sizeof(*data));
return i802_read_sta_data(bss, data, addr);
}
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index d0ec48c..94b8bdf 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -228,6 +228,7 @@
void *arg, int use_existing);
void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv, int ifidx);
unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv);
+int nl80211_get_assoc_ssid(struct wpa_driver_nl80211_data *drv, u8 *ssid);
enum chan_width convert2width(int width);
void nl80211_mark_disconnected(struct wpa_driver_nl80211_data *drv);
struct i802_bss * get_bss_ifindex(struct wpa_driver_nl80211_data *drv,
@@ -282,15 +283,6 @@
/* driver_nl80211_scan.c */
-struct nl80211_bss_info_arg {
- struct wpa_driver_nl80211_data *drv;
- struct wpa_scan_results *res;
- unsigned int assoc_freq;
- unsigned int ibss_freq;
- u8 assoc_bssid[ETH_ALEN];
-};
-
-int bss_info_handler(struct nl_msg *msg, void *arg);
void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx);
int wpa_driver_nl80211_scan(struct i802_bss *bss,
struct wpa_driver_scan_params *params);
@@ -299,7 +291,7 @@
int wpa_driver_nl80211_stop_sched_scan(void *priv);
struct wpa_scan_results * wpa_driver_nl80211_get_scan_results(void *priv);
void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv);
-int wpa_driver_nl80211_abort_scan(void *priv);
+int wpa_driver_nl80211_abort_scan(void *priv, u64 scan_cookie);
int wpa_driver_nl80211_vendor_scan(struct i802_bss *bss,
struct wpa_driver_scan_params *params);
int nl80211_set_default_scan_ies(void *priv, const u8 *ies, size_t ies_len);
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 2507a43..85706ef 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -365,6 +365,18 @@
if (ext_feature_isset(ext_features, len, NL80211_EXT_FEATURE_FILS_STA))
capa->flags |= WPA_DRIVER_FLAGS_SUPPORT_FILS;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_BEACON_RATE_LEGACY))
+ capa->flags |= WPA_DRIVER_FLAGS_BEACON_RATE_LEGACY;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_BEACON_RATE_HT))
+ capa->flags |= WPA_DRIVER_FLAGS_BEACON_RATE_HT;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_BEACON_RATE_VHT))
+ capa->flags |= WPA_DRIVER_FLAGS_BEACON_RATE_VHT;
}
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index c77e21e..66cfb72 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -206,6 +206,7 @@
const struct ieee80211_mgmt *mgmt;
union wpa_event_data event;
u16 status;
+ int ssid_len;
if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
drv->force_connect_cmd) {
@@ -257,6 +258,16 @@
event.assoc_info.freq = drv->assoc_freq;
+ /* When this association was initiated outside of wpa_supplicant,
+ * drv->ssid needs to be set here to satisfy later checking. */
+ ssid_len = nl80211_get_assoc_ssid(drv, drv->ssid);
+ if (ssid_len > 0) {
+ drv->ssid_len = ssid_len;
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Set drv->ssid based on scan res info to '%s'",
+ wpa_ssid_txt(drv->ssid, drv->ssid_len));
+ }
+
nl80211_parse_wmm_params(wmm, &event.assoc_info.wmm_params);
wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
@@ -275,8 +286,9 @@
struct nlattr *subnet_status)
{
union wpa_event_data event;
- const u8 *ssid;
+ const u8 *ssid = NULL;
u16 status_code;
+ int ssid_len;
if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
/*
@@ -347,6 +359,10 @@
if (ssid && ssid[1] > 0 && ssid[1] <= 32) {
drv->ssid_len = ssid[1];
os_memcpy(drv->ssid, ssid + 2, ssid[1]);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Set drv->ssid based on req_ie to '%s'",
+ wpa_ssid_txt(drv->ssid,
+ drv->ssid_len));
}
}
}
@@ -357,6 +373,16 @@
event.assoc_info.freq = nl80211_get_assoc_freq(drv);
+ if ((!ssid || ssid[1] == 0 || ssid[1] > 32) &&
+ (ssid_len = nl80211_get_assoc_ssid(drv, drv->ssid)) > 0) {
+ /* When this connection was initiated outside of wpa_supplicant,
+ * drv->ssid needs to be set here to satisfy later checking. */
+ drv->ssid_len = ssid_len;
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Set drv->ssid based on scan res info to '%s'",
+ wpa_ssid_txt(drv->ssid, drv->ssid_len));
+ }
+
if (authorized && nla_get_u8(authorized)) {
event.assoc_info.authorized = 1;
wpa_printf(MSG_DEBUG, "nl80211: connection authorized");
@@ -2116,9 +2142,10 @@
case NL80211_CMD_NEW_SCAN_RESULTS:
wpa_dbg(drv->ctx, MSG_DEBUG,
"nl80211: New scan results available");
+ if (drv->last_scan_cmd != NL80211_CMD_VENDOR)
+ drv->scan_state = SCAN_COMPLETED;
drv->scan_complete_events = 1;
if (drv->last_scan_cmd == NL80211_CMD_TRIGGER_SCAN) {
- drv->scan_state = SCAN_COMPLETED;
eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout,
drv, drv->ctx);
drv->last_scan_cmd = 0;
@@ -2135,8 +2162,9 @@
break;
case NL80211_CMD_SCAN_ABORTED:
wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan aborted");
- if (drv->last_scan_cmd == NL80211_CMD_TRIGGER_SCAN) {
+ if (drv->last_scan_cmd != NL80211_CMD_VENDOR)
drv->scan_state = SCAN_ABORTED;
+ if (drv->last_scan_cmd == NL80211_CMD_TRIGGER_SCAN) {
/*
* Need to indicate that scan results are available in
* order not to make wpa_supplicant stop its scanning.
diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c
index c115b6b..43ed2b7 100644
--- a/src/drivers/driver_nl80211_scan.c
+++ b/src/drivers/driver_nl80211_scan.c
@@ -20,6 +20,14 @@
#include "driver_nl80211.h"
+#define MAX_NL80211_NOISE_FREQS 50
+
+struct nl80211_noise_info {
+ u32 freq[MAX_NL80211_NOISE_FREQS];
+ s8 noise[MAX_NL80211_NOISE_FREQS];
+ unsigned int count;
+};
+
static int get_noise_for_scan_results(struct nl_msg *msg, void *arg)
{
struct nlattr *tb[NL80211_ATTR_MAX + 1];
@@ -29,9 +37,10 @@
[NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
[NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
};
- struct wpa_scan_results *scan_results = arg;
- struct wpa_scan_res *scan_res;
- size_t i;
+ struct nl80211_noise_info *info = arg;
+
+ if (info->count >= MAX_NL80211_NOISE_FREQS)
+ return NL_STOP;
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
genlmsg_attrlen(gnlh, 0), NULL);
@@ -55,36 +64,83 @@
if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
return NL_SKIP;
- for (i = 0; i < scan_results->num; ++i) {
- scan_res = scan_results->res[i];
- if (!scan_res)
- continue;
- if ((int) nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
- scan_res->freq)
- continue;
- if (!(scan_res->flags & WPA_SCAN_NOISE_INVALID))
- continue;
- scan_res->noise = (s8)
- nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
- scan_res->flags &= ~WPA_SCAN_NOISE_INVALID;
- }
+ info->freq[info->count] =
+ nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]);
+ info->noise[info->count] =
+ (s8) nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
+ info->count++;
return NL_SKIP;
}
static int nl80211_get_noise_for_scan_results(
- struct wpa_driver_nl80211_data *drv,
- struct wpa_scan_results *scan_res)
+ struct wpa_driver_nl80211_data *drv, struct nl80211_noise_info *info)
{
struct nl_msg *msg;
+ os_memset(info, 0, sizeof(*info));
msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
- return send_and_recv_msgs(drv, msg, get_noise_for_scan_results,
- scan_res);
+ return send_and_recv_msgs(drv, msg, get_noise_for_scan_results, info);
}
+static int nl80211_abort_scan(struct i802_bss *bss)
+{
+ int ret;
+ struct nl_msg *msg;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Abort scan");
+ msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_ABORT_SCAN);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Abort scan failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ }
+ return ret;
+}
+
+
+#ifdef CONFIG_DRIVER_NL80211_QCA
+static int nl80211_abort_vendor_scan(struct wpa_driver_nl80211_data *drv,
+ u64 scan_cookie)
+{
+ struct nl_msg *msg;
+ struct nlattr *params;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Abort vendor scan with cookie 0x%llx",
+ (long long unsigned int) scan_cookie);
+
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
+ if (!msg ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_ABORT_SCAN) ||
+ !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+ nla_put_u64(msg, QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE, scan_cookie))
+ goto fail;
+
+ nla_nest_end(msg, params);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Aborting vendor scan with cookie 0x%llx failed: ret=%d (%s)",
+ (long long unsigned int) scan_cookie, ret,
+ strerror(-ret));
+ goto fail;
+ }
+ return 0;
+fail:
+ nlmsg_free(msg);
+ return -1;
+}
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+
+
/**
* wpa_driver_nl80211_scan_timeout - Scan timeout to report scan completion
* @eloop_ctx: Driver private data
@@ -98,7 +154,15 @@
struct wpa_driver_nl80211_data *drv = eloop_ctx;
wpa_printf(MSG_DEBUG, "nl80211: Scan timeout - try to abort it");
- if (!wpa_driver_nl80211_abort_scan(drv->first_bss))
+#ifdef CONFIG_DRIVER_NL80211_QCA
+ if (drv->vendor_scan_cookie &&
+ nl80211_abort_vendor_scan(drv, drv->vendor_scan_cookie) == 0) {
+ drv->vendor_scan_cookie = 0;
+ return;
+ }
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+ if (!drv->vendor_scan_cookie &&
+ nl80211_abort_scan(drv->first_bss) == 0)
return;
wpa_printf(MSG_DEBUG, "nl80211: Failed to abort scan");
@@ -562,7 +626,9 @@
}
-int bss_info_handler(struct nl_msg *msg, void *arg)
+static struct wpa_scan_res *
+nl80211_parse_bss_info(struct wpa_driver_nl80211_data *drv,
+ struct nl_msg *msg)
{
struct nlattr *tb[NL80211_ATTR_MAX + 1];
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
@@ -580,49 +646,18 @@
[NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 },
[NL80211_BSS_BEACON_IES] = { .type = NLA_UNSPEC },
};
- struct nl80211_bss_info_arg *_arg = arg;
- struct wpa_scan_results *res = _arg->res;
- struct wpa_scan_res **tmp;
struct wpa_scan_res *r;
const u8 *ie, *beacon_ie;
size_t ie_len, beacon_ie_len;
u8 *pos;
- size_t i;
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
genlmsg_attrlen(gnlh, 0), NULL);
if (!tb[NL80211_ATTR_BSS])
- return NL_SKIP;
+ return NULL;
if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
bss_policy))
- return NL_SKIP;
- if (bss[NL80211_BSS_STATUS]) {
- enum nl80211_bss_status status;
- status = nla_get_u32(bss[NL80211_BSS_STATUS]);
- if (status == NL80211_BSS_STATUS_ASSOCIATED &&
- bss[NL80211_BSS_FREQUENCY]) {
- _arg->assoc_freq =
- nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
- wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz",
- _arg->assoc_freq);
- }
- if (status == NL80211_BSS_STATUS_IBSS_JOINED &&
- bss[NL80211_BSS_FREQUENCY]) {
- _arg->ibss_freq =
- nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
- wpa_printf(MSG_DEBUG, "nl80211: IBSS-joined on %u MHz",
- _arg->ibss_freq);
- }
- if (status == NL80211_BSS_STATUS_ASSOCIATED &&
- bss[NL80211_BSS_BSSID]) {
- os_memcpy(_arg->assoc_bssid,
- nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN);
- wpa_printf(MSG_DEBUG, "nl80211: Associated with "
- MACSTR, MAC2STR(_arg->assoc_bssid));
- }
- }
- if (!res)
- return NL_SKIP;
+ return NULL;
if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
@@ -638,13 +673,13 @@
beacon_ie_len = 0;
}
- if (nl80211_scan_filtered(_arg->drv, ie ? ie : beacon_ie,
+ if (nl80211_scan_filtered(drv, ie ? ie : beacon_ie,
ie ? ie_len : beacon_ie_len))
- return NL_SKIP;
+ return NULL;
r = os_zalloc(sizeof(*r) + ie_len + beacon_ie_len);
if (r == NULL)
- return NL_SKIP;
+ return NULL;
if (bss[NL80211_BSS_BSSID])
os_memcpy(r->bssid, nla_data(bss[NL80211_BSS_BSSID]),
ETH_ALEN);
@@ -695,40 +730,30 @@
}
}
- /*
- * cfg80211 maintains separate BSS table entries for APs if the same
- * BSSID,SSID pair is seen on multiple channels. wpa_supplicant does
- * not use frequency as a separate key in the BSS table, so filter out
- * duplicated entries. Prefer associated BSS entry in such a case in
- * order to get the correct frequency into the BSS table. Similarly,
- * prefer newer entries over older.
- */
- for (i = 0; i < res->num; i++) {
- const u8 *s1, *s2;
- if (os_memcmp(res->res[i]->bssid, r->bssid, ETH_ALEN) != 0)
- continue;
+ return r;
+}
- s1 = get_ie((u8 *) (res->res[i] + 1),
- res->res[i]->ie_len, WLAN_EID_SSID);
- s2 = get_ie((u8 *) (r + 1), r->ie_len, WLAN_EID_SSID);
- if (s1 == NULL || s2 == NULL || s1[1] != s2[1] ||
- os_memcmp(s1, s2, 2 + s1[1]) != 0)
- continue;
- /* Same BSSID,SSID was already included in scan results */
- wpa_printf(MSG_DEBUG, "nl80211: Remove duplicated scan result "
- "for " MACSTR, MAC2STR(r->bssid));
+struct nl80211_bss_info_arg {
+ struct wpa_driver_nl80211_data *drv;
+ struct wpa_scan_results *res;
+};
- if (((r->flags & WPA_SCAN_ASSOCIATED) &&
- !(res->res[i]->flags & WPA_SCAN_ASSOCIATED)) ||
- r->age < res->res[i]->age) {
- os_free(res->res[i]);
- res->res[i] = r;
- } else
- os_free(r);
+static int bss_info_handler(struct nl_msg *msg, void *arg)
+{
+ struct nl80211_bss_info_arg *_arg = arg;
+ struct wpa_scan_results *res = _arg->res;
+ struct wpa_scan_res **tmp;
+ struct wpa_scan_res *r;
+
+ r = nl80211_parse_bss_info(_arg->drv, msg);
+ if (!r)
+ return NL_SKIP;
+
+ if (!res) {
+ os_free(r);
return NL_SKIP;
}
-
tmp = os_realloc_array(res->res, res->num + 1,
sizeof(struct wpa_scan_res *));
if (tmp == NULL) {
@@ -755,36 +780,51 @@
}
+static void nl80211_check_bss_status(struct wpa_driver_nl80211_data *drv,
+ struct wpa_scan_res *r)
+{
+ if (!(r->flags & WPA_SCAN_ASSOCIATED))
+ return;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Scan results indicate BSS status with "
+ MACSTR " as associated", MAC2STR(r->bssid));
+ if (is_sta_interface(drv->nlmode) && !drv->associated) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Local state (not associated) does not match with BSS state");
+ clear_state_mismatch(drv, r->bssid);
+ } else if (is_sta_interface(drv->nlmode) &&
+ os_memcmp(drv->bssid, r->bssid, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Local state (associated with " MACSTR
+ ") does not match with BSS state",
+ MAC2STR(drv->bssid));
+ clear_state_mismatch(drv, r->bssid);
+ clear_state_mismatch(drv, drv->bssid);
+ }
+}
+
+
static void wpa_driver_nl80211_check_bss_status(
struct wpa_driver_nl80211_data *drv, struct wpa_scan_results *res)
{
size_t i;
- for (i = 0; i < res->num; i++) {
- struct wpa_scan_res *r = res->res[i];
+ for (i = 0; i < res->num; i++)
+ nl80211_check_bss_status(drv, res->res[i]);
+}
- if (r->flags & WPA_SCAN_ASSOCIATED) {
- wpa_printf(MSG_DEBUG, "nl80211: Scan results "
- "indicate BSS status with " MACSTR
- " as associated",
- MAC2STR(r->bssid));
- if (is_sta_interface(drv->nlmode) &&
- !drv->associated) {
- wpa_printf(MSG_DEBUG, "nl80211: Local state "
- "(not associated) does not match "
- "with BSS state");
- clear_state_mismatch(drv, r->bssid);
- } else if (is_sta_interface(drv->nlmode) &&
- os_memcmp(drv->bssid, r->bssid, ETH_ALEN) !=
- 0) {
- wpa_printf(MSG_DEBUG, "nl80211: Local state "
- "(associated with " MACSTR ") does "
- "not match with BSS state",
- MAC2STR(drv->bssid));
- clear_state_mismatch(drv, r->bssid);
- clear_state_mismatch(drv, drv->bssid);
- }
- }
+
+static void nl80211_update_scan_res_noise(struct wpa_scan_res *res,
+ struct nl80211_noise_info *info)
+{
+ unsigned int i;
+
+ for (i = 0; res && i < info->count; i++) {
+ if ((int) info->freq[i] != res->freq ||
+ !(res->flags & WPA_SCAN_NOISE_INVALID))
+ continue;
+ res->noise = info->noise[i];
+ res->flags &= ~WPA_SCAN_NOISE_INVALID;
}
}
@@ -810,9 +850,17 @@
arg.res = res;
ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
if (ret == 0) {
+ struct nl80211_noise_info info;
+
wpa_printf(MSG_DEBUG, "nl80211: Received scan results (%lu "
"BSSes)", (unsigned long) res->num);
- nl80211_get_noise_for_scan_results(drv, res);
+ if (nl80211_get_noise_for_scan_results(drv, &info) == 0) {
+ size_t i;
+
+ for (i = 0; i < res->num; ++i)
+ nl80211_update_scan_res_noise(res->res[i],
+ &info);
+ }
return res;
}
wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
@@ -840,45 +888,57 @@
}
-void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv)
+struct nl80211_dump_scan_ctx {
+ struct wpa_driver_nl80211_data *drv;
+ int idx;
+};
+
+static int nl80211_dump_scan_handler(struct nl_msg *msg, void *arg)
{
- struct wpa_scan_results *res;
- size_t i;
+ struct nl80211_dump_scan_ctx *ctx = arg;
+ struct wpa_scan_res *r;
- res = nl80211_get_scan_results(drv);
- if (res == NULL) {
- wpa_printf(MSG_DEBUG, "nl80211: Failed to get scan results");
- return;
- }
-
- wpa_printf(MSG_DEBUG, "nl80211: Scan result dump");
- for (i = 0; i < res->num; i++) {
- struct wpa_scan_res *r = res->res[i];
- wpa_printf(MSG_DEBUG, "nl80211: %d/%d " MACSTR "%s",
- (int) i, (int) res->num, MAC2STR(r->bssid),
- r->flags & WPA_SCAN_ASSOCIATED ? " [assoc]" : "");
- }
-
- wpa_scan_results_free(res);
+ r = nl80211_parse_bss_info(ctx->drv, msg);
+ if (!r)
+ return NL_SKIP;
+ wpa_printf(MSG_DEBUG, "nl80211: %d " MACSTR " %d%s",
+ ctx->idx, MAC2STR(r->bssid), r->freq,
+ r->flags & WPA_SCAN_ASSOCIATED ? " [assoc]" : "");
+ ctx->idx++;
+ os_free(r);
+ return NL_SKIP;
}
-int wpa_driver_nl80211_abort_scan(void *priv)
+void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv)
+{
+ struct nl_msg *msg;
+ struct nl80211_dump_scan_ctx ctx;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Scan result dump");
+ ctx.drv = drv;
+ ctx.idx = 0;
+ msg = nl80211_cmd_msg(drv->first_bss, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
+ if (msg)
+ send_and_recv_msgs(drv, msg, nl80211_dump_scan_handler, &ctx);
+}
+
+
+int wpa_driver_nl80211_abort_scan(void *priv, u64 scan_cookie)
{
struct i802_bss *bss = priv;
+#ifdef CONFIG_DRIVER_NL80211_QCA
struct wpa_driver_nl80211_data *drv = bss->drv;
- int ret;
- struct nl_msg *msg;
- wpa_printf(MSG_DEBUG, "nl80211: Abort scan");
- msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_ABORT_SCAN);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- if (ret) {
- wpa_printf(MSG_DEBUG, "nl80211: Abort scan failed: ret=%d (%s)",
- ret, strerror(-ret));
- }
-
- return ret;
+ /*
+ * If scan_cookie is zero, a normal scan through kernel (cfg80211)
+ * was triggered, hence abort the cfg80211 scan instead of the vendor
+ * scan.
+ */
+ if (drv->scan_vendor_cmd_avail && scan_cookie)
+ return nl80211_abort_vendor_scan(drv, scan_cookie);
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+ return nl80211_abort_scan(bss);
}
@@ -1056,6 +1116,8 @@
drv->vendor_scan_cookie = cookie;
drv->scan_state = SCAN_REQUESTED;
+ /* Pass the cookie to the caller to help distinguish the scans. */
+ params->scan_cookie = cookie;
wpa_printf(MSG_DEBUG,
"nl80211: Vendor scan requested (ret=%d) - scan timeout 30 seconds, scan cookie:0x%llx",
diff --git a/src/drivers/driver_privsep.c b/src/drivers/driver_privsep.c
index 5d85033..8c93d26 100644
--- a/src/drivers/driver_privsep.c
+++ b/src/drivers/driver_privsep.c
@@ -102,10 +102,26 @@
struct wpa_driver_scan_params *params)
{
struct wpa_driver_privsep_data *drv = priv;
- const u8 *ssid = params->ssids[0].ssid;
- size_t ssid_len = params->ssids[0].ssid_len;
+ struct privsep_cmd_scan scan;
+ size_t i;
+
wpa_printf(MSG_DEBUG, "%s: priv=%p", __func__, priv);
- return wpa_priv_cmd(drv, PRIVSEP_CMD_SCAN, ssid, ssid_len,
+ os_memset(&scan, 0, sizeof(scan));
+ scan.num_ssids = params->num_ssids;
+ for (i = 0; i < params->num_ssids; i++) {
+ if (!params->ssids[i].ssid)
+ continue;
+ scan.ssid_lens[i] = params->ssids[i].ssid_len;
+ os_memcpy(scan.ssids[i], params->ssids[i].ssid,
+ scan.ssid_lens[i]);
+ }
+
+ for (i = 0; i < PRIVSEP_MAX_SCAN_FREQS &&
+ params->freqs && params->freqs[i]; i++)
+ scan.freqs[i] = params->freqs[i];
+ scan.num_freqs = i;
+
+ return wpa_priv_cmd(drv, PRIVSEP_CMD_SCAN, &scan, sizeof(scan),
NULL, NULL);
}
@@ -173,7 +189,11 @@
break;
os_memcpy(r, pos, len);
pos += len;
- if (sizeof(*r) + r->ie_len > (size_t) len) {
+ if (sizeof(*r) + r->ie_len + r->beacon_ie_len > (size_t) len) {
+ wpa_printf(MSG_ERROR,
+ "privsep: Invalid scan result len (%d + %d + %d > %d)",
+ (int) sizeof(*r), (int) r->ie_len,
+ (int) r->beacon_ie_len, len);
os_free(r);
break;
}
diff --git a/src/drivers/driver_wired.c b/src/drivers/driver_wired.c
index 422a220..7e09dcf 100644
--- a/src/drivers/driver_wired.c
+++ b/src/drivers/driver_wired.c
@@ -12,6 +12,7 @@
#include "common.h"
#include "eloop.h"
#include "driver.h"
+#include "driver_wired_common.h"
#include <sys/ioctl.h>
#undef IFNAMSIZ
@@ -42,20 +43,12 @@
#pragma pack(pop)
#endif /* _MSC_VER */
-static const u8 pae_group_addr[ETH_ALEN] =
-{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
-
struct wpa_driver_wired_data {
- char ifname[IFNAMSIZ + 1];
- void *ctx;
+ struct driver_wired_common_data common;
- int sock; /* raw packet socket for driver access */
int dhcp_sock; /* socket for dhcp packets */
int use_pae_group_addr;
-
- int pf_sock;
- int membership, multi, iff_allmulti, iff_up;
};
@@ -83,34 +76,6 @@
};
-static int wired_multicast_membership(int sock, int ifindex,
- const u8 *addr, int add)
-{
-#ifdef __linux__
- struct packet_mreq mreq;
-
- if (sock < 0)
- return -1;
-
- os_memset(&mreq, 0, sizeof(mreq));
- mreq.mr_ifindex = ifindex;
- mreq.mr_type = PACKET_MR_MULTICAST;
- mreq.mr_alen = ETH_ALEN;
- os_memcpy(mreq.mr_address, addr, ETH_ALEN);
-
- if (setsockopt(sock, SOL_PACKET,
- add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP,
- &mreq, sizeof(mreq)) < 0) {
- wpa_printf(MSG_ERROR, "setsockopt: %s", strerror(errno));
- return -1;
- }
- return 0;
-#else /* __linux__ */
- return -1;
-#endif /* __linux__ */
-}
-
-
#ifdef __linux__
static void handle_data(void *ctx, unsigned char *buf, size_t len)
{
@@ -208,21 +173,22 @@
struct sockaddr_in addr2;
int n = 1;
- drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE));
- if (drv->sock < 0) {
+ drv->common.sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE));
+ if (drv->common.sock < 0) {
wpa_printf(MSG_ERROR, "socket[PF_PACKET,SOCK_RAW]: %s",
strerror(errno));
return -1;
}
- if (eloop_register_read_sock(drv->sock, handle_read, drv->ctx, NULL)) {
+ if (eloop_register_read_sock(drv->common.sock, handle_read,
+ drv->common.ctx, NULL)) {
wpa_printf(MSG_INFO, "Could not register read socket");
return -1;
}
os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
- if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) {
+ os_strlcpy(ifr.ifr_name, drv->common.ifname, sizeof(ifr.ifr_name));
+ if (ioctl(drv->common.sock, SIOCGIFINDEX, &ifr) != 0) {
wpa_printf(MSG_ERROR, "ioctl(SIOCGIFINDEX): %s",
strerror(errno));
return -1;
@@ -234,13 +200,14 @@
wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d",
addr.sll_ifindex);
- if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ if (bind(drv->common.sock, (struct sockaddr *) &addr, sizeof(addr)) < 0)
+ {
wpa_printf(MSG_ERROR, "bind: %s", strerror(errno));
return -1;
}
/* filter multicast address */
- if (wired_multicast_membership(drv->sock, ifr.ifr_ifindex,
+ if (wired_multicast_membership(drv->common.sock, ifr.ifr_ifindex,
pae_group_addr, 1) < 0) {
wpa_printf(MSG_ERROR, "wired: Failed to add multicast group "
"membership");
@@ -248,8 +215,8 @@
}
os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
- if (ioctl(drv->sock, SIOCGIFHWADDR, &ifr) != 0) {
+ os_strlcpy(ifr.ifr_name, drv->common.ifname, sizeof(ifr.ifr_name));
+ if (ioctl(drv->common.sock, SIOCGIFHWADDR, &ifr) != 0) {
wpa_printf(MSG_ERROR, "ioctl(SIOCGIFHWADDR): %s",
strerror(errno));
return -1;
@@ -269,8 +236,8 @@
return -1;
}
- if (eloop_register_read_sock(drv->dhcp_sock, handle_dhcp, drv->ctx,
- NULL)) {
+ if (eloop_register_read_sock(drv->dhcp_sock, handle_dhcp,
+ drv->common.ctx, NULL)) {
wpa_printf(MSG_INFO, "Could not register read socket");
return -1;
}
@@ -294,7 +261,7 @@
}
os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_ifrn.ifrn_name, drv->ifname, IFNAMSIZ);
+ os_strlcpy(ifr.ifr_ifrn.ifrn_name, drv->common.ifname, IFNAMSIZ);
if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BINDTODEVICE,
(char *) &ifr, sizeof(ifr)) < 0) {
wpa_printf(MSG_ERROR,
@@ -343,7 +310,7 @@
pos = (u8 *) (hdr + 1);
os_memcpy(pos, data, data_len);
- res = send(drv->sock, (u8 *) hdr, len, 0);
+ res = send(drv->common.sock, (u8 *) hdr, len, 0);
os_free(hdr);
if (res < 0) {
@@ -368,8 +335,9 @@
return NULL;
}
- drv->ctx = hapd;
- os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname));
+ drv->common.ctx = hapd;
+ os_strlcpy(drv->common.ifname, params->ifname,
+ sizeof(drv->common.ifname));
drv->use_pae_group_addr = params->use_pae_group_addr;
if (wired_init_sockets(drv, params->own_addr)) {
@@ -385,9 +353,9 @@
{
struct wpa_driver_wired_data *drv = priv;
- if (drv->sock >= 0) {
- eloop_unregister_read_sock(drv->sock);
- close(drv->sock);
+ if (drv->common.sock >= 0) {
+ eloop_unregister_read_sock(drv->common.sock);
+ close(drv->common.sock);
}
if (drv->dhcp_sock >= 0) {
@@ -399,227 +367,18 @@
}
-static int wpa_driver_wired_get_ssid(void *priv, u8 *ssid)
-{
- ssid[0] = 0;
- return 0;
-}
-
-
-static int wpa_driver_wired_get_bssid(void *priv, u8 *bssid)
-{
- /* Report PAE group address as the "BSSID" for wired connection. */
- os_memcpy(bssid, pae_group_addr, ETH_ALEN);
- return 0;
-}
-
-
-static int wpa_driver_wired_get_capa(void *priv, struct wpa_driver_capa *capa)
-{
- os_memset(capa, 0, sizeof(*capa));
- capa->flags = WPA_DRIVER_FLAGS_WIRED;
- return 0;
-}
-
-
-static int wpa_driver_wired_get_ifflags(const char *ifname, int *flags)
-{
- struct ifreq ifr;
- int s;
-
- s = socket(PF_INET, SOCK_DGRAM, 0);
- if (s < 0) {
- wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
- return -1;
- }
-
- os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
- if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
- wpa_printf(MSG_ERROR, "ioctl[SIOCGIFFLAGS]: %s",
- strerror(errno));
- close(s);
- return -1;
- }
- close(s);
- *flags = ifr.ifr_flags & 0xffff;
- return 0;
-}
-
-
-static int wpa_driver_wired_set_ifflags(const char *ifname, int flags)
-{
- struct ifreq ifr;
- int s;
-
- s = socket(PF_INET, SOCK_DGRAM, 0);
- if (s < 0) {
- wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
- return -1;
- }
-
- os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
- ifr.ifr_flags = flags & 0xffff;
- if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
- wpa_printf(MSG_ERROR, "ioctl[SIOCSIFFLAGS]: %s",
- strerror(errno));
- close(s);
- return -1;
- }
- close(s);
- return 0;
-}
-
-
-#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
-static int wpa_driver_wired_get_ifstatus(const char *ifname, int *status)
-{
- struct ifmediareq ifmr;
- int s;
-
- s = socket(PF_INET, SOCK_DGRAM, 0);
- if (s < 0) {
- wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
- return -1;
- }
-
- os_memset(&ifmr, 0, sizeof(ifmr));
- os_strlcpy(ifmr.ifm_name, ifname, IFNAMSIZ);
- if (ioctl(s, SIOCGIFMEDIA, (caddr_t) &ifmr) < 0) {
- wpa_printf(MSG_ERROR, "ioctl[SIOCGIFMEDIA]: %s",
- strerror(errno));
- close(s);
- return -1;
- }
- close(s);
- *status = (ifmr.ifm_status & (IFM_ACTIVE | IFM_AVALID)) ==
- (IFM_ACTIVE | IFM_AVALID);
-
- return 0;
-}
-#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
-
-
-static int wpa_driver_wired_multi(const char *ifname, const u8 *addr, int add)
-{
- struct ifreq ifr;
- int s;
-
-#ifdef __sun__
- return -1;
-#endif /* __sun__ */
-
- s = socket(PF_INET, SOCK_DGRAM, 0);
- if (s < 0) {
- wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
- return -1;
- }
-
- os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
-#ifdef __linux__
- ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
- os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
-#endif /* __linux__ */
-#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
- {
- struct sockaddr_dl *dlp;
- dlp = (struct sockaddr_dl *) &ifr.ifr_addr;
- dlp->sdl_len = sizeof(struct sockaddr_dl);
- dlp->sdl_family = AF_LINK;
- dlp->sdl_index = 0;
- dlp->sdl_nlen = 0;
- dlp->sdl_alen = ETH_ALEN;
- dlp->sdl_slen = 0;
- os_memcpy(LLADDR(dlp), addr, ETH_ALEN);
- }
-#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
-#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
- {
- struct sockaddr *sap;
- sap = (struct sockaddr *) &ifr.ifr_addr;
- sap->sa_len = sizeof(struct sockaddr);
- sap->sa_family = AF_UNSPEC;
- os_memcpy(sap->sa_data, addr, ETH_ALEN);
- }
-#endif /* defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) */
-
- if (ioctl(s, add ? SIOCADDMULTI : SIOCDELMULTI, (caddr_t) &ifr) < 0) {
- wpa_printf(MSG_ERROR, "ioctl[SIOC{ADD/DEL}MULTI]: %s",
- strerror(errno));
- close(s);
- return -1;
- }
- close(s);
- return 0;
-}
-
-
static void * wpa_driver_wired_init(void *ctx, const char *ifname)
{
struct wpa_driver_wired_data *drv;
- int flags;
drv = os_zalloc(sizeof(*drv));
if (drv == NULL)
return NULL;
- os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
- drv->ctx = ctx;
-#ifdef __linux__
- drv->pf_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
- if (drv->pf_sock < 0)
- wpa_printf(MSG_ERROR, "socket(PF_PACKET): %s", strerror(errno));
-#else /* __linux__ */
- drv->pf_sock = -1;
-#endif /* __linux__ */
-
- if (wpa_driver_wired_get_ifflags(ifname, &flags) == 0 &&
- !(flags & IFF_UP) &&
- wpa_driver_wired_set_ifflags(ifname, flags | IFF_UP) == 0) {
- drv->iff_up = 1;
- }
-
- if (wired_multicast_membership(drv->pf_sock,
- if_nametoindex(drv->ifname),
- pae_group_addr, 1) == 0) {
- wpa_printf(MSG_DEBUG, "%s: Added multicast membership with "
- "packet socket", __func__);
- drv->membership = 1;
- } else if (wpa_driver_wired_multi(ifname, pae_group_addr, 1) == 0) {
- wpa_printf(MSG_DEBUG, "%s: Added multicast membership with "
- "SIOCADDMULTI", __func__);
- drv->multi = 1;
- } else if (wpa_driver_wired_get_ifflags(ifname, &flags) < 0) {
- wpa_printf(MSG_INFO, "%s: Could not get interface "
- "flags", __func__);
+ if (driver_wired_init_common(&drv->common, ifname, ctx) < 0) {
os_free(drv);
return NULL;
- } else if (flags & IFF_ALLMULTI) {
- wpa_printf(MSG_DEBUG, "%s: Interface is already configured "
- "for multicast", __func__);
- } else if (wpa_driver_wired_set_ifflags(ifname,
- flags | IFF_ALLMULTI) < 0) {
- wpa_printf(MSG_INFO, "%s: Failed to enable allmulti",
- __func__);
- os_free(drv);
- return NULL;
- } else {
- wpa_printf(MSG_DEBUG, "%s: Enabled allmulti mode",
- __func__);
- drv->iff_allmulti = 1;
}
-#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
- {
- int status;
- wpa_printf(MSG_DEBUG, "%s: waiting for link to become active",
- __func__);
- while (wpa_driver_wired_get_ifstatus(ifname, &status) == 0 &&
- status == 0)
- sleep(1);
- }
-#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
return drv;
}
@@ -628,41 +387,8 @@
static void wpa_driver_wired_deinit(void *priv)
{
struct wpa_driver_wired_data *drv = priv;
- int flags;
- if (drv->membership &&
- wired_multicast_membership(drv->pf_sock,
- if_nametoindex(drv->ifname),
- pae_group_addr, 0) < 0) {
- wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE multicast "
- "group (PACKET)", __func__);
- }
-
- if (drv->multi &&
- wpa_driver_wired_multi(drv->ifname, pae_group_addr, 0) < 0) {
- wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE multicast "
- "group (SIOCDELMULTI)", __func__);
- }
-
- if (drv->iff_allmulti &&
- (wpa_driver_wired_get_ifflags(drv->ifname, &flags) < 0 ||
- wpa_driver_wired_set_ifflags(drv->ifname,
- flags & ~IFF_ALLMULTI) < 0)) {
- wpa_printf(MSG_DEBUG, "%s: Failed to disable allmulti mode",
- __func__);
- }
-
- if (drv->iff_up &&
- wpa_driver_wired_get_ifflags(drv->ifname, &flags) == 0 &&
- (flags & IFF_UP) &&
- wpa_driver_wired_set_ifflags(drv->ifname, flags & ~IFF_UP) < 0) {
- wpa_printf(MSG_DEBUG, "%s: Failed to set the interface down",
- __func__);
- }
-
- if (drv->pf_sock != -1)
- close(drv->pf_sock);
-
+ driver_wired_deinit_common(&drv->common);
os_free(drv);
}
@@ -673,9 +399,9 @@
.hapd_init = wired_driver_hapd_init,
.hapd_deinit = wired_driver_hapd_deinit,
.hapd_send_eapol = wired_send_eapol,
- .get_ssid = wpa_driver_wired_get_ssid,
- .get_bssid = wpa_driver_wired_get_bssid,
- .get_capa = wpa_driver_wired_get_capa,
+ .get_ssid = driver_wired_get_ssid,
+ .get_bssid = driver_wired_get_bssid,
+ .get_capa = driver_wired_get_capa,
.init = wpa_driver_wired_init,
.deinit = wpa_driver_wired_deinit,
};
diff --git a/src/drivers/driver_wired_common.c b/src/drivers/driver_wired_common.c
new file mode 100644
index 0000000..a860b1c
--- /dev/null
+++ b/src/drivers/driver_wired_common.c
@@ -0,0 +1,322 @@
+/*
+ * Common functions for Wired Ethernet driver interfaces
+ * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004, Gunter Burchardt <tira@isx.de>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "driver.h"
+#include "driver_wired_common.h"
+
+#include <sys/ioctl.h>
+#include <net/if.h>
+#ifdef __linux__
+#include <netpacket/packet.h>
+#include <net/if_arp.h>
+#include <net/if.h>
+#endif /* __linux__ */
+#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) */
+#ifdef __sun__
+#include <sys/sockio.h>
+#endif /* __sun__ */
+
+
+static int driver_wired_get_ifflags(const char *ifname, int *flags)
+{
+ struct ifreq ifr;
+ int s;
+
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
+ return -1;
+ }
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIFFLAGS]: %s",
+ strerror(errno));
+ close(s);
+ return -1;
+ }
+ close(s);
+ *flags = ifr.ifr_flags & 0xffff;
+ return 0;
+}
+
+
+static int driver_wired_set_ifflags(const char *ifname, int flags)
+{
+ struct ifreq ifr;
+ int s;
+
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
+ return -1;
+ }
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ ifr.ifr_flags = flags & 0xffff;
+ if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIFFLAGS]: %s",
+ strerror(errno));
+ close(s);
+ return -1;
+ }
+ close(s);
+ return 0;
+}
+
+
+static int driver_wired_multi(const char *ifname, const u8 *addr, int add)
+{
+ struct ifreq ifr;
+ int s;
+
+#ifdef __sun__
+ return -1;
+#endif /* __sun__ */
+
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
+ return -1;
+ }
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+#ifdef __linux__
+ ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
+ os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
+#endif /* __linux__ */
+#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
+ {
+ struct sockaddr_dl *dlp;
+
+ dlp = (struct sockaddr_dl *) &ifr.ifr_addr;
+ dlp->sdl_len = sizeof(struct sockaddr_dl);
+ dlp->sdl_family = AF_LINK;
+ dlp->sdl_index = 0;
+ dlp->sdl_nlen = 0;
+ dlp->sdl_alen = ETH_ALEN;
+ dlp->sdl_slen = 0;
+ os_memcpy(LLADDR(dlp), addr, ETH_ALEN);
+ }
+#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
+#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
+ {
+ struct sockaddr *sap;
+
+ sap = (struct sockaddr *) &ifr.ifr_addr;
+ sap->sa_len = sizeof(struct sockaddr);
+ sap->sa_family = AF_UNSPEC;
+ os_memcpy(sap->sa_data, addr, ETH_ALEN);
+ }
+#endif /* defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) */
+
+ if (ioctl(s, add ? SIOCADDMULTI : SIOCDELMULTI, (caddr_t) &ifr) < 0) {
+ wpa_printf(MSG_ERROR, "ioctl[SIOC{ADD/DEL}MULTI]: %s",
+ strerror(errno));
+ close(s);
+ return -1;
+ }
+ close(s);
+ return 0;
+}
+
+
+int wired_multicast_membership(int sock, int ifindex, const u8 *addr, int add)
+{
+#ifdef __linux__
+ struct packet_mreq mreq;
+
+ if (sock < 0)
+ return -1;
+
+ os_memset(&mreq, 0, sizeof(mreq));
+ mreq.mr_ifindex = ifindex;
+ mreq.mr_type = PACKET_MR_MULTICAST;
+ mreq.mr_alen = ETH_ALEN;
+ os_memcpy(mreq.mr_address, addr, ETH_ALEN);
+
+ if (setsockopt(sock, SOL_PACKET,
+ add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP,
+ &mreq, sizeof(mreq)) < 0) {
+ wpa_printf(MSG_ERROR, "setsockopt: %s", strerror(errno));
+ return -1;
+ }
+ return 0;
+#else /* __linux__ */
+ return -1;
+#endif /* __linux__ */
+}
+
+
+int driver_wired_get_ssid(void *priv, u8 *ssid)
+{
+ ssid[0] = 0;
+ return 0;
+}
+
+
+int driver_wired_get_bssid(void *priv, u8 *bssid)
+{
+ /* Report PAE group address as the "BSSID" for wired connection. */
+ os_memcpy(bssid, pae_group_addr, ETH_ALEN);
+ return 0;
+}
+
+
+int driver_wired_get_capa(void *priv, struct wpa_driver_capa *capa)
+{
+ os_memset(capa, 0, sizeof(*capa));
+ capa->flags = WPA_DRIVER_FLAGS_WIRED;
+ return 0;
+}
+
+
+#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
+static int driver_wired_get_ifstatus(const char *ifname, int *status)
+{
+ struct ifmediareq ifmr;
+ int s;
+
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
+ return -1;
+ }
+
+ os_memset(&ifmr, 0, sizeof(ifmr));
+ os_strlcpy(ifmr.ifm_name, ifname, IFNAMSIZ);
+ if (ioctl(s, SIOCGIFMEDIA, (caddr_t) &ifmr) < 0) {
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIFMEDIA]: %s",
+ strerror(errno));
+ close(s);
+ return -1;
+ }
+ close(s);
+ *status = (ifmr.ifm_status & (IFM_ACTIVE | IFM_AVALID)) ==
+ (IFM_ACTIVE | IFM_AVALID);
+
+ return 0;
+}
+#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
+
+
+int driver_wired_init_common(struct driver_wired_common_data *common,
+ const char *ifname, void *ctx)
+{
+ int flags;
+
+ os_strlcpy(common->ifname, ifname, sizeof(common->ifname));
+ common->ctx = ctx;
+
+#ifdef __linux__
+ common->pf_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
+ if (common->pf_sock < 0)
+ wpa_printf(MSG_ERROR, "socket(PF_PACKET): %s", strerror(errno));
+#else /* __linux__ */
+ common->pf_sock = -1;
+#endif /* __linux__ */
+
+ if (driver_wired_get_ifflags(ifname, &flags) == 0 &&
+ !(flags & IFF_UP) &&
+ driver_wired_set_ifflags(ifname, flags | IFF_UP) == 0)
+ common->iff_up = 1;
+
+ if (wired_multicast_membership(common->pf_sock,
+ if_nametoindex(common->ifname),
+ pae_group_addr, 1) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "%s: Added multicast membership with packet socket",
+ __func__);
+ common->membership = 1;
+ } else if (driver_wired_multi(ifname, pae_group_addr, 1) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "%s: Added multicast membership with SIOCADDMULTI",
+ __func__);
+ common->multi = 1;
+ } else if (driver_wired_get_ifflags(ifname, &flags) < 0) {
+ wpa_printf(MSG_INFO, "%s: Could not get interface flags",
+ __func__);
+ return -1;
+ } else if (flags & IFF_ALLMULTI) {
+ wpa_printf(MSG_DEBUG,
+ "%s: Interface is already configured for multicast",
+ __func__);
+ } else if (driver_wired_set_ifflags(ifname,
+ flags | IFF_ALLMULTI) < 0) {
+ wpa_printf(MSG_INFO, "%s: Failed to enable allmulti", __func__);
+ return -1;
+ } else {
+ wpa_printf(MSG_DEBUG, "%s: Enabled allmulti mode", __func__);
+ common->iff_allmulti = 1;
+ }
+#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
+ {
+ int status;
+
+ wpa_printf(MSG_DEBUG, "%s: waiting for link to become active",
+ __func__);
+ while (driver_wired_get_ifstatus(ifname, &status) == 0 &&
+ status == 0)
+ sleep(1);
+ }
+#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
+
+ return 0;
+}
+
+
+void driver_wired_deinit_common(struct driver_wired_common_data *common)
+{
+ int flags;
+
+ if (common->membership &&
+ wired_multicast_membership(common->pf_sock,
+ if_nametoindex(common->ifname),
+ pae_group_addr, 0) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "%s: Failed to remove PAE multicast group (PACKET)",
+ __func__);
+ }
+
+ if (common->multi &&
+ driver_wired_multi(common->ifname, pae_group_addr, 0) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "%s: Failed to remove PAE multicast group (SIOCDELMULTI)",
+ __func__);
+ }
+
+ if (common->iff_allmulti &&
+ (driver_wired_get_ifflags(common->ifname, &flags) < 0 ||
+ driver_wired_set_ifflags(common->ifname,
+ flags & ~IFF_ALLMULTI) < 0)) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to disable allmulti mode",
+ __func__);
+ }
+
+ if (common->iff_up &&
+ driver_wired_get_ifflags(common->ifname, &flags) == 0 &&
+ (flags & IFF_UP) &&
+ driver_wired_set_ifflags(common->ifname, flags & ~IFF_UP) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to set the interface down",
+ __func__);
+ }
+
+ if (common->pf_sock != -1)
+ close(common->pf_sock);
+}
diff --git a/src/drivers/driver_wired_common.h b/src/drivers/driver_wired_common.h
new file mode 100644
index 0000000..2bb0710
--- /dev/null
+++ b/src/drivers/driver_wired_common.h
@@ -0,0 +1,34 @@
+/*
+ * Common definitions for Wired Ethernet driver interfaces
+ * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004, Gunter Burchardt <tira@isx.de>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DRIVER_WIRED_COMMON_H
+#define DRIVER_WIRED_COMMON_H
+
+struct driver_wired_common_data {
+ char ifname[IFNAMSIZ + 1];
+ void *ctx;
+
+ int sock; /* raw packet socket for driver access */
+ int pf_sock;
+ int membership, multi, iff_allmulti, iff_up;
+};
+
+static const u8 pae_group_addr[ETH_ALEN] =
+{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
+
+int wired_multicast_membership(int sock, int ifindex, const u8 *addr, int add);
+int driver_wired_get_ssid(void *priv, u8 *ssid);
+int driver_wired_get_bssid(void *priv, u8 *bssid);
+int driver_wired_get_capa(void *priv, struct wpa_driver_capa *capa);
+
+int driver_wired_init_common(struct driver_wired_common_data *common,
+ const char *ifname, void *ctx);
+void driver_wired_deinit_common(struct driver_wired_common_data *common);
+
+#endif /* DRIVER_WIRED_COMMON_H */
diff --git a/src/drivers/drivers.c b/src/drivers/drivers.c
index 00773a7..e95df6d 100644
--- a/src/drivers/drivers.c
+++ b/src/drivers/drivers.c
@@ -34,6 +34,9 @@
#ifdef CONFIG_DRIVER_WIRED
&wpa_driver_wired_ops,
#endif /* CONFIG_DRIVER_WIRED */
+#ifdef CONFIG_DRIVER_MACSEC_LINUX
+ &wpa_driver_macsec_linux_ops,
+#endif /* CONFIG_DRIVER_MACSEC_LINUX */
#ifdef CONFIG_DRIVER_MACSEC_QCA
&wpa_driver_macsec_qca_ops,
#endif /* CONFIG_DRIVER_MACSEC_QCA */
diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak
index c6d3f81..1496b47 100644
--- a/src/drivers/drivers.mak
+++ b/src/drivers/drivers.mak
@@ -15,11 +15,24 @@
ifdef CONFIG_DRIVER_WIRED
DRV_CFLAGS += -DCONFIG_DRIVER_WIRED
DRV_OBJS += ../src/drivers/driver_wired.o
+NEED_DRV_WIRED_COMMON=1
+endif
+
+ifdef CONFIG_DRIVER_MACSEC_LINUX
+DRV_CFLAGS += -DCONFIG_DRIVER_MACSEC_LINUX
+DRV_OBJS += ../src/drivers/driver_macsec_linux.o
+NEED_DRV_WIRED_COMMON=1
+CONFIG_LIBNL3_ROUTE=y
endif
ifdef CONFIG_DRIVER_MACSEC_QCA
DRV_CFLAGS += -DCONFIG_DRIVER_MACSEC_QCA
DRV_OBJS += ../src/drivers/driver_macsec_qca.o
+NEED_DRV_WIRED_COMMON=1
+endif
+
+ifdef NEED_DRV_WIRED_COMMON
+DRV_OBJS += ../src/drivers/driver_wired_common.o
endif
ifdef CONFIG_DRIVER_NL80211
diff --git a/src/drivers/drivers.mk b/src/drivers/drivers.mk
index c6fe4c2..cd25133 100644
--- a/src/drivers/drivers.mk
+++ b/src/drivers/drivers.mk
@@ -15,6 +15,18 @@
ifdef CONFIG_DRIVER_WIRED
DRV_CFLAGS += -DCONFIG_DRIVER_WIRED
DRV_OBJS += src/drivers/driver_wired.c
+NEED_DRV_WIRED_COMMON=1
+endif
+
+ifdef CONFIG_DRIVER_MACSEC_LINUX
+DRV_CFLAGS += -DCONFIG_DRIVER_MACSEC_LINUX
+DRV_OBJS += src/drivers/driver_macsec_linux.c
+NEED_DRV_WIRED_COMMON=1
+CONFIG_LIBNL3_ROUTE=y
+endif
+
+ifdef NEED_DRV_WIRED_COMMON
+DRV_OBJS += src/drivers/driver_wired_common.c
endif
ifdef CONFIG_DRIVER_NL80211
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index a268a00..259c9c7 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -600,6 +600,20 @@
*
* @NL80211_CMD_SET_WDS_PEER: Set the MAC address of the peer on a WDS interface.
*
+ * @NL80211_CMD_SET_MULTICAST_TO_UNICAST: Configure if this AP should perform
+ * multicast to unicast conversion. When enabled, all multicast packets
+ * with ethertype ARP, IPv4 or IPv6 (possibly within an 802.1Q header)
+ * will be sent out to each station once with the destination (multicast)
+ * MAC address replaced by the station's MAC address. Note that this may
+ * break certain expectations of the receiver, e.g. the ability to drop
+ * unicast IP packets encapsulated in multicast L2 frames, or the ability
+ * to not send destination unreachable messages in such cases.
+ * This can only be toggled per BSS. Configure this on an interface of
+ * type %NL80211_IFTYPE_AP. It applies to all its VLAN interfaces
+ * (%NL80211_IFTYPE_AP_VLAN), except for those in 4addr (WDS) mode.
+ * If %NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED is not present with this
+ * command, the feature is disabled.
+ *
* @NL80211_CMD_JOIN_MESH: Join a mesh. The mesh ID must be given, and initial
* mesh config parameters may be given.
* @NL80211_CMD_LEAVE_MESH: Leave the mesh network -- no special arguments, the
@@ -874,6 +888,12 @@
* This will contain a %NL80211_ATTR_NAN_MATCH nested attribute and
* %NL80211_ATTR_COOKIE.
*
+ * @NL80211_CMD_UPDATE_CONNECT_PARAMS: Update one or more connect parameters
+ * for subsequent roaming cases if the driver or firmware uses internal
+ * BSS selection. This command can be issued only while connected and it
+ * does not result in a change for the current association. Currently,
+ * only the %NL80211_ATTR_IE data is used and updated with this command.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -1069,6 +1089,10 @@
NL80211_CMD_CHANGE_NAN_CONFIG,
NL80211_CMD_NAN_MATCH,
+ NL80211_CMD_SET_MULTICAST_TO_UNICAST,
+
+ NL80211_CMD_UPDATE_CONNECT_PARAMS,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -1950,6 +1974,9 @@
* Request/Response frame protection. This attribute contains the 16 octet
* STA Nonce followed by 16 octets of AP Nonce.
*
+ * @NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED: Indicates whether or not multicast
+ * packets should be send out as unicast to all stations (flag attribute).
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2352,6 +2379,8 @@
NL80211_ATTR_FILS_KEK,
NL80211_ATTR_FILS_NONCES,
+ NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
diff --git a/src/pae/ieee802_1x_cp.c b/src/pae/ieee802_1x_cp.c
index e294e64..360fcd3 100644
--- a/src/pae/ieee802_1x_cp.c
+++ b/src/pae/ieee802_1x_cp.c
@@ -159,6 +159,7 @@
secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
secy_cp_control_protect_frames(sm->kay, sm->protect_frames);
+ secy_cp_control_encrypt(sm->kay, sm->kay->macsec_encrypt);
secy_cp_control_validate_frames(sm->kay, sm->validate_frames);
secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window);
}
@@ -177,6 +178,7 @@
secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
secy_cp_control_protect_frames(sm->kay, sm->protect_frames);
+ secy_cp_control_encrypt(sm->kay, sm->kay->macsec_encrypt);
secy_cp_control_validate_frames(sm->kay, sm->validate_frames);
secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window);
}
@@ -203,6 +205,7 @@
secy_cp_control_confidentiality_offset(sm->kay,
sm->confidentiality_offset);
secy_cp_control_protect_frames(sm->kay, sm->protect_frames);
+ secy_cp_control_encrypt(sm->kay, sm->kay->macsec_encrypt);
secy_cp_control_validate_frames(sm->kay, sm->validate_frames);
secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window);
}
@@ -466,6 +469,7 @@
wpa_printf(MSG_DEBUG, "CP: state machine created");
secy_cp_control_protect_frames(sm->kay, sm->protect_frames);
+ secy_cp_control_encrypt(sm->kay, sm->kay->macsec_encrypt);
secy_cp_control_validate_frames(sm->kay, sm->validate_frames);
secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window);
secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
diff --git a/src/pae/ieee802_1x_kay.c b/src/pae/ieee802_1x_kay.c
index 63bbd13..1d6d9a9 100644
--- a/src/pae/ieee802_1x_kay.c
+++ b/src/pae/ieee802_1x_kay.c
@@ -379,6 +379,17 @@
}
+u64 mka_sci_u64(struct ieee802_1x_mka_sci *sci)
+{
+ struct ieee802_1x_mka_sci tmp;
+
+ os_memcpy(tmp.addr, sci->addr, ETH_ALEN);
+ tmp.port = sci->port;
+
+ return *((u64 *) &tmp);
+}
+
+
static Boolean sci_equal(const struct ieee802_1x_mka_sci *a,
const struct ieee802_1x_mka_sci *b)
{
@@ -3071,7 +3082,7 @@
*/
struct ieee802_1x_kay *
ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
- const char *ifname, const u8 *addr)
+ u16 port, const char *ifname, const u8 *addr)
{
struct ieee802_1x_kay *kay;
@@ -3093,7 +3104,7 @@
os_strlcpy(kay->if_name, ifname, IFNAMSIZ);
os_memcpy(kay->actor_sci.addr, addr, ETH_ALEN);
- kay->actor_sci.port = host_to_be16(0x0001);
+ kay->actor_sci.port = host_to_be16(port ? port : 0x0001);
kay->actor_priority = DEFAULT_PRIO_NOT_KEY_SERVER;
/* While actor acts as a key server, shall distribute sakey */
@@ -3111,7 +3122,14 @@
dl_list_init(&kay->participant_list);
- if (policy == DO_NOT_SECURE) {
+ if (policy != DO_NOT_SECURE &&
+ secy_get_capability(kay, &kay->macsec_capable) < 0) {
+ os_free(kay);
+ return NULL;
+ }
+
+ if (policy == DO_NOT_SECURE ||
+ kay->macsec_capable == MACSEC_CAP_NOT_IMPLEMENTED) {
kay->macsec_capable = MACSEC_CAP_NOT_IMPLEMENTED;
kay->macsec_desired = FALSE;
kay->macsec_protect = FALSE;
@@ -3120,20 +3138,16 @@
kay->macsec_replay_window = 0;
kay->macsec_confidentiality = CONFIDENTIALITY_NONE;
} else {
- if (secy_get_capability(kay, &kay->macsec_capable) < 0) {
- os_free(kay);
- return NULL;
- }
-
kay->macsec_desired = TRUE;
kay->macsec_protect = TRUE;
+ kay->macsec_encrypt = policy == SHOULD_ENCRYPT;
kay->macsec_validate = Strict;
kay->macsec_replay_protect = FALSE;
kay->macsec_replay_window = 0;
if (kay->macsec_capable >= MACSEC_CAP_INTEG_AND_CONF)
kay->macsec_confidentiality = CONFIDENTIALITY_OFFSET_0;
else
- kay->macsec_confidentiality = MACSEC_CAP_INTEGRITY;
+ kay->macsec_confidentiality = CONFIDENTIALITY_NONE;
}
wpa_printf(MSG_DEBUG, "KaY: state machine created");
@@ -3337,8 +3351,16 @@
usecs = os_random() % (MKA_HELLO_TIME * 1000);
eloop_register_timeout(0, usecs, ieee802_1x_participant_timer,
participant, NULL);
- participant->mka_life = MKA_LIFE_TIME / 1000 + time(NULL) +
- usecs / 1000000;
+
+ /* Disable MKA lifetime for PSK mode.
+ * The peer(s) can take a long time to come up, because we
+ * create a "standby" MKA, and we need it to remain live until
+ * some peer appears.
+ */
+ if (mode != PSK) {
+ participant->mka_life = MKA_LIFE_TIME / 1000 + time(NULL) +
+ usecs / 1000000;
+ }
return participant;
diff --git a/src/pae/ieee802_1x_kay.h b/src/pae/ieee802_1x_kay.h
index 576a8a0..9a92d1c 100644
--- a/src/pae/ieee802_1x_kay.h
+++ b/src/pae/ieee802_1x_kay.h
@@ -142,6 +142,7 @@
int (*macsec_deinit)(void *ctx);
int (*macsec_get_capability)(void *priv, enum macsec_cap *cap);
int (*enable_protect_frames)(void *ctx, Boolean enabled);
+ int (*enable_encrypt)(void *ctx, Boolean enabled);
int (*set_replay_protect)(void *ctx, Boolean enabled, u32 window);
int (*set_current_cipher_suite)(void *ctx, u64 cs);
int (*enable_controlled_port)(void *ctx, Boolean enabled);
@@ -181,6 +182,7 @@
enum macsec_cap macsec_capable;
Boolean macsec_desired;
Boolean macsec_protect;
+ Boolean macsec_encrypt;
Boolean macsec_replay_protect;
u32 macsec_replay_window;
enum validate_frames macsec_validate;
@@ -229,9 +231,11 @@
};
+u64 mka_sci_u64(struct ieee802_1x_mka_sci *sci);
+
struct ieee802_1x_kay *
ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
- const char *ifname, const u8 *addr);
+ u16 port, const char *ifname, const u8 *addr);
void ieee802_1x_kay_deinit(struct ieee802_1x_kay *kay);
struct ieee802_1x_mka_participant *
diff --git a/src/pae/ieee802_1x_secy_ops.c b/src/pae/ieee802_1x_secy_ops.c
index b1a9d22..ab5339b 100644
--- a/src/pae/ieee802_1x_secy_ops.c
+++ b/src/pae/ieee802_1x_secy_ops.c
@@ -45,6 +45,26 @@
}
+int secy_cp_control_encrypt(struct ieee802_1x_kay *kay, Boolean enabled)
+{
+ struct ieee802_1x_kay_ctx *ops;
+
+ if (!kay) {
+ wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
+ return -1;
+ }
+
+ ops = kay->ctx;
+ if (!ops || !ops->enable_encrypt) {
+ wpa_printf(MSG_ERROR,
+ "KaY: secy enable_encrypt operation not supported");
+ return -1;
+ }
+
+ return ops->enable_encrypt(ops->ctx, enabled);
+}
+
+
int secy_cp_control_replay(struct ieee802_1x_kay *kay, Boolean enabled, u32 win)
{
struct ieee802_1x_kay_ctx *ops;
diff --git a/src/pae/ieee802_1x_secy_ops.h b/src/pae/ieee802_1x_secy_ops.h
index 477120b..9fb29c3 100644
--- a/src/pae/ieee802_1x_secy_ops.h
+++ b/src/pae/ieee802_1x_secy_ops.h
@@ -21,6 +21,7 @@
int secy_cp_control_validate_frames(struct ieee802_1x_kay *kay,
enum validate_frames vf);
int secy_cp_control_protect_frames(struct ieee802_1x_kay *kay, Boolean flag);
+int secy_cp_control_encrypt(struct ieee802_1x_kay *kay, Boolean enabled);
int secy_cp_control_replay(struct ieee802_1x_kay *kay, Boolean flag, u32 win);
int secy_cp_control_current_cipher_suite(struct ieee802_1x_kay *kay, u64 cs);
int secy_cp_control_confidentiality_offset(struct ieee802_1x_kay *kay,
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 1a25d08..31f017b 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -1596,9 +1596,7 @@
# With BoringSSL we need libkeystore-engine in order to provide access to
# keystore keys.
-ifneq (,$(wildcard external/boringssl/flavor.mk))
LOCAL_SHARED_LIBRARIES += libkeystore-engine
-endif
ifdef CONFIG_DRIVER_NL80211
ifneq ($(wildcard external/libnl),)
diff --git a/wpa_supplicant/README b/wpa_supplicant/README
index 11ab01a..54564f6 100644
--- a/wpa_supplicant/README
+++ b/wpa_supplicant/README
@@ -965,6 +965,17 @@
also possible to run multiple wpa_priv processes at the same time, if
desired.
+It should be noted that the interface used between wpa_supplicant and
+wpa_priv does not include all the capabilities of the wpa_supplicant
+driver interface and at times, this interface lacks update especially
+for recent addition. Consequently, use of wpa_priv does come with the
+price of somewhat reduced available functionality. The next section
+describing how wpa_supplicant can be used with reduced privileges
+without having to handle the complexity of separate wpa_priv. While that
+approve does not provide separation for network admin capabilities, it
+does allow other root privileges to be dropped without the drawbacks of
+the wpa_priv process.
+
Linux capabilities instead of privileged process
------------------------------------------------
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 3a8778d..44a9a7b 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -595,6 +595,42 @@
{
u32 changes;
+ if (bss->last_update_idx == wpa_s->bss_update_idx) {
+ struct os_reltime update_time;
+
+ /*
+ * Some drivers (e.g., cfg80211) include multiple BSS entries
+ * for the same BSS if that BSS's channel changes. The BSS list
+ * implementation in wpa_supplicant does not do that and we need
+ * to filter out the obsolete results here to make sure only the
+ * most current BSS information remains in the table.
+ */
+ wpa_printf(MSG_DEBUG, "BSS: " MACSTR
+ " has multiple entries in the scan results - select the most current one",
+ MAC2STR(bss->bssid));
+ calculate_update_time(fetch_time, res->age, &update_time);
+ wpa_printf(MSG_DEBUG,
+ "Previous last_update: %u.%06u (freq %d%s)",
+ (unsigned int) bss->last_update.sec,
+ (unsigned int) bss->last_update.usec,
+ bss->freq,
+ (bss->flags & WPA_BSS_ASSOCIATED) ? " assoc" : "");
+ wpa_printf(MSG_DEBUG, "New last_update: %u.%06u (freq %d%s)",
+ (unsigned int) update_time.sec,
+ (unsigned int) update_time.usec,
+ res->freq,
+ (res->flags & WPA_SCAN_ASSOCIATED) ? " assoc" : "");
+ if ((bss->flags & WPA_BSS_ASSOCIATED) ||
+ (!(res->flags & WPA_SCAN_ASSOCIATED) &&
+ !os_reltime_before(&bss->last_update, &update_time))) {
+ wpa_printf(MSG_DEBUG,
+ "Ignore this BSS entry since the previous update looks more current");
+ return bss;
+ }
+ wpa_printf(MSG_DEBUG,
+ "Accept this BSS entry since it looks more current than the previous update");
+ }
+
changes = wpa_bss_compare_res(bss, res);
if (changes & WPA_BSS_FREQ_CHANGED_FLAG)
wpa_printf(MSG_DEBUG, "BSS: " MACSTR " changed freq %d --> %d",
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index a0b64b2..2120a6e 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -1828,6 +1828,69 @@
#endif /* CONFIG_MESH */
+#ifdef CONFIG_MACSEC
+
+static int wpa_config_parse_mka_cak(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ if (hexstr2bin(value, ssid->mka_cak, MACSEC_CAK_LEN) ||
+ value[MACSEC_CAK_LEN * 2] != '\0') {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CAK '%s'.",
+ line, value);
+ return -1;
+ }
+
+ ssid->mka_psk_set |= MKA_PSK_SET_CAK;
+
+ wpa_hexdump_key(MSG_MSGDUMP, "MKA-CAK", ssid->mka_cak, MACSEC_CAK_LEN);
+ return 0;
+}
+
+
+static int wpa_config_parse_mka_ckn(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ if (hexstr2bin(value, ssid->mka_ckn, MACSEC_CKN_LEN) ||
+ value[MACSEC_CKN_LEN * 2] != '\0') {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CKN '%s'.",
+ line, value);
+ return -1;
+ }
+
+ ssid->mka_psk_set |= MKA_PSK_SET_CKN;
+
+ wpa_hexdump_key(MSG_MSGDUMP, "MKA-CKN", ssid->mka_ckn, MACSEC_CKN_LEN);
+ return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+
+static char * wpa_config_write_mka_cak(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ if (!(ssid->mka_psk_set & MKA_PSK_SET_CAK))
+ return NULL;
+
+ return wpa_config_write_string_hex(ssid->mka_cak, MACSEC_CAK_LEN);
+}
+
+
+static char * wpa_config_write_mka_ckn(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ if (!(ssid->mka_psk_set & MKA_PSK_SET_CKN))
+ return NULL;
+ return wpa_config_write_string_hex(ssid->mka_ckn, MACSEC_CKN_LEN);
+}
+
+#endif /* NO_CONFIG_WRITE */
+
+#endif /* CONFIG_MACSEC */
+
+
/* Helper macros for network block parser */
#ifdef OFFSET
@@ -2062,6 +2125,10 @@
{ INT(beacon_int) },
#ifdef CONFIG_MACSEC
{ INT_RANGE(macsec_policy, 0, 1) },
+ { INT_RANGE(macsec_integ_only, 0, 1) },
+ { INT_RANGE(macsec_port, 1, 65534) },
+ { FUNC_KEY(mka_cak) },
+ { FUNC_KEY(mka_ckn) },
#endif /* CONFIG_MACSEC */
#ifdef CONFIG_HS20
{ INT(update_identifier) },
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 7ae1654..2e3d57e 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -662,6 +662,40 @@
#endif /* CONFIG_P2P */
+#ifdef CONFIG_MACSEC
+
+static void write_mka_cak(FILE *f, struct wpa_ssid *ssid)
+{
+ char *value;
+
+ if (!(ssid->mka_psk_set & MKA_PSK_SET_CAK))
+ return;
+
+ value = wpa_config_get(ssid, "mka_cak");
+ if (!value)
+ return;
+ fprintf(f, "\tmka_cak=%s\n", value);
+ os_free(value);
+}
+
+
+static void write_mka_ckn(FILE *f, struct wpa_ssid *ssid)
+{
+ char *value;
+
+ if (!(ssid->mka_psk_set & MKA_PSK_SET_CKN))
+ return;
+
+ value = wpa_config_get(ssid, "mka_ckn");
+ if (!value)
+ return;
+ fprintf(f, "\tmka_ckn=%s\n", value);
+ os_free(value);
+}
+
+#endif /* CONFIG_MACSEC */
+
+
static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
{
int i;
@@ -772,6 +806,10 @@
INT(beacon_int);
#ifdef CONFIG_MACSEC
INT(macsec_policy);
+ write_mka_cak(f, ssid);
+ write_mka_ckn(f, ssid);
+ INT(macsec_integ_only);
+ INT(macsec_port);
#endif /* CONFIG_MACSEC */
#ifdef CONFIG_HS20
INT(update_identifier);
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index 010b594..fe0f7fa 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -728,6 +728,47 @@
* determine whether to use a secure session or not.
*/
int macsec_policy;
+
+ /**
+ * macsec_integ_only - Determines how MACsec are transmitted
+ *
+ * This setting applies only when MACsec is in use, i.e.,
+ * - macsec_policy is enabled
+ * - the key server has decided to enable MACsec
+ *
+ * 0: Encrypt traffic (default)
+ * 1: Integrity only
+ */
+ int macsec_integ_only;
+
+ /**
+ * macsec_port - MACsec port (in SCI)
+ *
+ * Port component of the SCI.
+ *
+ * Range: 1-65534 (default: 1)
+ */
+ int macsec_port;
+
+ /**
+ * mka_ckn - MKA pre-shared CKN
+ */
+#define MACSEC_CKN_LEN 32
+ u8 mka_ckn[MACSEC_CKN_LEN];
+
+ /**
+ * mka_cak - MKA pre-shared CAK
+ */
+#define MACSEC_CAK_LEN 16
+ u8 mka_cak[MACSEC_CAK_LEN];
+
+#define MKA_PSK_SET_CKN BIT(0)
+#define MKA_PSK_SET_CAK BIT(1)
+#define MKA_PSK_SET (MKA_PSK_SET_CKN | MKA_PSK_SET_CAK)
+ /**
+ * mka_psk_set - Whether mka_ckn and mka_cak are set
+ */
+ u8 mka_psk_set;
#endif /* CONFIG_MACSEC */
#ifdef CONFIG_HS20
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index 27b3012..69fb8f4 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -1256,9 +1256,12 @@
* @wpa_s: %wpa_supplicant network interface data
* @client: this device is P2P client
* @persistent: 0 - non persistent group, 1 - persistent group
+ * @ip: When group role is client, it contains local IP address, netmask, and
+ * GO's IP address, if assigned; otherwise, NULL
*/
void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
- int client, int persistent)
+ int client, int persistent,
+ const u8 *ip)
{
DBusMessage *msg;
DBusMessageIter iter, dict_iter;
@@ -1300,6 +1303,13 @@
!wpa_dbus_dict_append_bool(&dict_iter, "persistent", persistent) ||
!wpa_dbus_dict_append_object_path(&dict_iter, "group_object",
wpa_s->dbus_groupobj_path) ||
+ (ip &&
+ (!wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddr",
+ (char *) ip, 4) ||
+ !wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddrMask",
+ (char *) ip + 4, 4) ||
+ !wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddrGo",
+ (char *) ip + 8, 4))) ||
!wpa_dbus_dict_close_write(&iter, &dict_iter)) {
wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
} else {
diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h
index d64fcee..2b0b775 100644
--- a/wpa_supplicant/dbus/dbus_new.h
+++ b/wpa_supplicant/dbus/dbus_new.h
@@ -190,7 +190,8 @@
const u8 *src, u16 dev_passwd_id,
u8 go_intent);
void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
- int client, int persistent);
+ int client, int persistent,
+ const u8 *ip);
void wpas_dbus_signal_p2p_group_formation_failure(struct wpa_supplicant *wpa_s,
const char *reason);
void wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s,
@@ -400,7 +401,8 @@
static inline void
wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
- int client, int persistent)
+ int client, int persistent,
+ const u8 *ip)
{
}
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index 73b9e20..f50420b 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -28,6 +28,18 @@
#include "../p2p_supplicant.h"
#include "../wifi_display.h"
+
+static int wpas_dbus_validate_dbus_ipaddr(struct wpa_dbus_dict_entry entry)
+{
+ if (entry.type != DBUS_TYPE_ARRAY ||
+ entry.array_type != DBUS_TYPE_BYTE ||
+ entry.array_len != 4)
+ return 0;
+
+ return 1;
+}
+
+
/**
* Parses out the mac address from the peer object path.
* @peer_path - object path of the form
@@ -867,6 +879,35 @@
goto err_no_mem;
}
+ /* GO IP address */
+ if (WPA_GET_BE32(wpa_s->conf->ip_addr_go) &&
+ !wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddrGo",
+ (char *) wpa_s->conf->ip_addr_go,
+ 4))
+ goto err_no_mem;
+
+ /* IP address mask */
+ if (WPA_GET_BE32(wpa_s->conf->ip_addr_mask) &&
+ !wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddrMask",
+ (char *) wpa_s->conf->ip_addr_mask,
+ 4))
+ goto err_no_mem;
+
+ /* IP address start */
+ if (WPA_GET_BE32(wpa_s->conf->ip_addr_start) &&
+ !wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddrStart",
+ (char *)
+ wpa_s->conf->ip_addr_start,
+ 4))
+ goto err_no_mem;
+
+ /* IP address end */
+ if (WPA_GET_BE32(wpa_s->conf->ip_addr_end) &&
+ !wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddrEnd",
+ (char *) wpa_s->conf->ip_addr_end,
+ 4))
+ goto err_no_mem;
+
/* Vendor Extensions */
for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
if (wpa_s->conf->wps_vendor_ext[i] == NULL)
@@ -1051,6 +1092,26 @@
wpa_s->conf->p2p_intra_bss = entry.bool_value;
wpa_s->conf->changed_parameters |=
CFG_CHANGED_P2P_INTRA_BSS;
+ } else if (os_strcmp(entry.key, "IpAddrGo") == 0) {
+ if (!wpas_dbus_validate_dbus_ipaddr(entry))
+ goto error;
+ os_memcpy(wpa_s->conf->ip_addr_go,
+ entry.bytearray_value, 4);
+ } else if (os_strcmp(entry.key, "IpAddrMask") == 0) {
+ if (!wpas_dbus_validate_dbus_ipaddr(entry))
+ goto error;
+ os_memcpy(wpa_s->conf->ip_addr_mask,
+ entry.bytearray_value, 4);
+ } else if (os_strcmp(entry.key, "IpAddrStart") == 0) {
+ if (!wpas_dbus_validate_dbus_ipaddr(entry))
+ goto error;
+ os_memcpy(wpa_s->conf->ip_addr_start,
+ entry.bytearray_value, 4);
+ } else if (os_strcmp(entry.key, "IpAddrEnd") == 0) {
+ if (!wpas_dbus_validate_dbus_ipaddr(entry))
+ goto error;
+ os_memcpy(wpa_s->conf->ip_addr_end,
+ entry.bytearray_value, 4);
} else if (os_strcmp(entry.key, "GroupIdle") == 0 &&
entry.type == DBUS_TYPE_UINT32)
wpa_s->conf->p2p_group_idle = entry.uint32_value;
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index c9bb20d..4758c16 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -731,6 +731,14 @@
return wpa_s->driver->enable_protect_frames(wpa_s->drv_priv, enabled);
}
+static inline int wpa_drv_enable_encrypt(struct wpa_supplicant *wpa_s,
+ Boolean enabled)
+{
+ if (!wpa_s->driver->enable_encrypt)
+ return -1;
+ return wpa_s->driver->enable_encrypt(wpa_s->drv_priv, enabled);
+}
+
static inline int wpa_drv_set_replay_protect(struct wpa_supplicant *wpa_s,
Boolean enabled, u32 window)
{
@@ -908,11 +916,12 @@
return wpa_s->driver->set_prob_oper_freq(wpa_s->drv_priv, freq);
}
-static inline int wpa_drv_abort_scan(struct wpa_supplicant *wpa_s)
+static inline int wpa_drv_abort_scan(struct wpa_supplicant *wpa_s,
+ u64 scan_cookie)
{
if (!wpa_s->driver->abort_scan)
return -1;
- return wpa_s->driver->abort_scan(wpa_s->drv_priv);
+ return wpa_s->driver->abort_scan(wpa_s->drv_priv, scan_cookie);
}
static inline int wpa_drv_configure_frame_filters(struct wpa_supplicant *wpa_s,
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 17f057a..67438e5 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -503,7 +503,7 @@
static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
- struct wpa_bss *bss)
+ struct wpa_bss *bss, int debug_print)
{
struct wpa_ie_data ie;
int proto_match = 0;
@@ -526,40 +526,46 @@
proto_match++;
if (wpa_parse_wpa_ie(rsn_ie, 2 + rsn_ie[1], &ie)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - parse "
- "failed");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip RSN IE - parse failed");
break;
}
if (wep_ok &&
(ie.group_cipher & (WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)))
{
- wpa_dbg(wpa_s, MSG_DEBUG, " selected based on TSN "
- "in RSN IE");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " selected based on TSN in RSN IE");
return 1;
}
if (!(ie.proto & ssid->proto)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - proto "
- "mismatch");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip RSN IE - proto mismatch");
break;
}
if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - PTK "
- "cipher mismatch");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip RSN IE - PTK cipher mismatch");
break;
}
if (!(ie.group_cipher & ssid->group_cipher)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - GTK "
- "cipher mismatch");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip RSN IE - GTK cipher mismatch");
break;
}
if (!(ie.key_mgmt & ssid->key_mgmt)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - key mgmt "
- "mismatch");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip RSN IE - key mgmt mismatch");
break;
}
@@ -567,16 +573,18 @@
if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
wpas_get_ssid_pmf(wpa_s, ssid) ==
MGMT_FRAME_PROTECTION_REQUIRED) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - no mgmt "
- "frame protection");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip RSN IE - no mgmt frame protection");
break;
}
#endif /* CONFIG_IEEE80211W */
if ((ie.capabilities & WPA_CAPABILITY_MFPR) &&
wpas_get_ssid_pmf(wpa_s, ssid) ==
NO_MGMT_FRAME_PROTECTION) {
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip RSN IE - no mgmt frame protection enabled but AP requires it");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip RSN IE - no mgmt frame protection enabled but AP requires it");
break;
}
#ifdef CONFIG_MBO
@@ -584,20 +592,24 @@
wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_AP_CAPA_IND) &&
wpas_get_ssid_pmf(wpa_s, ssid) !=
NO_MGMT_FRAME_PROTECTION) {
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip RSN IE - no mgmt frame protection enabled on MBO AP");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip RSN IE - no mgmt frame protection enabled on MBO AP");
break;
}
#endif /* CONFIG_MBO */
- wpa_dbg(wpa_s, MSG_DEBUG, " selected based on RSN IE");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " selected based on RSN IE");
return 1;
}
#ifdef CONFIG_IEEE80211W
if (wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) {
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - MFP Required but network not MFP Capable");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - MFP Required but network not MFP Capable");
return 0;
}
#endif /* CONFIG_IEEE80211W */
@@ -607,72 +619,87 @@
proto_match++;
if (wpa_parse_wpa_ie(wpa_ie, 2 + wpa_ie[1], &ie)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip WPA IE - parse "
- "failed");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip WPA IE - parse failed");
break;
}
if (wep_ok &&
(ie.group_cipher & (WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)))
{
- wpa_dbg(wpa_s, MSG_DEBUG, " selected based on TSN "
- "in WPA IE");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " selected based on TSN in WPA IE");
return 1;
}
if (!(ie.proto & ssid->proto)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip WPA IE - proto "
- "mismatch");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip WPA IE - proto mismatch");
break;
}
if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip WPA IE - PTK "
- "cipher mismatch");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip WPA IE - PTK cipher mismatch");
break;
}
if (!(ie.group_cipher & ssid->group_cipher)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip WPA IE - GTK "
- "cipher mismatch");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip WPA IE - GTK cipher mismatch");
break;
}
if (!(ie.key_mgmt & ssid->key_mgmt)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip WPA IE - key mgmt "
- "mismatch");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip WPA IE - key mgmt mismatch");
break;
}
- wpa_dbg(wpa_s, MSG_DEBUG, " selected based on WPA IE");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " selected based on WPA IE");
return 1;
}
if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && !wpa_ie &&
!rsn_ie) {
- wpa_dbg(wpa_s, MSG_DEBUG, " allow for non-WPA IEEE 802.1X");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " allow for non-WPA IEEE 802.1X");
return 1;
}
if ((ssid->proto & (WPA_PROTO_WPA | WPA_PROTO_RSN)) &&
wpa_key_mgmt_wpa(ssid->key_mgmt) && proto_match == 0) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - no WPA/RSN proto match");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - no WPA/RSN proto match");
return 0;
}
if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) &&
wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " allow in OSEN");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " allow in OSEN");
return 1;
}
if (!wpa_key_mgmt_wpa(ssid->key_mgmt)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " allow in non-WPA/WPA2");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " allow in non-WPA/WPA2");
return 1;
}
- wpa_dbg(wpa_s, MSG_DEBUG, " reject due to mismatch with "
- "WPA/WPA2");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " reject due to mismatch with WPA/WPA2");
return 0;
}
@@ -692,7 +719,8 @@
}
-static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+ int debug_print)
{
const struct hostapd_hw_modes *mode = NULL, *modes;
const u8 scan_ie[2] = { WLAN_EID_SUPP_RATES, WLAN_EID_EXT_SUPP_RATES };
@@ -749,9 +777,9 @@
if (flagged && ((rate_ie[j] & 0x7f) ==
BSS_MEMBERSHIP_SELECTOR_HT_PHY)) {
if (!ht_supported(mode)) {
- wpa_dbg(wpa_s, MSG_DEBUG,
- " hardware does not support "
- "HT PHY");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " hardware does not support HT PHY");
return 0;
}
continue;
@@ -761,9 +789,9 @@
if (flagged && ((rate_ie[j] & 0x7f) ==
BSS_MEMBERSHIP_SELECTOR_VHT_PHY)) {
if (!vht_supported(mode)) {
- wpa_dbg(wpa_s, MSG_DEBUG,
- " hardware does not support "
- "VHT PHY");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " hardware does not support VHT PHY");
return 0;
}
continue;
@@ -783,10 +811,11 @@
* order to join a BSS all required rates
* have to be supported by the hardware.
*/
- wpa_dbg(wpa_s, MSG_DEBUG,
- " hardware does not support required rate %d.%d Mbps (freq=%d mode==%d num_rates=%d)",
- r / 10, r % 10,
- bss->freq, mode->mode, mode->num_rates);
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " hardware does not support required rate %d.%d Mbps (freq=%d mode==%d num_rates=%d)",
+ r / 10, r % 10,
+ bss->freq, mode->mode, mode->num_rates);
return 0;
}
}
@@ -842,7 +871,7 @@
struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
int i, struct wpa_bss *bss,
struct wpa_ssid *group,
- int only_first_ssid)
+ int only_first_ssid, int debug_print)
{
u8 wpa_ie_len, rsn_ie_len;
int wpa;
@@ -863,15 +892,20 @@
ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
osen = ie != NULL;
- wpa_dbg(wpa_s, MSG_DEBUG, "%d: " MACSTR " ssid='%s' "
- "wpa_ie_len=%u rsn_ie_len=%u caps=0x%x level=%d freq=%d %s%s%s",
- i, MAC2STR(bss->bssid), wpa_ssid_txt(bss->ssid, bss->ssid_len),
- wpa_ie_len, rsn_ie_len, bss->caps, bss->level, bss->freq,
- wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE) ? " wps" : "",
- (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) ||
- wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) ?
- " p2p" : "",
- osen ? " osen=1" : "");
+ if (debug_print) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "%d: " MACSTR
+ " ssid='%s' wpa_ie_len=%u rsn_ie_len=%u caps=0x%x level=%d freq=%d %s%s%s",
+ i, MAC2STR(bss->bssid),
+ wpa_ssid_txt(bss->ssid, bss->ssid_len),
+ wpa_ie_len, rsn_ie_len, bss->caps, bss->level,
+ bss->freq,
+ wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE) ?
+ " wps" : "",
+ (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) ||
+ wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE))
+ ? " p2p" : "",
+ osen ? " osen=1" : "");
+ }
e = wpa_blacklist_get(wpa_s, bss->bssid);
if (e) {
@@ -888,24 +922,30 @@
limit = 0;
}
if (e->count > limit) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - blacklisted "
- "(count=%d limit=%d)", e->count, limit);
+ if (debug_print) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - blacklisted (count=%d limit=%d)",
+ e->count, limit);
+ }
return NULL;
}
}
if (bss->ssid_len == 0) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - SSID not known");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - SSID not known");
return NULL;
}
if (disallowed_bssid(wpa_s, bss->bssid)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - BSSID disallowed");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - BSSID disallowed");
return NULL;
}
if (disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - SSID disallowed");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - SSID disallowed");
return NULL;
}
@@ -916,21 +956,25 @@
int res;
if (wpas_network_disabled(wpa_s, ssid)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - disabled");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - disabled");
continue;
}
res = wpas_temp_disabled(wpa_s, ssid);
if (res > 0) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - disabled "
- "temporarily for %d second(s)", res);
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - disabled temporarily for %d second(s)",
+ res);
continue;
}
#ifdef CONFIG_WPS
if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && e && e->count > 0) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - blacklisted "
- "(WPS)");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - blacklisted (WPS)");
continue;
}
@@ -956,13 +1000,17 @@
if (check_ssid &&
(bss->ssid_len != ssid->ssid_len ||
os_memcmp(bss->ssid, ssid->ssid, bss->ssid_len) != 0)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - SSID mismatch");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - SSID mismatch");
continue;
}
if (ssid->bssid_set &&
os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - BSSID mismatch");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - BSSID mismatch");
continue;
}
@@ -970,8 +1018,9 @@
if (ssid->num_bssid_blacklist &&
addr_in_list(bss->bssid, ssid->bssid_blacklist,
ssid->num_bssid_blacklist)) {
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - BSSID blacklisted");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - BSSID blacklisted");
continue;
}
@@ -979,71 +1028,85 @@
if (ssid->num_bssid_whitelist &&
!addr_in_list(bss->bssid, ssid->bssid_whitelist,
ssid->num_bssid_whitelist)) {
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - BSSID not in whitelist");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - BSSID not in whitelist");
continue;
}
- if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss))
+ if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss,
+ debug_print))
continue;
if (!osen && !wpa &&
!(ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
!(ssid->key_mgmt & WPA_KEY_MGMT_WPS) &&
!(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - non-WPA network "
- "not allowed");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - non-WPA network not allowed");
continue;
}
if (wpa && !wpa_key_mgmt_wpa(ssid->key_mgmt) &&
has_wep_key(ssid)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - ignore WPA/WPA2 AP for WEP network block");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - ignore WPA/WPA2 AP for WEP network block");
continue;
}
if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) && !osen) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - non-OSEN network "
- "not allowed");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - non-OSEN network not allowed");
continue;
}
if (!wpa_supplicant_match_privacy(bss, ssid)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - privacy "
- "mismatch");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - privacy mismatch");
continue;
}
if (ssid->mode != IEEE80211_MODE_MESH && !bss_is_ess(bss) &&
!bss_is_pbss(bss)) {
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - not ESS, PBSS, or MBSS");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - not ESS, PBSS, or MBSS");
continue;
}
if (ssid->pbss != 2 && ssid->pbss != bss_is_pbss(bss)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - PBSS mismatch (ssid %d bss %d)",
- ssid->pbss, bss_is_pbss(bss));
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - PBSS mismatch (ssid %d bss %d)",
+ ssid->pbss, bss_is_pbss(bss));
continue;
}
if (!freq_allowed(ssid->freq_list, bss->freq)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - frequency not "
- "allowed");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - frequency not allowed");
continue;
}
#ifdef CONFIG_MESH
if (ssid->mode == IEEE80211_MODE_MESH && ssid->frequency > 0 &&
ssid->frequency != bss->freq) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - frequency not allowed (mesh)");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - frequency not allowed (mesh)");
continue;
}
#endif /* CONFIG_MESH */
- if (!rate_match(wpa_s, bss)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - rate sets do "
- "not match");
+ if (!rate_match(wpa_s, bss, debug_print)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - rate sets do not match");
continue;
}
@@ -1051,8 +1114,9 @@
if (ssid->mode == WPAS_MODE_IBSS &&
!(ssid->key_mgmt & (WPA_KEY_MGMT_NONE |
WPA_KEY_MGMT_WPA_NONE))) {
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - IBSS RSN not supported in the build");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - IBSS RSN not supported in the build");
continue;
}
#endif /* !CONFIG_IBSS_RSN */
@@ -1061,7 +1125,9 @@
if (ssid->p2p_group &&
!wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) &&
!wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - no P2P IE seen");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - no P2P IE seen");
continue;
}
@@ -1071,20 +1137,26 @@
ie = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
if (ie == NULL) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - no P2P element");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - no P2P element");
continue;
}
p2p_ie = wpa_bss_get_vendor_ie_multi(
bss, P2P_IE_VENDOR_TYPE);
if (p2p_ie == NULL) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - could not fetch P2P element");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - could not fetch P2P element");
continue;
}
if (p2p_parse_dev_addr_in_p2p_ie(p2p_ie, dev_addr) < 0
|| os_memcmp(dev_addr, ssid->go_p2p_dev_addr,
ETH_ALEN) != 0) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - no matching GO P2P Device Address in P2P element");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - no matching GO P2P Device Address in P2P element");
wpabuf_free(p2p_ie);
continue;
}
@@ -1104,8 +1176,9 @@
os_reltime_sub(&wpa_s->scan_min_time,
&bss->last_update, &diff);
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - scan result not recent enough (%u.%06u seconds too old)",
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - scan result not recent enough (%u.%06u seconds too old)",
(unsigned int) diff.sec,
(unsigned int) diff.usec);
continue;
@@ -1118,15 +1191,17 @@
assoc_disallow = wpas_mbo_get_bss_attr(
bss, MBO_ATTR_ID_ASSOC_DISALLOW);
if (assoc_disallow && assoc_disallow[1] >= 1) {
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - MBO association disallowed (reason %u)",
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - MBO association disallowed (reason %u)",
assoc_disallow[2]);
continue;
}
if (wpa_is_bss_tmp_disallowed(wpa_s, bss->bssid)) {
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - MBO retry delay has not passed yet");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - MBO retry delay has not passed yet");
continue;
}
#ifdef CONFIG_TESTING_OPTIONS
@@ -1151,6 +1226,25 @@
{
unsigned int i;
+ if (wpa_s->current_ssid) {
+ struct wpa_ssid *ssid;
+
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Scan results matching the currently selected network");
+ for (i = 0; i < wpa_s->last_scan_res_used; i++) {
+ struct wpa_bss *bss = wpa_s->last_scan_res[i];
+
+ ssid = wpa_scan_res_match(wpa_s, i, bss, group,
+ only_first_ssid, 0);
+ if (ssid != wpa_s->current_ssid)
+ continue;
+ wpa_dbg(wpa_s, MSG_DEBUG, "%u: " MACSTR
+ " freq=%d level=%d snr=%d est_throughput=%u",
+ i, MAC2STR(bss->bssid), bss->freq, bss->level,
+ bss->snr, bss->est_throughput);
+ }
+ }
+
if (only_first_ssid)
wpa_dbg(wpa_s, MSG_DEBUG, "Try to find BSS matching pre-selected network id=%d",
group->id);
@@ -1161,7 +1255,7 @@
for (i = 0; i < wpa_s->last_scan_res_used; i++) {
struct wpa_bss *bss = wpa_s->last_scan_res[i];
*selected_ssid = wpa_scan_res_match(wpa_s, i, bss, group,
- only_first_ssid);
+ only_first_ssid, 1);
if (!*selected_ssid)
continue;
wpa_dbg(wpa_s, MSG_DEBUG, " selected BSS " MACSTR
@@ -1396,8 +1490,9 @@
{
struct wpa_bss *current_bss = NULL;
#ifndef CONFIG_NO_ROAMING
- int min_diff;
+ int min_diff, diff;
int to_5ghz;
+ int cur_est, sel_est;
#endif /* CONFIG_NO_ROAMING */
if (wpa_s->reassociate)
@@ -1431,12 +1526,13 @@
#ifndef CONFIG_NO_ROAMING
wpa_dbg(wpa_s, MSG_DEBUG, "Considering within-ESS reassociation");
wpa_dbg(wpa_s, MSG_DEBUG, "Current BSS: " MACSTR
- " level=%d snr=%d est_throughput=%u",
- MAC2STR(current_bss->bssid), current_bss->level,
+ " freq=%d level=%d snr=%d est_throughput=%u",
+ MAC2STR(current_bss->bssid),
+ current_bss->freq, current_bss->level,
current_bss->snr, current_bss->est_throughput);
wpa_dbg(wpa_s, MSG_DEBUG, "Selected BSS: " MACSTR
- " level=%d snr=%d est_throughput=%u",
- MAC2STR(selected->bssid), selected->level,
+ " freq=%d level=%d snr=%d est_throughput=%u",
+ MAC2STR(selected->bssid), selected->freq, selected->level,
selected->snr, selected->est_throughput);
if (wpa_s->current_ssid->bssid_set &&
@@ -1462,6 +1558,14 @@
return 0;
}
+ if (current_bss->est_throughput > selected->est_throughput + 5000) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Skip roam - Current BSS has better estimated throughput");
+ return 1;
+ }
+
+ cur_est = current_bss->est_throughput;
+ sel_est = selected->est_throughput;
min_diff = 2;
if (current_bss->level < 0) {
if (current_bss->level < -85)
@@ -1474,20 +1578,42 @@
min_diff = 4;
else
min_diff = 5;
+ if (cur_est > sel_est * 1.5)
+ min_diff += 10;
+ else if (cur_est > sel_est * 1.2)
+ min_diff += 5;
+ else if (cur_est > sel_est * 1.1)
+ min_diff += 2;
+ else if (cur_est > sel_est)
+ min_diff++;
}
if (to_5ghz) {
+ int reduce = 2;
+
/* Make it easier to move to 5 GHz band */
- if (min_diff > 2)
- min_diff -= 2;
+ if (sel_est > cur_est * 1.5)
+ reduce = 5;
+ else if (sel_est > cur_est * 1.2)
+ reduce = 4;
+ else if (sel_est > cur_est * 1.1)
+ reduce = 3;
+
+ if (min_diff > reduce)
+ min_diff -= reduce;
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");
+ diff = abs(current_bss->level - selected->level);
+ if (diff < min_diff) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Skip roam - too small difference in signal level (%d < %d)",
+ diff, min_diff);
return 0;
}
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Allow reassociation due to difference in signal level (%d >= %d)",
+ diff, min_diff);
return 1;
#else /* CONFIG_NO_ROAMING */
return 0;
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index 6627b90..ba96548 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -682,12 +682,12 @@
void wpas_notify_p2p_group_started(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, int persistent,
- int client)
+ int client, const u8 *ip)
{
/* Notify a group has been started */
wpas_dbus_register_p2p_group(wpa_s, ssid);
- wpas_dbus_signal_p2p_group_started(wpa_s, client, persistent);
+ wpas_dbus_signal_p2p_group_started(wpa_s, client, persistent, ip);
}
diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
index 8cce0f3..e4d7fbf 100644
--- a/wpa_supplicant/notify.h
+++ b/wpa_supplicant/notify.h
@@ -114,7 +114,7 @@
unsigned int generated_pin);
void wpas_notify_p2p_group_started(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, int persistent,
- int client);
+ int client, const u8 *ip);
void wpas_notify_p2p_group_formation_failure(struct wpa_supplicant *wpa_s,
const char *reason);
void wpas_notify_persistent_group_added(struct wpa_supplicant *wpa_s,
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 6465e2f..2da92bf 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -308,6 +308,8 @@
}
ret = wpa_drv_scan(wpa_s, params);
+ if (ret == 0)
+ wpa_s->curr_scan_cookie = params->scan_cookie;
wpa_scan_free_params(params);
work->ctx = NULL;
if (ret) {
@@ -1383,7 +1385,7 @@
}
if (!client) {
- wpas_notify_p2p_group_started(wpa_s, ssid, persistent, 0);
+ wpas_notify_p2p_group_started(wpa_s, ssid, persistent, 0, NULL);
os_get_reltime(&wpa_s->global->p2p_go_wait_client);
}
}
@@ -1801,7 +1803,8 @@
}
wpas_notify_p2p_group_started(wpa_s, ssid,
- params->persistent_group, 0);
+ params->persistent_group, 0,
+ NULL);
wpas_p2p_cross_connect_setup(wpa_s);
wpas_p2p_set_group_idle_timeout(wpa_s);
@@ -7007,7 +7010,7 @@
wpas_p2p_store_persistent_group(wpa_s->p2pdev,
ssid, go_dev_addr);
- wpas_notify_p2p_group_started(wpa_s, ssid, persistent, 1);
+ wpas_notify_p2p_group_started(wpa_s, ssid, persistent, 1, ip);
}
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 172772d..272e633 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -176,6 +176,17 @@
params->only_new_results = 1;
}
ret = wpa_drv_scan(wpa_s, params);
+ /*
+ * Store the obtained vendor scan cookie (if any) in wpa_s context.
+ * The current design is to allow only one scan request on each
+ * interface, hence having this scan cookie stored in wpa_s context is
+ * fine for now.
+ *
+ * Revisit this logic if concurrent scan operations per interface
+ * is supported.
+ */
+ if (ret == 0)
+ wpa_s->curr_scan_cookie = params->scan_cookie;
wpa_scan_free_params(params);
work->ctx = NULL;
if (ret) {
@@ -703,11 +714,6 @@
size_t max_ssids;
int connect_without_scan = 0;
- if (wpa_s->pno || wpa_s->pno_sched_pending) {
- wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - PNO is in progress");
- return;
- }
-
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - interface disabled");
return;
@@ -768,6 +774,21 @@
return;
}
+ /*
+ * Don't cancel the scan based on ongoing PNO; defer it. Some scans are
+ * used for changing modes inside wpa_supplicant (roaming,
+ * auto-reconnect, etc). Discarding the scan might hurt these processes.
+ * The normal use case for PNO is to suspend the host immediately after
+ * starting PNO, so the periodic 100 ms attempts to run the scan do not
+ * normally happen in practice multiple times, i.e., this is simply
+ * restarting scanning once the host is woken up and PNO stopped.
+ */
+ if (wpa_s->pno || wpa_s->pno_sched_pending) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Defer scan - PNO is in progress");
+ wpa_supplicant_req_scan(wpa_s, 0, 100000);
+ return;
+ }
+
if (wpa_s->conf->ap_scan == 2)
max_ssids = 1;
else {
@@ -1047,7 +1068,8 @@
}
#endif /* CONFIG_P2P */
- if (wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCAN) {
+ if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCAN) &&
+ wpa_s->wpa_state <= WPA_SCANNING) {
params.mac_addr_rand = 1;
if (wpa_s->mac_addr_scan) {
params.mac_addr = wpa_s->mac_addr_scan;
@@ -1469,7 +1491,8 @@
wpa_setband_scan_freqs(wpa_s, scan_params);
- if (wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCHED_SCAN) {
+ if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCHED_SCAN) &&
+ wpa_s->wpa_state <= WPA_SCANNING) {
params.mac_addr_rand = 1;
if (wpa_s->mac_addr_sched_scan) {
params.mac_addr = wpa_s->mac_addr_sched_scan;
@@ -2524,7 +2547,8 @@
params.freqs = wpa_s->manual_sched_scan_freqs;
}
- if (wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_PNO) {
+ if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_PNO) &&
+ wpa_s->wpa_state <= WPA_SCANNING) {
params.mac_addr_rand = 1;
if (wpa_s->mac_addr_pno) {
params.mac_addr = wpa_s->mac_addr_pno;
@@ -2622,18 +2646,20 @@
int wpas_abort_ongoing_scan(struct wpa_supplicant *wpa_s)
{
- int scan_work = !!wpa_s->scan_work;
+ struct wpa_radio_work *work;
+ struct wpa_radio *radio = wpa_s->radio;
-#ifdef CONFIG_P2P
- scan_work |= !!wpa_s->p2p_scan_work;
-#endif /* CONFIG_P2P */
-
- if (scan_work && wpa_s->own_scan_running) {
+ dl_list_for_each(work, &radio->work, struct wpa_radio_work, list) {
+ if (work->wpa_s != wpa_s || !work->started ||
+ (os_strcmp(work->type, "scan") != 0 &&
+ os_strcmp(work->type, "p2p-scan") != 0))
+ continue;
wpa_dbg(wpa_s, MSG_DEBUG, "Abort an ongoing scan");
- return wpa_drv_abort_scan(wpa_s);
+ return wpa_drv_abort_scan(wpa_s, wpa_s->curr_scan_cookie);
}
- return 0;
+ wpa_dbg(wpa_s, MSG_DEBUG, "No ongoing scan/p2p-scan found to abort");
+ return -1;
}
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index 1b3409c..0b1a2db 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -562,7 +562,7 @@
if (wpa_s->current_ssid &&
!wpa_scan_res_match(wpa_s, 0, target, wpa_s->current_ssid,
- 1)) {
+ 1, 0)) {
wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
" (pref %d) does not match the current network profile",
MAC2STR(nei->bssid),
@@ -756,7 +756,7 @@
struct wpa_bss *bss = wpa_s->last_scan_res[i];
int res;
- if (wpa_scan_res_match(wpa_s, i, bss, ssid, 1)) {
+ if (wpa_scan_res_match(wpa_s, i, bss, ssid, 1, 0)) {
res = wnm_nei_rep_add_bss(wpa_s, bss, pos, len, pref--);
if (res == -2)
continue; /* could not build entry for BSS */
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 4877989..f11028a 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -1390,6 +1390,8 @@
"ap_max_inactivity", "dtim_period", "beacon_int",
#ifdef CONFIG_MACSEC
"macsec_policy",
+ "macsec_integ_only",
+ "macsec_port",
#endif /* CONFIG_MACSEC */
#ifdef CONFIG_HS20
"update_identifier",
diff --git a/wpa_supplicant/wpa_priv.c b/wpa_supplicant/wpa_priv.c
index b36d195..9b81fc1 100644
--- a/wpa_supplicant/wpa_priv.c
+++ b/wpa_supplicant/wpa_priv.c
@@ -21,6 +21,7 @@
#include "common/privsep_commands.h"
#include "common/ieee802_11_defs.h"
+#define WPA_PRIV_MAX_L2 3
struct wpa_priv_interface {
struct wpa_priv_interface *next;
@@ -35,11 +36,16 @@
void *drv_priv;
void *drv_global_priv;
struct sockaddr_un drv_addr;
+ socklen_t drv_addr_len;
int wpas_registered;
- /* TODO: add support for multiple l2 connections */
- struct l2_packet_data *l2;
- struct sockaddr_un l2_addr;
+ struct l2_packet_data *l2[WPA_PRIV_MAX_L2];
+ struct sockaddr_un l2_addr[WPA_PRIV_MAX_L2];
+ socklen_t l2_addr_len[WPA_PRIV_MAX_L2];
+ struct wpa_priv_l2 {
+ struct wpa_priv_interface *parent;
+ int idx;
+ } l2_ctx[WPA_PRIV_MAX_L2];
};
struct wpa_priv_global {
@@ -48,8 +54,10 @@
static void wpa_priv_cmd_register(struct wpa_priv_interface *iface,
- struct sockaddr_un *from)
+ struct sockaddr_un *from, socklen_t fromlen)
{
+ int i;
+
if (iface->drv_priv) {
wpa_printf(MSG_DEBUG, "Cleaning up forgotten driver instance");
if (iface->driver->deinit)
@@ -62,11 +70,13 @@
iface->wpas_registered = 0;
}
- if (iface->l2) {
- wpa_printf(MSG_DEBUG, "Cleaning up forgotten l2_packet "
- "instance");
- l2_packet_deinit(iface->l2);
- iface->l2 = NULL;
+ for (i = 0; i < WPA_PRIV_MAX_L2; i++) {
+ if (iface->l2[i]) {
+ wpa_printf(MSG_DEBUG,
+ "Cleaning up forgotten l2_packet instance");
+ l2_packet_deinit(iface->l2[i]);
+ iface->l2[i] = NULL;
+ }
}
if (iface->driver->init2) {
@@ -96,7 +106,8 @@
wpa_printf(MSG_DEBUG, "Driver wrapper '%s' initialized for interface "
"'%s'", iface->driver_name, iface->ifname);
- os_memcpy(&iface->drv_addr, from, sizeof(iface->drv_addr));
+ os_memcpy(&iface->drv_addr, from, fromlen);
+ iface->drv_addr_len = fromlen;
iface->wpas_registered = 1;
if (iface->driver->set_param &&
@@ -123,18 +134,43 @@
static void wpa_priv_cmd_scan(struct wpa_priv_interface *iface,
- char *buf, size_t len)
+ void *buf, size_t len)
{
struct wpa_driver_scan_params params;
+ struct privsep_cmd_scan *scan;
+ unsigned int i;
+ int freqs[PRIVSEP_MAX_SCAN_FREQS + 1];
if (iface->drv_priv == NULL)
return;
+ if (len < sizeof(*scan)) {
+ wpa_printf(MSG_DEBUG, "Invalid scan request");
+ return;
+ }
+
+ scan = buf;
+
os_memset(¶ms, 0, sizeof(params));
- if (len) {
- params.ssids[0].ssid = (u8 *) buf;
- params.ssids[0].ssid_len = len;
- params.num_ssids = 1;
+ if (scan->num_ssids > WPAS_MAX_SCAN_SSIDS) {
+ wpa_printf(MSG_DEBUG, "Invalid scan request (num_ssids)");
+ return;
+ }
+ params.num_ssids = scan->num_ssids;
+ for (i = 0; i < scan->num_ssids; i++) {
+ params.ssids[i].ssid = scan->ssids[i];
+ params.ssids[i].ssid_len = scan->ssid_lens[i];
+ }
+
+ if (scan->num_freqs > PRIVSEP_MAX_SCAN_FREQS) {
+ wpa_printf(MSG_DEBUG, "Invalid scan request (num_freqs)");
+ return;
+ }
+ if (scan->num_freqs) {
+ for (i = 0; i < scan->num_freqs; i++)
+ freqs[i] = scan->freqs[i];
+ freqs[i] = 0;
+ params.freqs = freqs;
}
if (iface->driver->scan2)
@@ -143,7 +179,8 @@
static void wpa_priv_get_scan_results2(struct wpa_priv_interface *iface,
- struct sockaddr_un *from)
+ struct sockaddr_un *from,
+ socklen_t fromlen)
{
struct wpa_scan_results *res;
u8 *buf = NULL, *pos, *end;
@@ -165,7 +202,7 @@
for (i = 0; i < res->num; i++) {
struct wpa_scan_res *r = res->res[i];
- val = sizeof(*r) + r->ie_len;
+ val = sizeof(*r) + r->ie_len + r->beacon_ie_len;
if (end - pos < (int) sizeof(int) + val)
break;
os_memcpy(pos, &val, sizeof(int));
@@ -174,8 +211,7 @@
pos += val;
}
- sendto(iface->fd, buf, pos - buf, 0, (struct sockaddr *) from,
- sizeof(*from));
+ sendto(iface->fd, buf, pos - buf, 0, (struct sockaddr *) from, fromlen);
os_free(buf);
wpa_scan_results_free(res);
@@ -184,21 +220,21 @@
fail:
os_free(buf);
wpa_scan_results_free(res);
- sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from));
+ sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, fromlen);
}
static void wpa_priv_cmd_get_scan_results(struct wpa_priv_interface *iface,
- struct sockaddr_un *from)
+ struct sockaddr_un *from,
+ socklen_t fromlen)
{
if (iface->drv_priv == NULL)
return;
if (iface->driver->get_scan_results2)
- wpa_priv_get_scan_results2(iface, from);
+ wpa_priv_get_scan_results2(iface, from, fromlen);
else
- sendto(iface->fd, "", 0, 0, (struct sockaddr *) from,
- sizeof(*from));
+ sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, fromlen);
}
@@ -303,7 +339,7 @@
static void wpa_priv_cmd_get_bssid(struct wpa_priv_interface *iface,
- struct sockaddr_un *from)
+ struct sockaddr_un *from, socklen_t fromlen)
{
u8 bssid[ETH_ALEN];
@@ -315,16 +351,16 @@
goto fail;
sendto(iface->fd, bssid, ETH_ALEN, 0, (struct sockaddr *) from,
- sizeof(*from));
+ fromlen);
return;
fail:
- sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from));
+ sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, fromlen);
}
static void wpa_priv_cmd_get_ssid(struct wpa_priv_interface *iface,
- struct sockaddr_un *from)
+ struct sockaddr_un *from, socklen_t fromlen)
{
u8 ssid[sizeof(int) + SSID_MAX_LEN];
int res;
@@ -335,17 +371,18 @@
if (iface->driver->get_ssid == NULL)
goto fail;
+ os_memset(ssid, 0, sizeof(ssid));
res = iface->driver->get_ssid(iface->drv_priv, &ssid[sizeof(int)]);
if (res < 0 || res > SSID_MAX_LEN)
goto fail;
os_memcpy(ssid, &res, sizeof(int));
sendto(iface->fd, ssid, sizeof(ssid), 0, (struct sockaddr *) from,
- sizeof(*from));
+ fromlen);
return;
fail:
- sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from));
+ sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, fromlen);
}
@@ -378,7 +415,7 @@
static void wpa_priv_cmd_get_capa(struct wpa_priv_interface *iface,
- struct sockaddr_un *from)
+ struct sockaddr_un *from, socklen_t fromlen)
{
struct wpa_driver_capa capa;
@@ -394,18 +431,19 @@
capa.extended_capa_mask = NULL;
capa.extended_capa_len = 0;
sendto(iface->fd, &capa, sizeof(capa), 0, (struct sockaddr *) from,
- sizeof(*from));
+ fromlen);
return;
fail:
- sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from));
+ sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, fromlen);
}
static void wpa_priv_l2_rx(void *ctx, const u8 *src_addr, const u8 *buf,
size_t len)
{
- struct wpa_priv_interface *iface = ctx;
+ struct wpa_priv_l2 *l2_ctx = ctx;
+ struct wpa_priv_interface *iface = l2_ctx->parent;
struct msghdr msg;
struct iovec io[2];
@@ -417,8 +455,8 @@
os_memset(&msg, 0, sizeof(msg));
msg.msg_iov = io;
msg.msg_iovlen = 2;
- msg.msg_name = &iface->l2_addr;
- msg.msg_namelen = sizeof(iface->l2_addr);
+ msg.msg_name = &iface->l2_addr[l2_ctx->idx];
+ msg.msg_namelen = iface->l2_addr_len[l2_ctx->idx];
if (sendmsg(iface->fd, &msg, 0) < 0) {
wpa_printf(MSG_ERROR, "sendmsg(l2 rx): %s", strerror(errno));
@@ -426,14 +464,23 @@
}
+static int wpa_priv_allowed_l2_proto(u16 proto)
+{
+ return proto == ETH_P_EAPOL || proto == ETH_P_RSN_PREAUTH ||
+ proto == ETH_P_80211_ENCAP;
+}
+
+
static void wpa_priv_cmd_l2_register(struct wpa_priv_interface *iface,
struct sockaddr_un *from,
+ socklen_t fromlen,
void *buf, size_t len)
{
int *reg_cmd = buf;
u8 own_addr[ETH_ALEN];
int res;
u16 proto;
+ int idx;
if (len != 2 * sizeof(int)) {
wpa_printf(MSG_DEBUG, "Invalid l2_register length %lu",
@@ -442,50 +489,69 @@
}
proto = reg_cmd[0];
- if (proto != ETH_P_EAPOL && proto != ETH_P_RSN_PREAUTH &&
- proto != ETH_P_80211_ENCAP) {
+ if (!wpa_priv_allowed_l2_proto(proto)) {
wpa_printf(MSG_DEBUG, "Refused l2_packet connection for "
"ethertype 0x%x", proto);
return;
}
- if (iface->l2) {
- wpa_printf(MSG_DEBUG, "Cleaning up forgotten l2_packet "
- "instance");
- l2_packet_deinit(iface->l2);
- iface->l2 = NULL;
+ for (idx = 0; idx < WPA_PRIV_MAX_L2; idx++) {
+ if (!iface->l2[idx])
+ break;
+ }
+ if (idx == WPA_PRIV_MAX_L2) {
+ wpa_printf(MSG_DEBUG, "No free l2_packet connection found");
+ return;
}
- os_memcpy(&iface->l2_addr, from, sizeof(iface->l2_addr));
+ os_memcpy(&iface->l2_addr[idx], from, fromlen);
+ iface->l2_addr_len[idx] = fromlen;
- iface->l2 = l2_packet_init(iface->ifname, NULL, proto,
- wpa_priv_l2_rx, iface, reg_cmd[1]);
- if (iface->l2 == NULL) {
+ iface->l2_ctx[idx].idx = idx;
+ iface->l2_ctx[idx].parent = iface;
+ iface->l2[idx] = l2_packet_init(iface->ifname, NULL, proto,
+ wpa_priv_l2_rx, &iface->l2_ctx[idx],
+ reg_cmd[1]);
+ if (!iface->l2[idx]) {
wpa_printf(MSG_DEBUG, "Failed to initialize l2_packet "
"instance for protocol %d", proto);
return;
}
- if (l2_packet_get_own_addr(iface->l2, own_addr) < 0) {
+ if (l2_packet_get_own_addr(iface->l2[idx], own_addr) < 0) {
wpa_printf(MSG_DEBUG, "Failed to get own address from "
"l2_packet");
- l2_packet_deinit(iface->l2);
- iface->l2 = NULL;
+ l2_packet_deinit(iface->l2[idx]);
+ iface->l2[idx] = NULL;
return;
}
res = sendto(iface->fd, own_addr, ETH_ALEN, 0,
- (struct sockaddr *) from, sizeof(*from));
- wpa_printf(MSG_DEBUG, "L2 registration: res=%d", res);
+ (struct sockaddr *) from, fromlen);
+ wpa_printf(MSG_DEBUG, "L2 registration[idx=%d]: res=%d", idx, res);
}
static void wpa_priv_cmd_l2_unregister(struct wpa_priv_interface *iface,
- struct sockaddr_un *from)
+ struct sockaddr_un *from,
+ socklen_t fromlen)
{
- if (iface->l2) {
- l2_packet_deinit(iface->l2);
- iface->l2 = NULL;
+ int idx;
+
+ for (idx = 0; idx < WPA_PRIV_MAX_L2; idx++) {
+ if (iface->l2_addr_len[idx] == fromlen &&
+ os_memcmp(&iface->l2_addr[idx], from, fromlen) == 0)
+ break;
+ }
+ if (idx == WPA_PRIV_MAX_L2) {
+ wpa_printf(MSG_DEBUG,
+ "No registered l2_packet socket found for unregister request");
+ return;
+ }
+
+ if (iface->l2[idx]) {
+ l2_packet_deinit(iface->l2[idx]);
+ iface->l2[idx] = NULL;
}
}
@@ -493,20 +559,36 @@
static void wpa_priv_cmd_l2_notify_auth_start(struct wpa_priv_interface *iface,
struct sockaddr_un *from)
{
- if (iface->l2)
- l2_packet_notify_auth_start(iface->l2);
+ int idx;
+
+ for (idx = 0; idx < WPA_PRIV_MAX_L2; idx++) {
+ if (iface->l2[idx])
+ l2_packet_notify_auth_start(iface->l2[idx]);
+ }
}
static void wpa_priv_cmd_l2_send(struct wpa_priv_interface *iface,
- struct sockaddr_un *from,
+ struct sockaddr_un *from, socklen_t fromlen,
void *buf, size_t len)
{
u8 *dst_addr;
u16 proto;
int res;
+ int idx;
- if (iface->l2 == NULL)
+ for (idx = 0; idx < WPA_PRIV_MAX_L2; idx++) {
+ if (iface->l2_addr_len[idx] == fromlen &&
+ os_memcmp(&iface->l2_addr[idx], from, fromlen) == 0)
+ break;
+ }
+ if (idx == WPA_PRIV_MAX_L2) {
+ wpa_printf(MSG_DEBUG,
+ "No registered l2_packet socket found for send request");
+ return;
+ }
+
+ if (iface->l2[idx] == NULL)
return;
if (len < ETH_ALEN + 2) {
@@ -518,15 +600,15 @@
dst_addr = buf;
os_memcpy(&proto, buf + ETH_ALEN, 2);
- if (proto != ETH_P_EAPOL && proto != ETH_P_RSN_PREAUTH) {
+ if (!wpa_priv_allowed_l2_proto(proto)) {
wpa_printf(MSG_DEBUG, "Refused l2_packet send for ethertype "
"0x%x", proto);
return;
}
- res = l2_packet_send(iface->l2, dst_addr, proto, buf + ETH_ALEN + 2,
- len - ETH_ALEN - 2);
- wpa_printf(MSG_DEBUG, "L2 send: res=%d", res);
+ res = l2_packet_send(iface->l2[idx], dst_addr, proto,
+ buf + ETH_ALEN + 2, len - ETH_ALEN - 2);
+ wpa_printf(MSG_DEBUG, "L2 send[idx=%d]: res=%d", idx, res);
}
@@ -571,7 +653,7 @@
switch (cmd) {
case PRIVSEP_CMD_REGISTER:
- wpa_priv_cmd_register(iface, &from);
+ wpa_priv_cmd_register(iface, &from, fromlen);
break;
case PRIVSEP_CMD_UNREGISTER:
wpa_priv_cmd_unregister(iface, &from);
@@ -580,34 +662,35 @@
wpa_priv_cmd_scan(iface, cmd_buf, cmd_len);
break;
case PRIVSEP_CMD_GET_SCAN_RESULTS:
- wpa_priv_cmd_get_scan_results(iface, &from);
+ wpa_priv_cmd_get_scan_results(iface, &from, fromlen);
break;
case PRIVSEP_CMD_ASSOCIATE:
wpa_priv_cmd_associate(iface, cmd_buf, cmd_len);
break;
case PRIVSEP_CMD_GET_BSSID:
- wpa_priv_cmd_get_bssid(iface, &from);
+ wpa_priv_cmd_get_bssid(iface, &from, fromlen);
break;
case PRIVSEP_CMD_GET_SSID:
- wpa_priv_cmd_get_ssid(iface, &from);
+ wpa_priv_cmd_get_ssid(iface, &from, fromlen);
break;
case PRIVSEP_CMD_SET_KEY:
wpa_priv_cmd_set_key(iface, cmd_buf, cmd_len);
break;
case PRIVSEP_CMD_GET_CAPA:
- wpa_priv_cmd_get_capa(iface, &from);
+ wpa_priv_cmd_get_capa(iface, &from, fromlen);
break;
case PRIVSEP_CMD_L2_REGISTER:
- wpa_priv_cmd_l2_register(iface, &from, cmd_buf, cmd_len);
+ wpa_priv_cmd_l2_register(iface, &from, fromlen,
+ cmd_buf, cmd_len);
break;
case PRIVSEP_CMD_L2_UNREGISTER:
- wpa_priv_cmd_l2_unregister(iface, &from);
+ wpa_priv_cmd_l2_unregister(iface, &from, fromlen);
break;
case PRIVSEP_CMD_L2_NOTIFY_AUTH_START:
wpa_priv_cmd_l2_notify_auth_start(iface, &from);
break;
case PRIVSEP_CMD_L2_SEND:
- wpa_priv_cmd_l2_send(iface, &from, cmd_buf, cmd_len);
+ wpa_priv_cmd_l2_send(iface, &from, fromlen, cmd_buf, cmd_len);
break;
case PRIVSEP_CMD_SET_COUNTRY:
pos = cmd_buf;
@@ -625,8 +708,14 @@
static void wpa_priv_interface_deinit(struct wpa_priv_interface *iface)
{
- if (iface->drv_priv && iface->driver->deinit)
- iface->driver->deinit(iface->drv_priv);
+ int i;
+
+ if (iface->drv_priv) {
+ if (iface->driver->deinit)
+ iface->driver->deinit(iface->drv_priv);
+ if (iface->drv_global_priv)
+ iface->driver->global_deinit(iface->drv_global_priv);
+ }
if (iface->fd >= 0) {
eloop_unregister_read_sock(iface->fd);
@@ -634,8 +723,10 @@
unlink(iface->sock_name);
}
- if (iface->l2)
- l2_packet_deinit(iface->l2);
+ for (i = 0; i < WPA_PRIV_MAX_L2; i++) {
+ if (iface->l2[i])
+ l2_packet_deinit(iface->l2[i]);
+ }
os_free(iface->ifname);
os_free(iface->driver_name);
@@ -777,7 +868,7 @@
msg.msg_iov = io;
msg.msg_iovlen = data ? 2 : 1;
msg.msg_name = &iface->drv_addr;
- msg.msg_namelen = sizeof(iface->drv_addr);
+ msg.msg_namelen = iface->drv_addr_len;
if (sendmsg(iface->fd, &msg, 0) < 0) {
wpa_printf(MSG_ERROR, "sendmsg(wpas_socket): %s",
@@ -796,7 +887,7 @@
struct privsep_event_auth *auth;
u8 *buf, *pos;
- buf = os_malloc(buflen);
+ buf = os_zalloc(buflen);
if (buf == NULL)
return;
@@ -1061,7 +1152,7 @@
msg.msg_iov = io;
msg.msg_iovlen = 3;
msg.msg_name = &iface->drv_addr;
- msg.msg_namelen = sizeof(iface->drv_addr);
+ msg.msg_namelen = iface->drv_addr_len;
if (sendmsg(iface->fd, &msg, 0) < 0)
wpa_printf(MSG_ERROR, "sendmsg(wpas_socket): %s",
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 8cfb488..531004f 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -329,7 +329,12 @@
eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
- ieee802_1x_alloc_kay_sm(wpa_s, ssid);
+#ifdef CONFIG_MACSEC
+ if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE && ssid->mka_psk_set)
+ ieee802_1x_create_preshared_mka(wpa_s, ssid);
+ else
+ ieee802_1x_alloc_kay_sm(wpa_s, ssid);
+#endif /* CONFIG_MACSEC */
#endif /* IEEE8021X_EAPOL */
}
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 047ca90..edb230d 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -98,9 +98,7 @@
# parameters (e.g., WPA IE generation); this mode can also be used with
# non-WPA drivers when using IEEE 802.1X mode; do not try to associate with
# APs (i.e., external program needs to control association). This mode must
-# also be used when using wired Ethernet drivers.
-# Note: macsec_qca driver is one type of Ethernet driver which implements
-# macsec feature.
+# also be used when using wired Ethernet drivers (including MACsec).
# 2: like 0, but associate with APs using security policy and SSID (but not
# BSSID); this can be used, e.g., with ndiswrapper and NDIS drivers to
# enable operation with hidden SSIDs and optimized roaming; in this mode,
@@ -881,17 +879,36 @@
# bit0 (1): require dynamically generated unicast WEP key
# bit1 (2): require dynamically generated broadcast WEP key
# (3 = require both keys; default)
-# Note: When using wired authentication (including macsec_qca driver),
+# Note: When using wired authentication (including MACsec drivers),
# eapol_flags must be set to 0 for the authentication to be completed
# successfully.
#
# macsec_policy: IEEE 802.1X/MACsec options
-# This determines how sessions are secured with MACsec. It is currently
-# applicable only when using the macsec_qca driver interface.
+# This determines how sessions are secured with MACsec (only for MACsec
+# drivers).
# 0: MACsec not in use (default)
# 1: MACsec enabled - Should secure, accept key server's advice to
# determine whether to use a secure session or not.
#
+# macsec_integ_only: IEEE 802.1X/MACsec transmit mode
+# This setting applies only when MACsec is in use, i.e.,
+# - macsec_policy is enabled
+# - the key server has decided to enable MACsec
+# 0: Encrypt traffic (default)
+# 1: Integrity only
+#
+# macsec_port: IEEE 802.1X/MACsec port
+# Port component of the SCI
+# Range: 1-65534 (default: 1)
+#
+# mka_cak and mka_ckn: IEEE 802.1X/MACsec pre-shared authentication mode
+# This allows to configure MACsec with a pre-shared key using a (CAK,CKN) pair.
+# In this mode, instances of wpa_supplicant can act as peers, one of
+# which will become the key server and start distributing SAKs.
+# mka_cak (CAK = Secure Connectivity Association Key) takes a 16-bytes (128 bit)
+# hex-string (32 hex-digits)
+# mka_ckn (CKN = CAK Name) takes a 32-bytes (256 bit) hex-string (64 hex-digits)
+#
# mixed_cell: This option can be used to configure whether so called mixed
# cells, i.e., networks that use both plaintext and encryption in the same
# SSID, are allowed when selecting a BSS from scan results.
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 4a7e3c7..ff3a531 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -652,6 +652,12 @@
int normal_scans; /* normal scans run before sched_scan */
int scan_for_connection; /* whether the scan request was triggered for
* finding a connection */
+ /*
+ * A unique cookie representing the vendor scan request. This cookie is
+ * returned from the driver interface. 0 indicates that there is no
+ * pending vendor scan request.
+ */
+ u64 curr_scan_cookie;
#define MAX_SCAN_ID 16
int scan_id[MAX_SCAN_ID];
unsigned int scan_id_count;
@@ -1310,6 +1316,6 @@
struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
int i, struct wpa_bss *bss,
struct wpa_ssid *group,
- int only_first_ssid);
+ int only_first_ssid, int debug_print);
#endif /* WPA_SUPPLICANT_I_H */
diff --git a/wpa_supplicant/wpas_kay.c b/wpa_supplicant/wpas_kay.c
index e032330..d3fefda 100644
--- a/wpa_supplicant/wpas_kay.c
+++ b/wpa_supplicant/wpas_kay.c
@@ -50,6 +50,12 @@
}
+static int wpas_enable_encrypt(void *wpa_s, Boolean enabled)
+{
+ return wpa_drv_enable_encrypt(wpa_s, enabled);
+}
+
+
static int wpas_set_replay_protect(void *wpa_s, Boolean enabled, u32 window)
{
return wpa_drv_set_replay_protect(wpa_s, enabled, window);
@@ -187,7 +193,14 @@
if (!ssid || ssid->macsec_policy == 0)
return 0;
- policy = ssid->macsec_policy == 1 ? SHOULD_SECURE : DO_NOT_SECURE;
+ if (ssid->macsec_policy == 1) {
+ if (ssid->macsec_integ_only == 1)
+ policy = SHOULD_SECURE;
+ else
+ policy = SHOULD_ENCRYPT;
+ } else {
+ policy = DO_NOT_SECURE;
+ }
kay_ctx = os_zalloc(sizeof(*kay_ctx));
if (!kay_ctx)
@@ -199,6 +212,7 @@
kay_ctx->macsec_deinit = wpas_macsec_deinit;
kay_ctx->macsec_get_capability = wpas_macsec_get_capability;
kay_ctx->enable_protect_frames = wpas_enable_protect_frames;
+ kay_ctx->enable_encrypt = wpas_enable_encrypt;
kay_ctx->set_replay_protect = wpas_set_replay_protect;
kay_ctx->set_current_cipher_suite = wpas_set_current_cipher_suite;
kay_ctx->enable_controlled_port = wpas_enable_controlled_port;
@@ -218,8 +232,8 @@
kay_ctx->enable_transmit_sa = wpas_enable_transmit_sa;
kay_ctx->disable_transmit_sa = wpas_disable_transmit_sa;
- res = ieee802_1x_kay_init(kay_ctx, policy, wpa_s->ifname,
- wpa_s->own_addr);
+ res = ieee802_1x_kay_init(kay_ctx, policy, ssid->macsec_port,
+ wpa_s->ifname, wpa_s->own_addr);
if (res == NULL) {
os_free(kay_ctx);
return -1;
@@ -371,3 +385,51 @@
return res;
}
+
+
+void * ieee802_1x_create_preshared_mka(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ struct mka_key *cak;
+ struct mka_key_name *ckn;
+ void *res;
+
+ if ((ssid->mka_psk_set & MKA_PSK_SET) != MKA_PSK_SET)
+ return NULL;
+
+ if (ieee802_1x_alloc_kay_sm(wpa_s, ssid) < 0)
+ return NULL;
+
+ if (!wpa_s->kay || wpa_s->kay->policy == DO_NOT_SECURE)
+ return NULL;
+
+ ckn = os_zalloc(sizeof(*ckn));
+ if (!ckn)
+ goto dealloc;
+
+ cak = os_zalloc(sizeof(*cak));
+ if (!cak)
+ goto free_ckn;
+
+ cak->len = MACSEC_CAK_LEN;
+ os_memcpy(cak->key, ssid->mka_cak, cak->len);
+
+ ckn->len = MACSEC_CKN_LEN;
+ os_memcpy(ckn->name, ssid->mka_ckn, ckn->len);
+
+ res = ieee802_1x_kay_create_mka(wpa_s->kay, ckn, cak, 0, PSK, FALSE);
+ if (res)
+ return res;
+
+ /* Failed to create MKA */
+ os_free(cak);
+
+ /* fallthrough */
+
+free_ckn:
+ os_free(ckn);
+dealloc:
+ ieee802_1x_dealloc_kay_sm(wpa_s);
+
+ return NULL;
+}
diff --git a/wpa_supplicant/wpas_kay.h b/wpa_supplicant/wpas_kay.h
index b7236d0..81f8e0c 100644
--- a/wpa_supplicant/wpas_kay.h
+++ b/wpa_supplicant/wpas_kay.h
@@ -17,6 +17,9 @@
const u8 *peer_addr);
void ieee802_1x_dealloc_kay_sm(struct wpa_supplicant *wpa_s);
+void * ieee802_1x_create_preshared_mka(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid);
+
#else /* CONFIG_MACSEC */
static inline int ieee802_1x_alloc_kay_sm(struct wpa_supplicant *wpa_s,
@@ -36,6 +39,13 @@
{
}
+static inline void *
+ieee802_1x_create_preshared_mka(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ return 0;
+}
+
#endif /* CONFIG_MACSEC */
#endif /* WPAS_KAY_H */