[PATCH 1/3] test-runner: make default iwd_config_dir=/tmp
by James Prestwood
The configuration value of iwd_config_dir was defaulting to /etc/iwd
which, in the context of test-runner, is probably not the best idea.
The system may have a main.conf file in /etc/iwd which could cause
tests to fail or behave unexpectedly.
In addition all tests which use iwd_config_dir set it to /tmp anyways.
Because of this, the new default value will be /tmp and no tests will
even need to bother setting this.
The configuration value itself is not being removed because it may be
useful to set arbitrary paths (e.g. /etc/iwd) for example when using
the shell functionality.
---
tools/test-runner.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/test-runner.c b/tools/test-runner.c
index 1be3f640..1adb8377 100644
--- a/tools/test-runner.c
+++ b/tools/test-runner.c
@@ -2205,7 +2205,7 @@ static void create_network_and_run_tests(void *data, void *user_data)
HW_CONFIG_GROUP_SETUP,
HW_CONFIG_SETUP_IWD_CONF_DIR);
if (!iwd_config_dir)
- iwd_config_dir = DAEMON_CONFIGDIR;
+ iwd_config_dir = "/tmp";
iwd_pid = start_iwd(iwd_config_dir, wiphy_list,
iwd_ext_options, iwd_phys, test_name);
--
2.21.1
10 months
[RFC 0/1] Fix DBus auth issues on Fedora
by James Prestwood
This 'fixes' test-runner DBus auth issues on Fedora and
maybe other system. I say 'fixes' because all its doing
is allowing anonymous access to the bus vs finding a
solution to the real problem. I (and I believe Andrew)
have been carrying similar patches in order to get
test-runner to work on Fedora.
I have tried diagnosing this without any success. Since
this is only for use in test-runner I thought a
solution (at least temporarily) would be to allow
anonymous access to DBus.
OR maybe someone will see this and have some idea as
to what is going on.
James Prestwood (1):
test-runner: allow anonymous Dbus access
tools/test-runner.c | 2 ++
1 file changed, 2 insertions(+)
--
2.21.1
10 months
[PATCH] handshake: fix OWE PTK derivation
by James Prestwood
This bug has been in here since OWE was written, but a similar bug also
existed in hostapd which allowed the PTK derivation to be identical.
In January 2020 hostapd fixed this bug, which now makes IWD incompatible
when using group 20 or 21.
This patch fixes the bug for IWD, so now OWE should be compatible with
recent hostapd version. This will break compatibility with old hostapd
versions which still have this bug.
---
src/handshake.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/src/handshake.c b/src/handshake.c
index bb376441..1cab48f1 100644
--- a/src/handshake.c
+++ b/src/handshake.c
@@ -410,14 +410,22 @@ bool handshake_state_derive_ptk(struct handshake_state *s)
s->ptk_complete = false;
- if (s->akm_suite & (IE_RSN_AKM_SUITE_FILS_SHA384 |
+ if (s->akm_suite & IE_RSN_AKM_SUITE_OWE) {
+ if (s->pmk_len == 32)
+ type = L_CHECKSUM_SHA256;
+ else if (s->pmk_len == 48)
+ type = L_CHECKSUM_SHA384;
+ else if (s->pmk_len == 64)
+ type = L_CHECKSUM_SHA512;
+ else
+ return false;
+ } else if (s->akm_suite & (IE_RSN_AKM_SUITE_FILS_SHA384 |
IE_RSN_AKM_SUITE_FT_OVER_FILS_SHA384))
type = L_CHECKSUM_SHA384;
else if (s->akm_suite & (IE_RSN_AKM_SUITE_8021X_SHA256 |
IE_RSN_AKM_SUITE_PSK_SHA256 |
IE_RSN_AKM_SUITE_SAE_SHA256 |
IE_RSN_AKM_SUITE_FT_OVER_SAE_SHA256 |
- IE_RSN_AKM_SUITE_OWE |
IE_RSN_AKM_SUITE_FILS_SHA256 |
IE_RSN_AKM_SUITE_FT_OVER_FILS_SHA256 |
IE_RSN_AKM_SUITE_OSEN))
--
2.21.1
10 months
[PATCH] wiphy: add check for CMD_AUTH/CMD_ASSOC support
by James Prestwood
If the AP only supports an AKM which requires an auth protocol
CMD_AUTHENTICATE/CMD_ASSOCIATE must be supported or else the
auth protocol cannot be run. All the auth protocols are started
assuming that the card supports these commands, but the support
was never checked when parsing supported commands.
This patch will prevent any fullMAC cards from using
SAE/FILS/OWE. This was the same behavior as before, just an
earlier failure path.
---
src/wiphy.c | 48 ++++++++++++++++++++++++++++++++++++++----------
1 file changed, 38 insertions(+), 10 deletions(-)
diff --git a/src/wiphy.c b/src/wiphy.c
index b8e80b00..8abf1b0f 100644
--- a/src/wiphy.c
+++ b/src/wiphy.c
@@ -86,6 +86,7 @@ struct wiphy {
bool support_rekey_offload:1;
bool support_adhoc_rsn:1;
bool support_qos_set_map:1;
+ bool support_cmds_auth_assoc:1;
bool soft_rfkill : 1;
bool hard_rfkill : 1;
bool offchannel_tx_ok : 1;
@@ -328,16 +329,32 @@ bool wiphy_can_connect(struct wiphy *wiphy, struct scan_bss *bss)
rsn_info.group_management_cipher))
return false;
- /*
- * if the AP ONLY supports SAE/WPA3, then we can only connect
- * if the wiphy feature is supported. Otherwise the AP may list
- * SAE as one of the AKM's but also support PSK (hybrid). In
- * this case we still want to allow a connection even if SAE
- * is not supported.
- */
- if (IE_AKM_IS_SAE(rsn_info.akm_suites) &&
- !wiphy_has_feature(wiphy, NL80211_FEATURE_SAE))
- return false;
+
+ switch (rsn_info.akm_suites) {
+ case IE_RSN_AKM_SUITE_SAE_SHA256:
+ case IE_RSN_AKM_SUITE_FT_OVER_SAE_SHA256:
+ /*
+ * if the AP ONLY supports SAE/WPA3, then we can only
+ * connect if the wiphy feature is supported. Otherwise
+ * the AP may list SAE as one of the AKM's but also
+ * support PSK (hybrid). In this case we still want to
+ * allow a connection even if SAE is not supported.
+ */
+ if (!wiphy_has_feature(wiphy, NL80211_FEATURE_SAE) ||
+ !wiphy->support_cmds_auth_assoc)
+ return false;
+
+ break;
+ case IE_RSN_AKM_SUITE_OWE:
+ case IE_RSN_AKM_SUITE_FILS_SHA256:
+ case IE_RSN_AKM_SUITE_FILS_SHA384:
+ case IE_RSN_AKM_SUITE_FT_OVER_FILS_SHA256:
+ case IE_RSN_AKM_SUITE_FT_OVER_FILS_SHA384:
+ if (!wiphy->support_cmds_auth_assoc)
+ return false;
+
+ break;
+ }
} else if (r != -ENOENT)
return false;
@@ -614,6 +631,8 @@ static void parse_supported_commands(struct wiphy *wiphy,
{
uint16_t type, len;
const void *data;
+ bool auth = false;
+ bool assoc = false;
while (l_genl_attr_next(attr, &type, &len, &data)) {
uint32_t cmd = *(uint32_t *)data;
@@ -628,8 +647,17 @@ static void parse_supported_commands(struct wiphy *wiphy,
case NL80211_CMD_SET_QOS_MAP:
wiphy->support_qos_set_map = true;
break;
+ case NL80211_CMD_AUTHENTICATE:
+ auth = true;
+ break;
+ case NL80211_CMD_ASSOCIATE:
+ assoc = true;
+ break;
}
}
+
+ if (auth && assoc)
+ wiphy->support_cmds_auth_assoc = true;
}
static void parse_supported_ciphers(struct wiphy *wiphy, const void *data,
--
2.21.1
10 months
[PATCH 1/9] frame-xchg: Add facility to keep retransmitting after ACK
by Andrew Zaborowski
In some cases a P2P peer will ACK our frame but not reply on the first
attempt, and other implementations seem to handle this by going back to
retransmitting the frame at a high rate until it gets ACKed again, at
which point they will again give the peer a longer time to tx the
response frame. Implement the same logic here by adding a
retries_on_ack parameter that takes the number of additional times we
want to restart the normal retransmit counter after we received no
response frame on the first attempt. So passing 0 maintains the
current behaviour, 1 for 1 extra attempt, etc.
In effect we may retransmit a frame about 15 * (retry_on_ack + 1) *
<in-kernel retransmit limit> times. The kernel/driver retransmits a
frame a number of times if there's no ACK (I've seen about 20 normally)
at a high frequency, if that fails we retry the whole process 15 times
inside frame-xchg.c and if we still get no ACK at any point, we give up.
If we do get an ACK, we wait for a response frame and if we don't get
that we will optionally reset the retry counter and restart the whole
thing retry_on_ack times.
---
src/frame-xchg.c | 61 +++++++++++++++++++++++++++++++++---------------
src/frame-xchg.h | 4 ++--
2 files changed, 44 insertions(+), 21 deletions(-)
diff --git a/src/frame-xchg.c b/src/frame-xchg.c
index d69fff7c..a5a80ca2 100644
--- a/src/frame-xchg.c
+++ b/src/frame-xchg.c
@@ -107,6 +107,7 @@ struct frame_xchg_data {
unsigned int retry_cnt;
unsigned int retry_interval;
unsigned int resp_timeout;
+ unsigned int retries_on_ack;
bool in_frame_cb : 1;
bool stale : 1;
};
@@ -726,6 +727,9 @@ static bool frame_watch_remove_by_handler(uint64_t wdev_id, uint32_t group_id,
}
static void frame_xchg_tx_retry(struct frame_xchg_data *fx);
+static bool frame_xchg_resp_handle(const struct mmpdu_header *mpdu,
+ const void *body, size_t body_len,
+ int rssi, void *user_data);
static void frame_xchg_resp_cb(const struct mmpdu_header *mpdu,
const void *body, size_t body_len,
int rssi, void *user_data);
@@ -805,12 +809,20 @@ static void frame_xchg_timeout_cb(struct l_timeout *timeout,
frame_xchg_tx_retry(fx);
}
-static void frame_xchg_resp_timeout_cb(struct l_timeout *timeout,
+static void frame_xchg_listen_end_cb(struct l_timeout *timeout,
void *user_data)
{
struct frame_xchg_data *fx = user_data;
- frame_xchg_done(fx, 0);
+ if (!fx->retries_on_ack) {
+ frame_xchg_done(fx, 0);
+ return;
+ }
+
+ l_timeout_remove(fx->timeout);
+ fx->retries_on_ack--;
+ fx->retry_cnt = 0;
+ frame_xchg_tx_retry(fx);
}
static void frame_xchg_tx_status(struct frame_xchg_data *fx, bool acked)
@@ -850,17 +862,19 @@ static void frame_xchg_tx_status(struct frame_xchg_data *fx, bool acked)
fx->have_cookie = false;
l_debug("Processing an early frame");
- frame_xchg_resp_cb(fx->early_frame.mpdu, fx->early_frame.body,
- fx->early_frame.body_len,
- fx->early_frame.rssi, fx);
- frame_xchg_done(fx, 0);
+ if (frame_xchg_resp_handle(fx->early_frame.mpdu, fx->early_frame.body,
+ fx->early_frame.body_len,
+ fx->early_frame.rssi, fx))
+ return;
+
+ frame_xchg_listen_end_cb(NULL, fx);
return;
}
/* Txed frame ACKed, listen for response frames */
fx->timeout = l_timeout_create_ms(fx->resp_timeout,
- frame_xchg_resp_timeout_cb, fx,
+ frame_xchg_listen_end_cb, fx,
frame_xchg_timeout_destroy);
}
@@ -946,9 +960,9 @@ static void frame_xchg_tx_retry(struct frame_xchg_data *fx)
fx->retry_cnt++;
}
-static void frame_xchg_resp_cb(const struct mmpdu_header *mpdu,
- const void *body, size_t body_len,
- int rssi, void *user_data)
+static bool frame_xchg_resp_handle(const struct mmpdu_header *mpdu,
+ const void *body, size_t body_len,
+ int rssi, void *user_data)
{
struct frame_xchg_data *fx = user_data;
const struct l_queue_entry *entry;
@@ -957,10 +971,10 @@ static void frame_xchg_resp_cb(const struct mmpdu_header *mpdu,
l_debug("");
if (memcmp(mpdu->address_1, fx->tx_mpdu->address_2, 6))
- return;
+ return false;
if (memcmp(mpdu->address_2, fx->tx_mpdu->address_1, 6))
- return;
+ return false;
/*
* Is the received frame's BSSID same as the transmitted frame's
@@ -970,7 +984,7 @@ static void frame_xchg_resp_cb(const struct mmpdu_header *mpdu,
*/
if (memcmp(mpdu->address_3, fx->tx_mpdu->address_3, 6) &&
!util_mem_is_zero(mpdu->address_3, 6))
- return;
+ return false;
for (entry = l_queue_get_entries(fx->rx_watches);
entry; entry = entry->next) {
@@ -994,18 +1008,18 @@ static void frame_xchg_resp_cb(const struct mmpdu_header *mpdu,
* to just exit without touching anything.
*/
if (!fx->in_frame_cb)
- return;
+ return true;
fx->in_frame_cb = false;
if (done || fx->stale) {
fx->cb = NULL;
frame_xchg_done(fx, 0);
- return;
+ return true;
}
}
- return;
+ return false;
early_frame:
/*
@@ -1016,13 +1030,21 @@ early_frame:
* Save the response frame to be processed in the Tx done callback.
*/
if (fx->early_frame.mpdu)
- return;
+ return false;
hdr_len = (const uint8_t *) body - (const uint8_t *) mpdu;
fx->early_frame.mpdu = l_memdup(mpdu, body_len + hdr_len);
fx->early_frame.body = (const uint8_t *) fx->early_frame.mpdu + hdr_len;
fx->early_frame.body_len = body_len;
fx->early_frame.rssi = rssi;
+ return false;
+}
+
+static void frame_xchg_resp_cb(const struct mmpdu_header *mpdu,
+ const void *body, size_t body_len,
+ int rssi, void *user_data)
+{
+ frame_xchg_resp_handle(mpdu, body, body_len, rssi, user_data);
}
static bool frame_xchg_match(const void *a, const void *b)
@@ -1050,8 +1072,8 @@ static bool frame_xchg_match(const void *a, const void *b)
*/
void frame_xchg_startv(uint64_t wdev_id, struct iovec *frame, uint32_t freq,
unsigned int retry_interval, unsigned int resp_timeout,
- uint32_t group_id, frame_xchg_cb_t cb, void *user_data,
- va_list resp_args)
+ unsigned int retries_on_ack, uint32_t group_id,
+ frame_xchg_cb_t cb, void *user_data, va_list resp_args)
{
struct frame_xchg_data *fx;
size_t frame_len;
@@ -1095,6 +1117,7 @@ void frame_xchg_startv(uint64_t wdev_id, struct iovec *frame, uint32_t freq,
fx->freq = freq;
fx->retry_interval = retry_interval;
fx->resp_timeout = resp_timeout;
+ fx->retries_on_ack = retries_on_ack;
fx->cb = cb;
fx->user_data = user_data;
fx->group_id = group_id;
diff --git a/src/frame-xchg.h b/src/frame-xchg.h
index 1855492c..93d528ae 100644
--- a/src/frame-xchg.h
+++ b/src/frame-xchg.h
@@ -45,6 +45,6 @@ bool frame_watch_wdev_remove(uint64_t wdev_id);
void frame_xchg_startv(uint64_t wdev_id, struct iovec *frame, uint32_t freq,
unsigned int retry_interval, unsigned int resp_timeout,
- uint32_t group_id, frame_xchg_cb_t cb, void *user_data,
- va_list resp_args);
+ unsigned int retries_on_ack, uint32_t group_id,
+ frame_xchg_cb_t cb, void *user_data, va_list resp_args);
void frame_xchg_stop(uint64_t wdev_id);
--
2.20.1
10 months, 1 week
[PATCH] frame-xchg: Drop l_io read destroy handler
by Andrew Zaborowski
This function was intended to catch socket errors and destroy the group
but it would leak the l_io object if that happened, and if called on
ordinary shutdown it could cause a crash. Since we're now assuming
that the netlink socket operations never fail just remove it.
---
src/frame-xchg.c | 15 +--------------
1 file changed, 1 insertion(+), 14 deletions(-)
diff --git a/src/frame-xchg.c b/src/frame-xchg.c
index 131d5061..50351615 100644
--- a/src/frame-xchg.c
+++ b/src/frame-xchg.c
@@ -361,19 +361,6 @@ static bool frame_watch_group_io_read(struct l_io *io, void *user_data)
return true;
}
-static void frame_watch_group_io_destroy(void *user_data)
-{
- struct watch_group *group = user_data;
-
- group->io = NULL;
-
- if (l_queue_remove(watch_groups, group)) {
- l_error("Frame watch group socket closed");
-
- frame_watch_group_destroy(group);
- }
-}
-
static struct watch_group *frame_watch_group_new(uint64_t wdev_id, uint32_t id)
{
struct watch_group *group = l_new(struct watch_group, 1);
@@ -435,7 +422,7 @@ static struct watch_group *frame_watch_group_new(uint64_t wdev_id, uint32_t id)
l_io_set_close_on_destroy(group->io, true);
l_io_set_read_handler(group->io, frame_watch_group_io_read, group,
- frame_watch_group_io_destroy);
+ NULL);
group->write_queue = l_queue_new();
return group;
--
2.20.1
10 months, 1 week
[PATCH] monitor: Print WFD IE contents
by Andrew Zaborowski
Only print the WFD version 2.1.0 spec subelements which removed all the
low level video format details from the IEs so this code is much
shorter.
---
monitor/nlmon.c | 317 +++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 303 insertions(+), 14 deletions(-)
diff --git a/monitor/nlmon.c b/monitor/nlmon.c
index 087b374f..0aeaea31 100644
--- a/monitor/nlmon.c
+++ b/monitor/nlmon.c
@@ -325,6 +325,18 @@ static void print_hexdump(unsigned int level,
}
}
+static void print_address(unsigned int level, const char *label,
+ const unsigned char address[6])
+{
+ char addr[18];
+
+ snprintf(addr, sizeof(addr), "%02X:%02X:%02X:%02X:%02X:%02X",
+ address[0], address[1], address[2],
+ address[3], address[4], address[5]);
+
+ print_attr(level, "%s %s", label, addr);
+}
+
static const struct {
const uint8_t oui[3];
const char *str;
@@ -3097,7 +3109,6 @@ static void print_p2p_capability(unsigned int level, const char *label,
CHECK_CAPS_BIT(P2P_GROUP_CAP_IP_ALLOCATION,
"IP Address Allocation");
}
-#undef CHECK_CAPS_BIT
static void print_p2p_go_intent(unsigned int level, const char *label,
const void *data, uint16_t size)
@@ -3658,11 +3669,294 @@ static void print_p2p_attributes(unsigned int level, const char *label,
}
}
+static void print_wfd_device_info_flags(unsigned int level, const char *label,
+ uint16_t caps)
+{
+ static const char *dev_type[] = {
+ [WFD_DEV_INFO_TYPE_SOURCE] = "Source",
+ [WFD_DEV_INFO_TYPE_PRIMARY_SINK] = "Primary sink",
+ [WFD_DEV_INFO_TYPE_SECONDARY_SINK] = "Secondary sink",
+ [WFD_DEV_INFO_TYPE_DUAL_ROLE] = "Dual-role possible",
+ };
+ static const char *session_avail[] = {
+ [0] = "Not available for WFD Session",
+ [1] = "Available for WFD Session",
+ [2] = "Reserved (0b10)",
+ [3] = "Reserved (0b11)",
+ };
+
+ print_attr(level, "%s:", label);
+
+ print_attr(level + 1, "Device Type: %s",
+ dev_type[caps & WFD_DEV_INFO_DEVICE_TYPE]);
+ CHECK_CAPS_BIT(WFD_DEV_INFO_COUPLED_SINK_AT_SOURCE_OK,
+ "Coupled Sink Operation supported by WFD Source");
+ CHECK_CAPS_BIT(WFD_DEV_INFO_COUPLED_SINK_AT_SINK_OK,
+ "Coupled Sink Operation supported by WFD Sink");
+ print_attr(level + 1, "Session Availability: %s",
+ session_avail[(caps &
+ WFD_DEV_INFO_SESSION_AVAILABILITY) >> 4]);
+ CHECK_CAPS_BIT(WFD_DEV_INFO_SERVICE_DISCOVERY_SUPPORT,
+ "WFD Service Discovery (WSD) supported");
+ print_attr(level + 1, "Preferred Connectivity (PC): %s",
+ (caps & WFD_DEV_INFO_PREFER_TDLS_CONNECTIVITY) ?
+ "TLDS" : "P2P");
+ CHECK_CAPS_BIT(WFD_DEV_INFO_CONTENT_PROTECTION_SUPPORT,
+ "Content Protection using HDCP system 2.x supported");
+ CHECK_CAPS_BIT(WFD_DEV_INFO_8021AS_TIME_SYNC_SUPPORT,
+ "Time Synchronization using 802.1AS supported");
+ CHECK_CAPS_BIT(WFD_DEV_INFO_NO_AUDIO_AT_PRIMARY_SINK,
+ "WFD Primary Sink does not support audio rendering");
+ CHECK_CAPS_BIT(WFD_DEV_INFO_AUDIO_ONLY_AT_SOURCE,
+ "WFD Source supports audio-only element stream");
+ CHECK_CAPS_BIT(WFD_DEV_INFO_TDLS_PERSISTENT_GROUP,
+ "TDLS persistent group intended");
+ CHECK_CAPS_BIT(WFD_DEV_INFO_REINVOKE_TDLS_GROUP,
+ "Request for re-invocation of TDLS persistent group");
+
+ caps &= ~0x00ff;
+ if (caps)
+ print_attr(level + 1, "Reserved: 0x%04x", caps);
+}
+
+static void print_wfd_device_info(unsigned int level, const char *label,
+ const void *data, uint16_t size)
+{
+ const uint8_t *bytes = data;
+
+ if (size != 6) {
+ printf("malformed WFD %s\n", label);
+ return;
+ }
+
+ print_wfd_device_info_flags(level, label, l_get_be16(bytes + 0));
+
+ print_attr(level, "%s: Session Management Control port %i",
+ label, l_get_be16(bytes + 2));
+ print_attr(level, "%s: Maximum Throughput %i Mbps",
+ label, l_get_be16(bytes + 4));
+}
+
+static void print_wfd_coupled_sink_info(unsigned int level, const char *label,
+ const void *data, uint16_t size)
+{
+ const uint8_t *bytes = data;
+ static const char *status[4] = {
+ [0] = "Not couple/Available for Coupling",
+ [1] = "Coupled",
+ [2] = "Teardown Coupling",
+ [3] = "Reserved (0b11)",
+ };
+
+ if (size != 7) {
+ printf("malformed WFD %s\n", label);
+ return;
+ }
+
+ print_attr(level, "%s:", label);
+
+ print_attr(level + 1, "Status: %s", status[bytes[0] & 3]);
+
+ if (bytes[0] & ~3)
+ print_attr(level + 1, "Reserved: 0x%02x", bytes[0] & ~3);
+
+ print_address(level + 1, "Coupled Sink MAC Address", bytes + 1);
+}
+
+static void print_wfd_extended_caps(unsigned int level, const char *label,
+ const void *data, uint16_t size)
+{
+ const uint8_t *bytes = data;
+ uint16_t caps;
+
+ if (size != 2) {
+ printf("malformed WFD %s\n", label);
+ return;
+ }
+
+ print_attr(level, "%s:", label);
+
+ caps = l_get_be16(bytes + 0);
+ CHECK_CAPS_BIT(0x0001, "UIBC support");
+ CHECK_CAPS_BIT(0x0002, "I2C Read/Write support");
+ CHECK_CAPS_BIT(0x0004, "Preferred Display mode support");
+ CHECK_CAPS_BIT(0x0008, "Standby and Resume Control support");
+ CHECK_CAPS_BIT(0x0010, "TDLS Persistent support");
+ CHECK_CAPS_BIT(0x0020, "TDLS Persistent BSSID support");
+
+ if (caps)
+ print_attr(level + 1, "Reserved: 0x%04x", caps);
+}
+
+static void print_wfd_local_ip(unsigned int level, const char *label,
+ const void *data, uint16_t size)
+{
+ const uint8_t *bytes = data;
+
+ if (size != 5) {
+ printf("malformed WFD %s\n", label);
+ return;
+ }
+
+ if (bytes[0] != 1) {
+ print_attr(level, "%s: Unknown version", label);
+ return;
+ }
+
+ print_attr(level, "%s: %i.%i.%i.%i", label,
+ bytes[1], bytes[2], bytes[3], bytes[4]);
+}
+
+static void print_wfd_session_info(unsigned int level, const char *label,
+ const void *data, uint16_t size)
+{
+ int i = 1;
+
+ if (size % 24 != 0) {
+ printf("malformed WFD %s\n", label);
+ return;
+ }
+
+ print_attr(level, "%s:", label);
+
+ while (size) {
+ const uint8_t *bytes = data;
+
+ if (bytes[0] != 23) {
+ print_attr(level + 1,
+ "malformed WFD Device Info Descriptor");
+ continue;
+ }
+
+ print_attr(level + 1, "Device Info for client %i:", i++);
+
+ if (bytes[0] != 1) {
+ print_attr(level, "%s: Unknown version", label);
+ return;
+ }
+
+ print_address(level + 2, "Device address", bytes + 1);
+
+ if (util_mem_is_zero(bytes + 7, 6))
+ print_attr(level+ + 2, "Not associated to an "
+ "infrastructure AP");
+ else
+ print_address(level + 2, "Associated BSSID", bytes + 7);
+
+ print_wfd_device_info_flags(level + 2, "WFD Device Information",
+ l_get_be16(bytes + 13));
+ print_attr(level + 2, "WFD Device Maximum Throughput %i Mbps",
+ l_get_be16(bytes + 15));
+ print_wfd_coupled_sink_info(level + 2,
+ "Coupled Sink Information",
+ bytes + 17, 7);
+
+ data += 24;
+ size -= 24;
+ }
+}
+
+static void print_wfd_r2_device_info(unsigned int level, const char *label,
+ const void *data, uint16_t size)
+{
+ static const char *dev_type[4] = {
+ [0] = "WFD R2 Source",
+ [1] = "WFD R2 Primary sink",
+ [2] = "Reserved (0b10)",
+ [3] = "Dual-role possible",
+ };
+ const uint8_t *bytes = data;
+ uint16_t caps;
+
+ if (size < 2) {
+ printf("malformed WFD %s\n", label);
+ return;
+ }
+
+ print_attr(level, "%s:", label);
+
+ caps = l_get_be16(bytes + 0);
+ print_attr(level + 1, "WFD R2 Device Type: %s", dev_type[caps & 3]);
+
+ if (caps & ~3)
+ print_attr(level + 1, "Reserved: 0x%04x", caps & ~3);
+}
+
+static struct attr_entry wfd_subelem_entry[] = {
+ { WFD_SUBELEM_WFD_DEVICE_INFORMATION, "WFD Device Information",
+ ATTR_CUSTOM, { .function = print_wfd_device_info } },
+ { WFD_SUBELEM_ASSOCIATED_BSSID, "Associated BSSID",
+ ATTR_ADDRESS },
+ { WFD_SUBELEM_COUPLED_SINK_INFORMATION, "Coupled Sink Information",
+ ATTR_CUSTOM, { .function = print_wfd_coupled_sink_info } },
+ { WFD_SUBELEM_EXTENDED_CAPABILITY, "WFD Extended Capability",
+ ATTR_CUSTOM, { .function = print_wfd_extended_caps } },
+ { WFD_SUBELEM_LOCAL_IP_ADDRESS, "Local IP Address",
+ ATTR_CUSTOM, { .function = print_wfd_local_ip } },
+ { WFD_SUBELEM_SESION_INFORMATION, "WFD Session Information",
+ ATTR_CUSTOM, { .function = print_wfd_session_info } },
+ { WFD_SUBELEM_ALTERNATIVE_MAC_ADDRESS, "Alternative MAC Address",
+ ATTR_ADDRESS },
+ { WFD_SUBELEM_R2_DEVICE_INFORMATION, "WFD R2 Device Information",
+ ATTR_CUSTOM, { .function = print_wfd_r2_device_info } },
+ { },
+};
+
+static void print_wfd_subelements(unsigned int level, const char *label,
+ const void *data, uint16_t size)
+{
+ struct wfd_subelem_iter iter;
+ int i;
+
+ print_attr(level, "%s: len %u", label, size);
+
+ wfd_subelem_iter_init(&iter, data, size);
+
+ while (wfd_subelem_iter_next(&iter)) {
+ uint16_t type = wfd_subelem_iter_get_type(&iter);
+ uint16_t len = wfd_subelem_iter_get_length(&iter);
+ const void *attr = wfd_subelem_iter_get_data(&iter);
+ struct attr_entry *entry = NULL;
+
+ for (i = 0; wfd_subelem_entry[i].str; i++) {
+ if (wfd_subelem_entry[i].attr == type) {
+ entry = &wfd_subelem_entry[i];
+ break;
+ }
+ }
+
+ if (!entry)
+ continue;
+
+ switch (entry->type) {
+ case ATTR_ADDRESS:
+ if (len != 6) {
+ print_attr(level + 1, "malformed %s",
+ entry->str);
+ break;
+ }
+
+ print_address(level + 1, entry->str, attr);
+ break;
+ default:
+ if (entry->function)
+ entry->function(level + 1, entry->str, attr,
+ len);
+ else {
+ print_attr(level + 1, "Type: 0x%02x: len %u",
+ type, len);
+ print_hexdump(level + 2, attr, len);
+ }
+ break;
+ }
+ }
+}
+
static void print_management_ies(unsigned int level, const char *label,
const void *data, uint16_t size)
{
- void *wsc_data, *p2p_data;
- ssize_t wsc_len, p2p_len;
+ void *wsc_data, *p2p_data, *wfd_data;
+ ssize_t wsc_len, p2p_len, wfd_len;
print_ie(level, label, data, size);
@@ -3679,18 +3973,13 @@ static void print_management_ies(unsigned int level, const char *label,
p2p_data, p2p_len);
l_free(p2p_data);
}
-}
-
-static void print_address(unsigned int level, const char *label,
- const unsigned char address[6])
-{
- char addr[18];
- snprintf(addr, sizeof(addr), "%02X:%02X:%02X:%02X:%02X:%02X",
- address[0], address[1], address[2],
- address[3], address[4], address[5]);
-
- print_attr(level, "%s %s", label, addr);
+ wfd_data = ie_tlv_extract_wfd_payload(data, size, &wfd_len);
+ if (wfd_data) {
+ print_wfd_subelements(level + 1, "WFD Payload",
+ wfd_data, wfd_len);
+ l_free(wfd_data);
+ }
}
static void print_reason_code(unsigned int level, const char *label,
--
2.20.1
10 months, 1 week
[PATCH v3 1/5] util: add util_is_valid_sta_address
by James Prestwood
Checks that that address is neither broadcast or group
---
src/util.c | 5 +++++
src/util.h | 1 +
2 files changed, 6 insertions(+)
diff --git a/src/util.c b/src/util.c
index 0c41ceb5..13b01c81 100644
--- a/src/util.c
+++ b/src/util.c
@@ -166,6 +166,11 @@ bool util_is_broadcast_address(const uint8_t *addr)
return !memcmp(addr, bcast_addr, 6);
}
+bool util_is_valid_sta_address(const uint8_t *addr)
+{
+ return !util_is_broadcast_address(addr) && !util_is_group_address(addr);
+}
+
/* This function assumes that identity is not bigger than 253 bytes */
const char *util_get_domain(const char *identity)
{
diff --git a/src/util.h b/src/util.h
index dfd1c847..edc6e777 100644
--- a/src/util.h
+++ b/src/util.h
@@ -38,6 +38,7 @@ const char *util_address_to_string(const uint8_t *addr);
bool util_string_to_address(const char *str, uint8_t *addr);
bool util_is_group_address(const uint8_t *addr);
bool util_is_broadcast_address(const uint8_t *addr);
+bool util_is_valid_sta_address(const uint8_t *addr);
const char *util_get_domain(const char *identity);
const char *util_get_username(const char *identity);
--
2.21.1
10 months, 1 week
[PATCH v2 1/4] station: support full MAC randomization and override
by James Prestwood
This patch adds two new options to a network provisioning file:
AlwaysRandomizeAddress={true,false}
If true, IWD will randomize the MAC address on each connection to this
network. The address does not persists between connections, any new
connection will result in a different MAC.
AddressOverride=<MAC>
If set, the MAC address will be set to <MAC> assuming its a valid MAC
address.
These two options should not be used together, and will only take effect
if [General].AddressRandomization is set to 'network' in the IWD
config file.
If neither of these options are set, and [General].AddressRandomization
is set to 'network', the default behavior remains the same; the MAC
will be generated deterministically on a per-network basis.
---
src/station.c | 38 ++++++++++++++++++++++++++++++++++++++
1 file changed, 38 insertions(+)
v2:
* Removed check for AddressRandomization=network. This is checked in
netdev.
diff --git a/src/station.c b/src/station.c
index 36b41f64..47af726e 100644
--- a/src/station.c
+++ b/src/station.c
@@ -875,6 +875,10 @@ static struct handshake_state *station_handshake_setup(struct station *station,
struct handshake_state *hs;
const char *ssid;
uint32_t eapol_proto_version;
+ const char *value;
+ bool full_random;
+ bool override = false;
+ uint8_t new_addr[ETH_ALEN];
hs = netdev_handshake_state_new(station->netdev);
@@ -934,6 +938,40 @@ static struct handshake_state *station_handshake_setup(struct station *station,
IE_RSN_AKM_SUITE_FT_OVER_FILS_SHA384))
hs->erp_cache = erp_cache_get(network_get_ssid(network));
+ /*
+ * We have three possible options here:
+ * 1. per-network MAC generation (default, no option in network config)
+ * 2. per-network full MAC randomization
+ * 3. per-network MAC override
+ */
+
+ if (!l_settings_get_bool(settings, "Settings",
+ "AlwaysRandomizeAddress",
+ &full_random))
+ full_random = false;
+
+ value = l_settings_get_value(settings, "Settings",
+ "AddressOverride");
+ if (value)
+ override = true;
+
+ if (override && full_random) {
+ l_warn("Cannot use both AlwaysRandomizeAddress and "
+ "AddressOverride concurrently, defaulting to override");
+ full_random = false;
+ }
+
+ if (override) {
+ if (util_string_to_address(value, new_addr))
+ handshake_state_set_supplicant_address(hs, new_addr);
+ else
+ l_warn("[Network].AddressOverride is not a valid "
+ "MAC address");
+ } else if (full_random) {
+ wiphy_generate_random_address(wiphy, new_addr);
+ handshake_state_set_supplicant_address(hs, new_addr);
+ }
+
return hs;
no_psk:
--
2.21.1
10 months, 1 week