All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/9] frame-xchg: Add facility to keep retransmitting after ACK
@ 2020-03-19 21:12 Andrew Zaborowski
  2020-03-19 21:12 ` [PATCH 2/9] frame-xchg: Add frame_xchg_start Andrew Zaborowski
                   ` (8 more replies)
  0 siblings, 9 replies; 13+ messages in thread
From: Andrew Zaborowski @ 2020-03-19 21:12 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 7214 bytes --]

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

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 2/9] frame-xchg: Add frame_xchg_start
  2020-03-19 21:12 [PATCH 1/9] frame-xchg: Add facility to keep retransmitting after ACK Andrew Zaborowski
@ 2020-03-19 21:12 ` Andrew Zaborowski
  2020-03-20 15:24   ` Denis Kenzior
  2020-03-19 21:12 ` [PATCH 3/9] wscutil: Implement wsc_build_probe_response Andrew Zaborowski
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 13+ messages in thread
From: Andrew Zaborowski @ 2020-03-19 21:12 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 1867 bytes --]

---
 src/frame-xchg.c | 13 +++++++++++++
 src/frame-xchg.h |  4 ++++
 2 files changed, 17 insertions(+)

diff --git a/src/frame-xchg.c b/src/frame-xchg.c
index a5a80ca2..827d36e0 100644
--- a/src/frame-xchg.c
+++ b/src/frame-xchg.c
@@ -1070,6 +1070,19 @@ static bool frame_xchg_match(const void *a, const void *b)
  * @resp_timeout was 0.  @frame is an iovec array terminated by an iovec
  * struct with NULL-iov_base.
  */
+void frame_xchg_start(uint64_t wdev_id, struct iovec *frame, uint32_t freq,
+			unsigned int retry_interval, unsigned int resp_timeout,
+			unsigned int retries_on_ack, uint32_t group_id,
+			frame_xchg_cb_t cb, void *user_data, ...)
+{
+	va_list args;
+
+	va_start(args, user_data);
+	frame_xchg_startv(wdev_id, frame, freq, retry_interval, resp_timeout,
+				retries_on_ack, group_id, cb, user_data, args);
+	va_end(args);
+}
+
 void frame_xchg_startv(uint64_t wdev_id, struct iovec *frame, uint32_t freq,
 			unsigned int retry_interval, unsigned int resp_timeout,
 			unsigned int retries_on_ack, uint32_t group_id,
diff --git a/src/frame-xchg.h b/src/frame-xchg.h
index 93d528ae..45b0e5fa 100644
--- a/src/frame-xchg.h
+++ b/src/frame-xchg.h
@@ -43,6 +43,10 @@ bool frame_watch_add(uint64_t wdev_id, uint32_t group, uint16_t frame_type,
 bool frame_watch_group_remove(uint64_t wdev_id, uint32_t group);
 bool frame_watch_wdev_remove(uint64_t wdev_id);
 
+void frame_xchg_start(uint64_t wdev_id, struct iovec *frame, uint32_t freq,
+			unsigned int retry_interval, unsigned int resp_timeout,
+			unsigned int retries_on_ack, uint32_t group_id,
+			frame_xchg_cb_t cb, void *user_data, ...);
 void frame_xchg_startv(uint64_t wdev_id, struct iovec *frame, uint32_t freq,
 			unsigned int retry_interval, unsigned int resp_timeout,
 			unsigned int retries_on_ack, uint32_t group_id,
-- 
2.20.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 3/9] wscutil: Implement wsc_build_probe_response
  2020-03-19 21:12 [PATCH 1/9] frame-xchg: Add facility to keep retransmitting after ACK Andrew Zaborowski
  2020-03-19 21:12 ` [PATCH 2/9] frame-xchg: Add frame_xchg_start Andrew Zaborowski
@ 2020-03-19 21:12 ` Andrew Zaborowski
  2020-03-19 21:12 ` [PATCH 4/9] wsc: Don't start connections until Cancel finishes Andrew Zaborowski
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 13+ messages in thread
From: Andrew Zaborowski @ 2020-03-19 21:12 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 4722 bytes --]

---
 src/wscutil.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++
 src/wscutil.h |  3 ++
 2 files changed, 96 insertions(+)

diff --git a/src/wscutil.c b/src/wscutil.c
index 99a74d1e..4f22bd83 100644
--- a/src/wscutil.c
+++ b/src/wscutil.c
@@ -31,6 +31,7 @@
 
 #include <ell/ell.h>
 
+#include "src/util.h"
 #include "src/wscutil.h"
 
 const unsigned char wsc_wfa_oui[3] = { 0x00, 0x37, 0x2a };
@@ -1759,6 +1760,12 @@ static uint8_t *wsc_attr_builder_free(struct wsc_attr_builder *builder,
 	return ret;
 }
 
+static void build_ap_setup_locked(struct wsc_attr_builder *builder, bool locked)
+{
+	wsc_attr_builder_start_attr(builder, WSC_ATTR_AP_SETUP_LOCKED);
+	wsc_attr_builder_put_u8(builder, locked ? 0x01 : 0x00);
+}
+
 static void build_association_state(struct wsc_attr_builder *builder,
 					enum wsc_association_state state)
 {
@@ -2014,6 +2021,22 @@ static void build_r_snonce2(struct wsc_attr_builder *builder,
 	wsc_attr_builder_put_bytes(builder, nonce, 16);
 }
 
+static void build_selected_registrar(struct wsc_attr_builder *builder,
+							bool selected)
+{
+	wsc_attr_builder_start_attr(builder, WSC_ATTR_SELECTED_REGISTRAR);
+	wsc_attr_builder_put_u8(builder, selected ? 0x01 : 0x00);
+}
+
+static void build_selected_registrar_configuration_methods(
+					struct wsc_attr_builder *builder,
+					uint16_t config_methods)
+{
+	wsc_attr_builder_start_attr(builder,
+			WSC_ATTR_SELECTED_REGISTRAR_CONFIGURATION_METHODS);
+	wsc_attr_builder_put_u16(builder, config_methods);
+}
+
 static void build_ssid(struct wsc_attr_builder *builder, const uint8_t *ssid,
 							size_t ssid_len)
 {
@@ -2129,6 +2152,76 @@ done:
 	return ret;
 }
 
+uint8_t *wsc_build_probe_response(
+		const struct wsc_probe_response *probe_response,
+		size_t *out_len)
+{
+	struct wsc_attr_builder *builder;
+	uint8_t *ret;
+
+	builder = wsc_attr_builder_new(512);
+	build_version(builder, 0x10);
+	build_wsc_state(builder, probe_response->state);
+
+	if (probe_response->ap_setup_locked)
+		build_ap_setup_locked(builder, true);
+
+	if (probe_response->selected_registrar) {
+		build_selected_registrar(builder, true);
+		build_device_password_id(builder,
+				probe_response->device_password_id);
+		build_selected_registrar_configuration_methods(builder,
+				probe_response->selected_reg_config_methods);
+	}
+
+	build_response_type(builder, probe_response->response_type);
+	build_uuid_e(builder, probe_response->uuid_e);
+	build_manufacturer(builder, probe_response->manufacturer);
+	build_model_name(builder, probe_response->model_name);
+	build_model_number(builder, probe_response->model_number);
+	build_serial_number(builder, probe_response->serial_number);
+	build_primary_device_type(builder,
+					&probe_response->primary_device_type);
+	build_device_name(builder, probe_response->device_name);
+	build_configuration_methods(builder, probe_response->config_methods);
+
+	if (probe_response->rf_bands & (probe_response->rf_bands - 1))
+		build_rf_bands(builder, probe_response->rf_bands);
+
+	if (!probe_response->version2)
+		goto done;
+
+	START_WFA_VENDOR_EXTENSION();
+
+	if (!util_mem_is_zero(probe_response->authorized_macs, 30)) {
+		int count;
+
+		for (count = 1; count < 5; count++)
+			if (util_mem_is_zero(probe_response->authorized_macs +
+						count * 6, 30 - count * 6))
+				break;
+
+		wsc_attr_builder_put_u8(builder,
+					WSC_WFA_EXTENSION_AUTHORIZED_MACS);
+		wsc_attr_builder_put_u8(builder, count * 6);
+		wsc_attr_builder_put_bytes(builder,
+					probe_response->authorized_macs,
+					count * 6);
+	}
+
+	if (probe_response->reg_config_methods) {
+		wsc_attr_builder_put_u8(builder,
+			WSC_WFA_EXTENSION_REGISTRAR_CONFIGRATION_METHODS);
+		wsc_attr_builder_put_u8(builder, 2);
+		wsc_attr_builder_put_u16(builder,
+					probe_response->reg_config_methods);
+	}
+
+done:
+	ret = wsc_attr_builder_free(builder, false, out_len);
+	return ret;
+}
+
 uint8_t *wsc_build_association_request(
 		const struct wsc_association_request *association_request,
 		size_t *out_len)
diff --git a/src/wscutil.h b/src/wscutil.h
index 0d06a60f..fc28a01e 100644
--- a/src/wscutil.h
+++ b/src/wscutil.h
@@ -606,6 +606,9 @@ uint8_t *wsc_build_credential(const struct wsc_credential *in, size_t *out_len);
 
 uint8_t *wsc_build_probe_request(const struct wsc_probe_request *probe_request,
 				size_t *out_len);
+uint8_t *wsc_build_probe_response(
+		const struct wsc_probe_response *probe_response,
+		size_t *out_len);
 uint8_t *wsc_build_association_request(
 		const struct wsc_association_request *association_request,
 		size_t *out_len);
-- 
2.20.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 4/9] wsc: Don't start connections until Cancel finishes
  2020-03-19 21:12 [PATCH 1/9] frame-xchg: Add facility to keep retransmitting after ACK Andrew Zaborowski
  2020-03-19 21:12 ` [PATCH 2/9] frame-xchg: Add frame_xchg_start Andrew Zaborowski
  2020-03-19 21:12 ` [PATCH 3/9] wscutil: Implement wsc_build_probe_response Andrew Zaborowski
@ 2020-03-19 21:12 ` Andrew Zaborowski
  2020-03-19 21:12 ` [PATCH 5/9] tools: Add utility to tx Probe Requests Andrew Zaborowski
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 13+ messages in thread
From: Andrew Zaborowski @ 2020-03-19 21:12 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 930 bytes --]

Return busy from StartPin and PushButton if the Cancel method is still
running.
---
 src/wsc.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/wsc.c b/src/wsc.c
index 393e8d8d..e9ebe5f5 100644
--- a/src/wsc.c
+++ b/src/wsc.c
@@ -1111,7 +1111,7 @@ static struct l_dbus_message *wsc_push_button(struct l_dbus *dbus,
 	if (!l_dbus_message_get_arguments(message, ""))
 		return dbus_error_invalid_args(message);
 
-	if (wsc->pending_connect)
+	if (wsc->pending_connect || wsc->pending_cancel)
 		return dbus_error_busy(message);
 
 	wsc->pending_connect = l_dbus_message_ref(message);
@@ -1150,7 +1150,7 @@ static struct l_dbus_message *wsc_start_pin(struct l_dbus *dbus,
 
 	l_debug("");
 
-	if (wsc->pending_connect)
+	if (wsc->pending_connect || wsc->pending_cancel)
 		return dbus_error_busy(message);
 
 	if (!l_dbus_message_get_arguments(message, "s", &pin))
-- 
2.20.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 5/9] tools: Add utility to tx Probe Requests
  2020-03-19 21:12 [PATCH 1/9] frame-xchg: Add facility to keep retransmitting after ACK Andrew Zaborowski
                   ` (2 preceding siblings ...)
  2020-03-19 21:12 ` [PATCH 4/9] wsc: Don't start connections until Cancel finishes Andrew Zaborowski
@ 2020-03-19 21:12 ` Andrew Zaborowski
  2020-03-19 21:12 ` [PATCH 6/9] p2putil: Add WFD IE parsing utilities Andrew Zaborowski
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 13+ messages in thread
From: Andrew Zaborowski @ 2020-03-19 21:12 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 9681 bytes --]

---
This is something I used for testing scanning, not sure if it's really
useful but it can be modified to send out other frames as needed.  I'm
not aware of any tool to transmit test frames.
---
 .gitignore        |   1 +
 Makefile.am       |   9 ++
 tools/probe-req.c | 302 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 312 insertions(+)
 create mode 100644 tools/probe-req.c

diff --git a/.gitignore b/.gitignore
index 54a765a5..93fec4f7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -34,6 +34,7 @@ wired/ead.service
 tools/hwsim
 tools/hwsim.1
 tools/test-runner
+tools/probe-req
 unit/test-cmac-aes
 unit/test-arc4
 unit/test-hmac-md5
diff --git a/Makefile.am b/Makefile.am
index da6e3f25..b54690a8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -339,6 +339,15 @@ man_MANS += wired/ead.8
 endif
 endif
 
+noinst_PROGRAMS += tools/probe-req
+
+tools_probe_req_SOURCES = tools/probe-req.c src/mpdu.h src/mpdu.c \
+					src/ie.h src/ie.c \
+					src/nl80211util.h src/nl80211util.c \
+					src/util.h src/util.c \
+					src/common.h src/common.c
+tools_probe_req_LDADD = $(ell_ldadd)
+
 if HWSIM
 bin_PROGRAMS += tools/hwsim
 
diff --git a/tools/probe-req.c b/tools/probe-req.c
new file mode 100644
index 00000000..7ec8e3af
--- /dev/null
+++ b/tools/probe-req.c
@@ -0,0 +1,302 @@
+/*
+ *
+ *  Wireless daemon for Linux
+ *
+ *  Copyright (C) 2020  Intel Corporation. All rights reserved.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <unistd.h>
+
+#include <ell/ell.h>
+
+#include "linux/nl80211.h"
+
+#include "src/mpdu.h"
+#include "src/nl80211util.h"
+
+static struct l_genl *genl;
+static struct l_genl_family *nl80211;
+static int exit_status;
+static uint64_t wdev_id;
+static uint8_t wdev_addr[6];
+static uint32_t freq;
+
+static const uint8_t probe_req_body[] = {
+	/* SSID */
+	0x00, 0x07, 'D', 'I', 'R', 'E', 'C', 'T', '-',
+	/* Supported Rates */
+	0x01, 0x08, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
+	/* DS Parameter Set */
+	0x03, 0x01, 0x00,
+	/* HT Capabilities */
+	0x2d, 0x1a, 0xef, 0x11, 0x17, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x2c, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	/* WPS */
+	0xdd, 0x6c, 0x00, 0x50, 0xf2, 0x04,
+	/* > Version */
+	0x10, 0x4a, 0x00, 0x01, 0x10,
+	/* > Request Type */
+	0x10, 0x3a, 0x00, 0x01, 0x00,
+	/* > Config Methods */
+	0x10, 0x08, 0x00, 0x02, 0x13, 0x80,
+	/* > UUID E */
+	0x10, 0x47, 0x00, 0x10, 0x46, 0x92, 0x49, 0x6f, 0xce, 0x1e, 0x5f, 0xd1,
+	0xa5, 0x45, 0x9b, 0x1c, 0xa5, 0xde, 0xb9, 0x41,
+	/* > Primary Device Type */
+	0x10, 0x54, 0x00, 0x08, 0x00, 0x01, 0x00, 0x50, 0xf2, 0x04, 0x00, 0x01,
+	/* > RF Bands */
+	0x10, 0x3c, 0x00, 0x01, 0x01,
+	/* > Association State */
+	0x10, 0x02, 0x00, 0x02, 0x00, 0x00,
+	/* > Configuration Error */
+	0x10, 0x09, 0x00, 0x02, 0x00, 0x00,
+	/* > Device Password ID */
+	0x10, 0x12, 0x00, 0x02, 0x00, 0x00,
+	/* > Manufacturer */
+	0x10, 0x21, 0x00, 0x01, 0x20,
+	/* > Model Name */
+	0x10, 0x23, 0x00, 0x01, 0x20,
+	/* > Model Numbers */
+	0x10, 0x24, 0x00, 0x01, 0x20,
+	/* > Device Name */
+	0x10, 0x11, 0x00, 0x04, 't', 'e', 's', 't',
+	/* > Vendor Extension > Version2 */
+	0x10, 0x49, 0x00, 0x06, 0x00, 0x37, 0x2a, 0x00, 0x01, 0x20,
+	/* P2P */
+	0xdd, 0x11, 0x50, 0x6f, 0x9a, 0x09,
+	/* > P2P Capability */
+	0x02, 0x02, 0x00, 0x04, 0x00,
+	/* > Listen Channel */
+	0x06, 0x05, 0x00, 'X', 'X', 0x04, 0x51, 0x01,
+};
+
+static void frame_cb(struct l_genl_msg *msg, void *user_data)
+{
+	int err = l_genl_msg_get_error(msg);
+
+	if (err < 0) {
+		l_error("CMD_FRAME failed: %s (%i)", strerror(-err), -err);
+		exit_status = EXIT_FAILURE;
+	} else {
+		l_info("Frame queued");
+		exit_status = EXIT_SUCCESS;
+	}
+
+	l_main_quit();
+}
+
+static void get_interface_callback(struct l_genl_msg *msg, void *user_data)
+{
+	uint32_t ifindex;
+	uint32_t iftype;
+	const char *ifname;
+	const uint8_t *ifaddr;
+	uint64_t cur_wdev_id;
+	struct ifreq ifr;
+	int sock;
+	int r;
+
+	/*
+	 * For now hoose the first interface with iftype station, require it
+	 * to be UP and have an ifindex.
+	 */
+
+	if (wdev_id)
+		return;
+
+	if (nl80211_parse_attrs(msg, NL80211_ATTR_IFINDEX, &ifindex,
+					NL80211_ATTR_WDEV, &cur_wdev_id,
+					NL80211_ATTR_IFTYPE, &iftype,
+					NL80211_ATTR_IFNAME, &ifname,
+					NL80211_ATTR_MAC, &ifaddr,
+					NL80211_ATTR_UNSPEC) < 0)
+		return;
+
+	if (iftype != NL80211_IFTYPE_STATION)
+		return;
+
+	sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
+	if (sock == -1)
+		return;
+
+	memset(&ifr, 0, sizeof(ifr));
+	l_strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+	r = ioctl(sock, SIOCGIFFLAGS, &ifr);
+	close(sock);
+
+	/* IFF_RUNNING not required */
+	if (r == -1 || !(ifr.ifr_flags & IFF_UP))
+		return;
+
+	l_info("Selected interface %s", ifname);
+	wdev_id = cur_wdev_id;
+	memcpy(wdev_addr, ifaddr, 6);
+}
+
+static void get_interface_done(void *user_data)
+{
+	struct l_genl_msg *msg;
+	uint8_t frame_buf[256] __attribute__ ((aligned));
+	struct mmpdu_header *hdr = (void *) frame_buf;
+	static const uint8_t bcast_addr[6] =
+		{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+	size_t frame_len;
+
+	if (!wdev_id) {
+		l_error("No suitable interface found");
+		exit_status = EXIT_FAILURE;
+		l_main_quit();
+		return;
+	}
+
+	memset(frame_buf, 0, sizeof(*hdr));
+	hdr->fc.protocol_version = 0;
+	hdr->fc.type = MPDU_TYPE_MANAGEMENT;
+	hdr->fc.subtype = MPDU_MANAGEMENT_SUBTYPE_PROBE_REQUEST;
+	memcpy(hdr->address_1, bcast_addr, 6);	/* DA */
+	memcpy(hdr->address_2, wdev_addr, 6);	/* SA */
+	memcpy(hdr->address_3, bcast_addr, 6);	/* BSSID */
+	frame_len = (uint8_t *) mmpdu_body(hdr) - (uint8_t *) hdr;
+
+	memcpy((void *) mmpdu_body(hdr), probe_req_body, sizeof(probe_req_body));
+	frame_len += sizeof(probe_req_body);
+
+	msg = l_genl_msg_new_sized(NL80211_CMD_FRAME, 128 + frame_len);
+	l_genl_msg_append_attr(msg, NL80211_ATTR_WDEV, 8, &wdev_id);
+
+	if (freq) {
+		l_genl_msg_append_attr(msg, NL80211_ATTR_WIPHY_FREQ, 4, &freq);
+		l_genl_msg_append_attr(msg, NL80211_ATTR_OFFCHANNEL_TX_OK, 0,
+					NULL);
+	}
+
+	l_genl_msg_append_attr(msg, NL80211_ATTR_FRAME, frame_len, frame_buf);
+	l_genl_msg_append_attr(msg, NL80211_ATTR_DONT_WAIT_FOR_ACK, 0, NULL);
+	l_genl_msg_append_attr(msg, NL80211_ATTR_TX_NO_CCK_RATE, 0, NULL);
+
+	if (!l_genl_family_send(nl80211, msg, frame_cb, user_data, NULL)) {
+		l_error("l_genl_family_send failed");
+		exit_status = EXIT_FAILURE;
+		l_main_quit();
+		return;
+	}
+}
+
+static void dump_interfaces(void)
+{
+	struct l_genl_msg *msg;
+
+	msg = l_genl_msg_new(NL80211_CMD_GET_INTERFACE);
+	if (!l_genl_family_dump(nl80211, msg, get_interface_callback,
+				NULL, get_interface_done)) {
+		l_genl_msg_unref(msg);
+		l_error("Getting nl80211 interface information failed");
+		exit_status = EXIT_FAILURE;
+		l_main_quit();
+		return;
+	}
+}
+
+static void family_discovered(const struct l_genl_family_info *info,
+							void *user_data)
+{
+	if (!strcmp(l_genl_family_info_get_name(info), NL80211_GENL_NAME))
+		nl80211 = l_genl_family_new(genl, NL80211_GENL_NAME);
+}
+
+static void discovery_done(void *user_data)
+{
+	if (!nl80211) {
+		l_error("nl80211 doesn't exist.\n"
+			"Load it manually using modprobe cfg80211");
+		goto quit;
+	}
+
+	dump_interfaces();
+	return;
+
+quit:
+	exit_status = EXIT_FAILURE;
+	l_main_quit();
+}
+
+int main(int argc, char *argv[])
+{
+	if (argc >= 2) {
+		char *endp;
+
+		if (!strcmp(argv[1], "-h")) {
+			fprintf(stderr,
+				"Usage: %s [<frequency>]\n\n"
+				"Send out a broadcast Probe Request frame.  "
+				"A wireless interface must be UP.  If a "
+				"frequency is not given, the frame is "
+				"transmitted on the current channel.\n",
+				argv[0]);
+			return EXIT_SUCCESS;
+		}
+
+		freq = strtol(argv[1], &endp, 0);
+
+		if (*endp != '\0') {
+			fprintf(stderr, "Can't parse '%s'\n", endp);
+			return EXIT_FAILURE;
+		}
+	}
+
+	if (!l_main_init())
+		return EXIT_FAILURE;
+
+	l_log_set_stderr();
+	exit_status = EXIT_FAILURE;
+
+	genl = l_genl_new();
+	if (!genl) {
+		l_error("Failed to initialize generic netlink");
+		goto done;
+	}
+
+	if (!l_genl_discover_families(genl, family_discovered, NULL,
+						discovery_done)) {
+		l_error("Unable to start family discovery");
+		l_genl_unref(genl);
+		goto done;
+	}
+
+	l_main_run();
+
+	l_genl_family_free(nl80211);
+	l_genl_unref(genl);
+
+done:
+	l_main_exit();
+
+	return exit_status;
+}
-- 
2.20.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 6/9] p2putil: Add WFD IE parsing utilities
  2020-03-19 21:12 [PATCH 1/9] frame-xchg: Add facility to keep retransmitting after ACK Andrew Zaborowski
                   ` (3 preceding siblings ...)
  2020-03-19 21:12 ` [PATCH 5/9] tools: Add utility to tx Probe Requests Andrew Zaborowski
@ 2020-03-19 21:12 ` Andrew Zaborowski
  2020-03-19 21:12 ` [PATCH 7/9] ie: Add ie_tlv_extract_wfd_payload Andrew Zaborowski
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 13+ messages in thread
From: Andrew Zaborowski @ 2020-03-19 21:12 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 4096 bytes --]

Only add constants for parsing the Device Information subelement as that
is the main thing we care about in P2P code.  And since our own WFD IEs
will likely only need to contain the Device Information subelement, we
don't need builder utilities.  We do need iterator utilities because we
may receive WFD IEs with more subelements.
---
This could also be placed in a header file on its own if preferred.  On
the other hand iterating over the WFD IE elements and P2P IE elements
works the same way except for the endiannes of the length field, so
those functions could be replaced with macros pointing at the P2P IE
utils (p2p_attr_iter_*) with the exception of wfd_subelem_iter_next.
---
 src/p2putil.c | 22 +++++++++++++++++
 src/p2putil.h | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 89 insertions(+)

diff --git a/src/p2putil.c b/src/p2putil.c
index 58a75a11..ef69f88d 100644
--- a/src/p2putil.c
+++ b/src/p2putil.c
@@ -58,6 +58,28 @@ bool p2p_attr_iter_next(struct p2p_attr_iter *iter)
 	return true;
 }
 
+void wfd_subelem_iter_init(struct wfd_subelem_iter *iter, const uint8_t *pdu,
+				size_t len)
+{
+	iter->pos = pdu;
+	iter->end = pdu + len;
+	iter->type = -1;
+}
+
+bool wfd_subelem_iter_next(struct wfd_subelem_iter *iter)
+{
+	if (iter->type != (enum wfd_subelem_type) -1)
+		iter->pos += 3 + iter->len;
+
+	if (iter->pos + 3 > iter->end ||
+			iter->pos + 3 + l_get_be16(iter->pos + 1) > iter->end)
+		return false;
+
+	iter->type = iter->pos[0];
+	iter->len = l_get_be16(iter->pos + 1);
+	return true;
+}
+
 enum attr_flag {
 	ATTR_FLAG_REQUIRED  = 0x1,  /* Always required */
 };
diff --git a/src/p2putil.h b/src/p2putil.h
index 09c72c74..c609ab16 100644
--- a/src/p2putil.h
+++ b/src/p2putil.h
@@ -152,6 +152,73 @@ static inline const uint8_t *p2p_attr_iter_get_data(struct p2p_attr_iter *iter)
 	return iter->pos + 3;
 }
 
+/* Wi-Fi Display Technical Specification v2.1.0 Table 27 */
+enum wfd_subelem_type {
+	WFD_SUBELEM_WFD_DEVICE_INFORMATION	= 0,
+	WFD_SUBELEM_ASSOCIATED_BSSID		= 1,
+	WFD_SUBELEM_COUPLED_SINK_INFORMATION	= 6,
+	WFD_SUBELEM_EXTENDED_CAPABILITY		= 7,
+	WFD_SUBELEM_LOCAL_IP_ADDRESS		= 8,
+	WFD_SUBELEM_SESION_INFORMATION		= 9,
+	WFD_SUBELEM_ALTERNATIVE_MAC_ADDRESS	= 10,
+	WFD_SUBELEM_R2_DEVICE_INFORMATION	= 11,
+};
+
+enum wfd_dev_info_bits {
+	WFD_DEV_INFO_DEVICE_TYPE		= 0x0003,
+	WFD_DEV_INFO_COUPLED_SINK_AT_SOURCE_OK	= 0x0004,
+	WFD_DEV_INFO_COUPLED_SINK_AT_SINK_OK	= 0x0008,
+	WFD_DEV_INFO_SESSION_AVAILABILITY	= 0x0030,
+	WFD_DEV_INFO_SERVICE_DISCOVERY_SUPPORT	= 0x0040,
+	WFD_DEV_INFO_PREFER_TDLS_CONNECTIVITY	= 0x0080,
+	WFD_DEV_INFO_CONTENT_PROTECTION_SUPPORT	= 0x0100,
+	WFD_DEV_INFO_8021AS_TIME_SYNC_SUPPORT	= 0x0200,
+	WFD_DEV_INFO_NO_AUDIO_AT_PRIMARY_SINK	= 0x0400,
+	WFD_DEV_INFO_AUDIO_ONLY_AT_SOURCE	= 0x0800,
+	WFD_DEV_INFO_TDLS_PERSISTENT_GROUP	= 0x1000,
+	WFD_DEV_INFO_REINVOKE_TDLS_GROUP	= 0x2000,
+};
+
+enum wfd_dev_info_type {
+	WFD_DEV_INFO_TYPE_SOURCE		= 0x0000,
+	WFD_DEV_INFO_TYPE_PRIMARY_SINK		= 0x0001,
+	WFD_DEV_INFO_TYPE_SECONDARY_SINK	= 0x0002,
+	WFD_DEV_INFO_TYPE_DUAL_ROLE		= 0x0003,
+};
+
+enum wfd_dev_info_session_availability {
+	WFD_DEV_INFO_SESSION_NOT_AVAILABLE	= 0x0000,
+	WFD_DEV_INFO_SESSION_AVAILABLE		= 0x0010,
+};
+
+struct wfd_subelem_iter {
+	const uint8_t *pos;
+	const uint8_t *end;
+	enum wfd_subelem_type type;
+	size_t len;
+};
+
+void wfd_subelem_iter_init(struct wfd_subelem_iter *iter, const uint8_t *pdu,
+				size_t len);
+bool wfd_subelem_iter_next(struct wfd_subelem_iter *iter);
+
+static inline enum wfd_subelem_type wfd_subelem_iter_get_type(
+						struct wfd_subelem_iter *iter)
+{
+	return iter->type;
+}
+
+static inline size_t wfd_subelem_iter_get_length(struct wfd_subelem_iter *iter)
+{
+	return iter->len;
+}
+
+static inline const uint8_t *wfd_subelem_iter_get_data(
+						struct wfd_subelem_iter *iter)
+{
+	return iter->pos + 3;
+}
+
 struct p2p_capability_attr {
 	uint8_t device_caps;
 	uint8_t group_caps;
-- 
2.20.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 7/9] ie: Add ie_tlv_extract_wfd_payload
  2020-03-19 21:12 [PATCH 1/9] frame-xchg: Add facility to keep retransmitting after ACK Andrew Zaborowski
                   ` (4 preceding siblings ...)
  2020-03-19 21:12 ` [PATCH 6/9] p2putil: Add WFD IE parsing utilities Andrew Zaborowski
@ 2020-03-19 21:12 ` Andrew Zaborowski
  2020-03-19 21:12 ` [PATCH 8/9] monitor: Print WFD IE contents Andrew Zaborowski
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 13+ messages in thread
From: Andrew Zaborowski @ 2020-03-19 21:12 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 1788 bytes --]

---
 src/ie.c | 17 +++++++++++++++++
 src/ie.h |  3 +++
 2 files changed, 20 insertions(+)

diff --git a/src/ie.c b/src/ie.c
index f120c89e..8d212ea0 100644
--- a/src/ie.c
+++ b/src/ie.c
@@ -200,6 +200,23 @@ void *ie_tlv_extract_p2p_payload(const unsigned char *ies, size_t len,
 					ies, len, true, out_len);
 }
 
+/*
+ * Wi-Fi Display Technical Specification v2.1.0, Section 5.1.1:
+ * "More than one WFD IE may be included in a single frame.  If multiple WFD
+ * IEs are present, the complete WFD subelement data consists of the
+ * concatenation of the WFD subelement fields of the WFD IEs.  The WFD
+ * subelements field of each WFD IE may be any length up to the maximum
+ * (251 octets).  The order of the concatenated WFD subelement data shall be
+ * preserved in the ordering of the WFD IEs in the frame.  All of the WFD IEs
+ * shall fit within a single frame and shall be adjacent in the frame."
+ */
+void *ie_tlv_extract_wfd_payload(const unsigned char *ies, size_t len,
+							ssize_t *out_len)
+{
+	return ie_tlv_vendor_ie_concat(wifi_alliance_oui, 0x0a,
+					ies, len, true, out_len);
+}
+
 /*
  * Encapsulate & Fragment data into Vendor IE with a given OUI + type
  *
diff --git a/src/ie.h b/src/ie.h
index 12a664b5..47dc9eff 100644
--- a/src/ie.h
+++ b/src/ie.h
@@ -431,6 +431,9 @@ void *ie_tlv_extract_p2p_payload(const uint8_t *ies, size_t len,
 void *ie_tlv_encapsulate_p2p_payload(const uint8_t *data, size_t len,
 							size_t *out_len);
 
+void *ie_tlv_extract_wfd_payload(const unsigned char *ies, size_t len,
+							ssize_t *out_len);
+
 bool ie_tlv_builder_init(struct ie_tlv_builder *builder, unsigned char *buf,
 				size_t len);
 bool ie_tlv_builder_set_length(struct ie_tlv_builder *builder,
-- 
2.20.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 8/9] monitor: Print WFD IE contents
  2020-03-19 21:12 [PATCH 1/9] frame-xchg: Add facility to keep retransmitting after ACK Andrew Zaborowski
                   ` (5 preceding siblings ...)
  2020-03-19 21:12 ` [PATCH 7/9] ie: Add ie_tlv_extract_wfd_payload Andrew Zaborowski
@ 2020-03-19 21:12 ` Andrew Zaborowski
  2020-03-20 15:33   ` Denis Kenzior
  2020-03-19 21:12 ` [PATCH 9/9] eap-tls: Print a hint about IWD_TLS_DEBUG on TLS errors Andrew Zaborowski
  2020-03-20 15:15 ` [PATCH 1/9] frame-xchg: Add facility to keep retransmitting after ACK Denis Kenzior
  8 siblings, 1 reply; 13+ messages in thread
From: Andrew Zaborowski @ 2020-03-19 21:12 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 10909 bytes --]

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..91a223d6 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[4] = {
+		[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",
+	};
+#pragma GCC diagnostic ignored "-Woverride-init"
+	static const char *session_avail[4] = {
+		[0 ... 3] = "Reserved",
+		[WFD_DEV_INFO_SESSION_NOT_AVAILABLE >> 4] =
+			"Not available for WFD Session",
+		[WFD_DEV_INFO_SESSION_AVAILABLE >> 4] =
+			"Available for WFD Session",
+	};
+
+	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

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 9/9] eap-tls: Print a hint about IWD_TLS_DEBUG on TLS errors
  2020-03-19 21:12 [PATCH 1/9] frame-xchg: Add facility to keep retransmitting after ACK Andrew Zaborowski
                   ` (6 preceding siblings ...)
  2020-03-19 21:12 ` [PATCH 8/9] monitor: Print WFD IE contents Andrew Zaborowski
@ 2020-03-19 21:12 ` Andrew Zaborowski
  2020-03-20 15:15 ` [PATCH 1/9] frame-xchg: Add facility to keep retransmitting after ACK Denis Kenzior
  8 siblings, 0 replies; 13+ messages in thread
From: Andrew Zaborowski @ 2020-03-19 21:12 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 1382 bytes --]

---
 src/eap-tls-common.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/src/eap-tls-common.c b/src/eap-tls-common.c
index a6125969..28febaf0 100644
--- a/src/eap-tls-common.c
+++ b/src/eap-tls-common.c
@@ -255,6 +255,13 @@ static void eap_tls_tunnel_ready(const char *peer_identity, void *user_data)
 		l_tls_close(eap_tls->tunnel);
 }
 
+static void eap_tls_debug_hint(void)
+{
+	if (!getenv("IWD_TLS_DEBUG"))
+		l_debug("set the IWD_TLS_DEBUG environment variable to see "
+			"more information");
+}
+
 static void eap_tls_tunnel_disconnected(enum l_tls_alert_desc reason,
 						bool remote, void *user_data)
 {
@@ -592,6 +599,7 @@ static bool eap_tls_tunnel_init(struct eap_state *eap)
 
 			l_error("%s: Failed to set auth data.",
 					eap_get_method_name(eap));
+			eap_tls_debug_hint();
 			return false;
 		}
 
@@ -606,6 +614,7 @@ static bool eap_tls_tunnel_init(struct eap_state *eap)
 			eap_tls->ca_cert = NULL;
 			l_error("%s: Error settings CA certificates.",
 					eap_get_method_name(eap));
+			eap_tls_debug_hint();
 			return false;
 		}
 
@@ -618,6 +627,7 @@ static bool eap_tls_tunnel_init(struct eap_state *eap)
 	if (!l_tls_start(eap_tls->tunnel)) {
 		l_error("%s: Failed to start the TLS client",
 						eap_get_method_name(eap));
+		eap_tls_debug_hint();
 		return false;
 	}
 
-- 
2.20.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH 1/9] frame-xchg: Add facility to keep retransmitting after ACK
  2020-03-19 21:12 [PATCH 1/9] frame-xchg: Add facility to keep retransmitting after ACK Andrew Zaborowski
                   ` (7 preceding siblings ...)
  2020-03-19 21:12 ` [PATCH 9/9] eap-tls: Print a hint about IWD_TLS_DEBUG on TLS errors Andrew Zaborowski
@ 2020-03-20 15:15 ` Denis Kenzior
  8 siblings, 0 replies; 13+ messages in thread
From: Denis Kenzior @ 2020-03-20 15:15 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 2079 bytes --]

Hi Andrew,

On 3/19/20 4:12 PM, Andrew Zaborowski wrote:
> 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(-)

<snip>

> @@ -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,

I fixed up this >80 char line...

> +						fx->early_frame.body_len,
> +						fx->early_frame.rssi, fx))
> +			return;
> +
> +		frame_xchg_listen_end_cb(NULL, fx);
>   		return;
>   	}


and applied.  Thanks.

Regards,
-Denis

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 2/9] frame-xchg: Add frame_xchg_start
  2020-03-19 21:12 ` [PATCH 2/9] frame-xchg: Add frame_xchg_start Andrew Zaborowski
@ 2020-03-20 15:24   ` Denis Kenzior
  0 siblings, 0 replies; 13+ messages in thread
From: Denis Kenzior @ 2020-03-20 15:24 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 241 bytes --]

Hi Andrew,

On 3/19/20 4:12 PM, Andrew Zaborowski wrote:
> ---
>   src/frame-xchg.c | 13 +++++++++++++
>   src/frame-xchg.h |  4 ++++
>   2 files changed, 17 insertions(+)
> 

Patches 2-7 and 9 applied, thanks.

Regards,
-Denis

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 8/9] monitor: Print WFD IE contents
  2020-03-19 21:12 ` [PATCH 8/9] monitor: Print WFD IE contents Andrew Zaborowski
@ 2020-03-20 15:33   ` Denis Kenzior
  2020-03-20 15:54     ` Andrew Zaborowski
  0 siblings, 1 reply; 13+ messages in thread
From: Denis Kenzior @ 2020-03-20 15:33 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 2006 bytes --]

Hi Andrew,

On 3/19/20 4:12 PM, Andrew Zaborowski wrote:
> 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..91a223d6 100644
> --- a/monitor/nlmon.c
> +++ b/monitor/nlmon.c

<snip>

> @@ -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

Don't know if this is intended, but you no longer 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[4] = {
> +		[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",
> +	};
> +#pragma GCC diagnostic ignored "-Woverride-init"

Don't you want to #pragma push and pop instead of disabling this for the 
entire file?

What is this trying to fix anyway?

> +	static const char *session_avail[4] = {
> +		[0 ... 3] = "Reserved",

Perhaps not trying to initialize the entire array to "Reserved" first

> +		[WFD_DEV_INFO_SESSION_NOT_AVAILABLE >> 4] =
> +			"Not available for WFD Session",
> +		[WFD_DEV_INFO_SESSION_AVAILABLE >> 4] =
> +			"Available for WFD Session",

And resetting it later  would help?

> +	};
> +

Regards,
-Denis

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 8/9] monitor: Print WFD IE contents
  2020-03-20 15:33   ` Denis Kenzior
@ 2020-03-20 15:54     ` Andrew Zaborowski
  0 siblings, 0 replies; 13+ messages in thread
From: Andrew Zaborowski @ 2020-03-20 15:54 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 2113 bytes --]

Hi Denis,

On Fri, 20 Mar 2020 at 16:33, Denis Kenzior <denkenz@gmail.com> wrote:
> On 3/19/20 4:12 PM, Andrew Zaborowski wrote:
> > @@ -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
>
> Don't know if this is intended, but you no longer undef CHECK_CAPS_BIT ...

Right, I thought it now seems useful across a bigger part of the file
and a name conflict is unlikely...

>
> >
> >   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[4] = {
> > +             [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",
> > +     };
> > +#pragma GCC diagnostic ignored "-Woverride-init"
>
> Don't you want to #pragma push and pop instead of disabling this for the
> entire file?
>
> What is this trying to fix anyway?
>
> > +     static const char *session_avail[4] = {
> > +             [0 ... 3] = "Reserved",
>
> Perhaps not trying to initialize the entire array to "Reserved" first
>
> > +             [WFD_DEV_INFO_SESSION_NOT_AVAILABLE >> 4] =
> > +                     "Not available for WFD Session",
> > +             [WFD_DEV_INFO_SESSION_AVAILABLE >> 4] =
> > +                     "Available for WFD Session",
>
> And resetting it later  would help?

I can do that instead and give up trying to use the
WFD_DEV_INFO_SESSION_.* constants, I'll send a new patch.

Best regards

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2020-03-20 15:54 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-03-19 21:12 [PATCH 1/9] frame-xchg: Add facility to keep retransmitting after ACK Andrew Zaborowski
2020-03-19 21:12 ` [PATCH 2/9] frame-xchg: Add frame_xchg_start Andrew Zaborowski
2020-03-20 15:24   ` Denis Kenzior
2020-03-19 21:12 ` [PATCH 3/9] wscutil: Implement wsc_build_probe_response Andrew Zaborowski
2020-03-19 21:12 ` [PATCH 4/9] wsc: Don't start connections until Cancel finishes Andrew Zaborowski
2020-03-19 21:12 ` [PATCH 5/9] tools: Add utility to tx Probe Requests Andrew Zaborowski
2020-03-19 21:12 ` [PATCH 6/9] p2putil: Add WFD IE parsing utilities Andrew Zaborowski
2020-03-19 21:12 ` [PATCH 7/9] ie: Add ie_tlv_extract_wfd_payload Andrew Zaborowski
2020-03-19 21:12 ` [PATCH 8/9] monitor: Print WFD IE contents Andrew Zaborowski
2020-03-20 15:33   ` Denis Kenzior
2020-03-20 15:54     ` Andrew Zaborowski
2020-03-19 21:12 ` [PATCH 9/9] eap-tls: Print a hint about IWD_TLS_DEBUG on TLS errors Andrew Zaborowski
2020-03-20 15:15 ` [PATCH 1/9] frame-xchg: Add facility to keep retransmitting after ACK Denis Kenzior

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.