Cumulative patch from commit ed0a4ddc22526361a138c6b145561fcaac24e2a5
ed0a4dd nl80211: Update drv->ssid on connect/associate event based on BSS data
9f346fa nl80211: Fix scan_state update in no pending scan state
34f7c69 Add multicast to unicast support
5f2c0a2 Sync with mac80211-next.git include/uapi/linux/nl80211.h
08032c7 Remove inactivity timeout for wired interfaces
57f93d6 Defer scans while PNO is in progress instead of skipping them
a1fce39 nl80211: Optimize memory use in nl80211_get_assoc_freq()
da2c284 nl80211: Reduce nl80211_dump_scan() memory need
b72a01b nl80211: Split bss_info_handler() into a separate parser function
cfadab2 nl80211: Move duplicate scan result removal to bss.c
2a1cf26 nl80211: Add more debug details to duplicate scan entry removal
865081c privsep: Support frequency list for scan requests
da818ee privsep: Support multiple scan SSIDs
002b504 privsep: Coding style cleanup for struct definitions
d3c43e5 privsep: Fix scan result fetching with Beacon frame IEs
0771e91 wpa_priv: Document reduced functionality
6d97561 wpa_priv: Handler driver global_deinit() on termination path
ce0f899 wpa_priv: Explicitly clear padding in message structures
e064177 wpa_priv: Use fromlen instead sizeof(struct sockaddr_un)
128d3c6 wpa_priv: Add support for multiple l2_packet connections
c8fef78 nl80211: Split nl80211_check_bss_status() into a separate function
e35e137 nl80211: Separate channel noise fetch from scan result processing
cb2b666 Fix 4addr reassociation-without-deauthentication on AP
8c0ed37 wired: Mark some common helper functions static
ba5ea11 mka: Remove references to macsec_qca from wpa_supplicant.conf
f014d9d macsec_linux: Add a driver for macsec on Linux kernels
8618313 drivers: Move driver_wired_get_ssid() to a common file
d27c42b drivers: Move driver_wired_get_bssid() to a common file
9281e5c drivers: Move driver_wired_get_capa() to a common file
ec9cfb9 drivers: Move driver_wired_deinit_common() to a common file
ed5ae61 drivers: Move driver_wired_init_common() to a common file
5a55ec3 drivers: Move driver_wired_get_ifstatus() to a common file
d718a5d drivers: Move driver_wired_set_ifflags() to a common file
567b7d4 drivers: Move driver_wired_get_ifflags() to a common file
693124a drivers: Move driver_wired_multi() to a common file
b0906ef drivers: Move wired_multicast_membership() to a common file
0abc8d1 drivers: Move common definitions for wired drivers out
bf88401 Add support to abort vendor scan
eeb34a4 nl80211: Enhance abort scan to also abort the vendor scan
1a793f5 Define a QCA vendor command to abort vendor scan
47d74bf Add MGMT_RX_PROCESS test command for hostapd
2ab0965 AP: Do not drop STA entry if PMF is used with full AP client state
209dad0 FT: Explicitly check for MDE not present in non-FT association
d4f3003 nl80211: Configure Beacon frame TX rate if driver advertises support
29483a5 Add support for user configurable Beacon frame data rate for AP mode
346b333 Use random MAC address for scanning only in non-connected state
18f1611 D-Bus: Send P2P IP address assignment info with GroupStarted event
046fa6f D-Bus: Add getter and setter for P2P IP address config parameters
d503eee FT: Complete CONFIG_IEEE80211R_AP renaming for hostapd
e0d9fd3 wpa_supplicant: Allow configuring the MACsec port for MKA
1d3d066 mka: Add enable_encrypt op and call it from CP state machine
7b4d546 wpa_supplicant: Add macsec_integ_only setting for MKA
008e224 mka: Disable peer detection timeout for PSK mode
ad51731 wpa_supplicant: Allow pre-shared (CAK,CKN) pair for MKA
5acbf22 Fix hostapd usage entry style for -T
611d67a Add doxygen ref to eap_method structure
88f93c3 Android: Remove BoringSSL guard
7824bf7 nl80211: Fix get_inact_sec() returning -1 on failure
088d53d mka: Fix getting capabilities from the driver
5e785a6 Reserve QCA vendor specific nl80211 command 144
4051dd8 GAS: Add Capability List ANQP-element support for Info ID 270, 280..299
d50f518 Fix libap.a build
e65a87b Debug print scan results matching the currently selected network
8d1e693 Use estimated throughput to avoid signal based roaming decision
Test: Wifi Suite
Change-Id: Ic470ffe9004d28d34916e50221d631ac99d4163f
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
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 */