* wmediumd: further updates
@ 2020-06-25 13:08 Johannes Berg
2020-06-25 13:08 ` [PATCH 1/9] wmediumd: add -lstdc++ for SANITIZE=1 Johannes Berg
` (9 more replies)
0 siblings, 10 replies; 13+ messages in thread
From: Johannes Berg @ 2020-06-25 13:08 UTC (permalink / raw)
To: me; +Cc: linux-wireless
Hi,
I've been working on this some more, so I have a few fixes and
updates. Notably, perhaps, the ability to write a pcapng file.
johannes
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 1/9] wmediumd: add -lstdc++ for SANITIZE=1
2020-06-25 13:08 wmediumd: further updates Johannes Berg
@ 2020-06-25 13:08 ` Johannes Berg
2020-06-25 13:08 ` [PATCH 2/9] wmediumd: properly wait for control socket ACK Johannes Berg
` (8 subsequent siblings)
9 siblings, 0 replies; 13+ messages in thread
From: Johannes Berg @ 2020-06-25 13:08 UTC (permalink / raw)
To: me; +Cc: linux-wireless, Johannes Berg
From: Johannes Berg <johannes.berg@intel.com>
It appears that in some scenarios this is necessary to get
the right version of the library, otherwise some runtime
linking can fail. Add -lstdc++ as required by -lasan.
---
wmediumd/Makefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/wmediumd/Makefile b/wmediumd/Makefile
index f75c4e8b4e3e..fa94eb01fbc2 100644
--- a/wmediumd/Makefile
+++ b/wmediumd/Makefile
@@ -56,7 +56,7 @@ OBJECTS += lib/uds.o lib/vhost.o lib/wallclock.o
ifeq ($(SANITIZE),1)
CFLAGS += -fsanitize=undefined,address
# apparently these have to come first for some reason
-override LDFLAGS := -lasan -lubsan $(LDFLAGS)
+override LDFLAGS := -lasan -lubsan -lstdc++ $(LDFLAGS)
endif
all: wmediumd
--
2.26.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 2/9] wmediumd: properly wait for control socket ACK
2020-06-25 13:08 wmediumd: further updates Johannes Berg
2020-06-25 13:08 ` [PATCH 1/9] wmediumd: add -lstdc++ for SANITIZE=1 Johannes Berg
@ 2020-06-25 13:08 ` Johannes Berg
2020-06-25 13:08 ` [PATCH 3/9] wmediumd: sync with external scheduler on API socket Johannes Berg
` (7 subsequent siblings)
9 siblings, 0 replies; 13+ messages in thread
From: Johannes Berg @ 2020-06-25 13:08 UTC (permalink / raw)
To: me; +Cc: linux-wireless, Johannes Berg
From: Johannes Berg <johannes.berg@intel.com>
When the control socket is used in conjunction with a time
controller, then it may happen that we have
wmediumd app time controller
------ message ------>
(wait for ack)
----- request runtime --->
<-------------- update scheduler ----------------
(wait for ack)
and deadlock here, because the update scheduler message
isn't processed by wmediumd.
Fix this by properly deferring to the mainloop when waiting
for an ACK message on the control socket.
---
wmediumd/wmediumd.c | 23 +++++++++++++++++++++--
wmediumd/wmediumd.h | 1 +
2 files changed, 22 insertions(+), 2 deletions(-)
diff --git a/wmediumd/wmediumd.c b/wmediumd/wmediumd.c
index d756dc4be5b9..8a9d97b6a427 100644
--- a/wmediumd/wmediumd.c
+++ b/wmediumd/wmediumd.c
@@ -26,6 +26,7 @@
#include <netlink/genl/genl.h>
#include <netlink/genl/ctrl.h>
#include <netlink/genl/family.h>
+#include <assert.h>
#include <stdint.h>
#include <getopt.h>
#include <signal.h>
@@ -264,6 +265,15 @@ static struct station *get_station_by_used_addr(struct wmediumd *ctx, u8 *addr)
return NULL;
}
+static void wmediumd_wait_for_client_ack(struct wmediumd *ctx,
+ struct client *client)
+{
+ client->wait_for_ack = true;
+
+ while (client->wait_for_ack)
+ usfstl_loop_wait_and_handle();
+}
+
static void queue_frame(struct wmediumd *ctx, struct station *station,
struct frame *frame)
{
@@ -430,8 +440,7 @@ static void wmediumd_send_to_client(struct wmediumd *ctx,
hdr.data_len = len;
write(client->loop.fd, &hdr, sizeof(hdr));
write(client->loop.fd, (void *)nlmsg_hdr(msg), len);
- /* read the ACK back */
- read(client->loop.fd, &hdr, sizeof(hdr));
+ wmediumd_wait_for_client_ack(ctx, client);
break;
}
}
@@ -871,6 +880,14 @@ static void wmediumd_api_handler(struct usfstl_loop_entry *entry)
if (len != hdr.data_len)
goto disconnect;
+ if (client->wait_for_ack) {
+ assert(hdr.type == WMEDIUMD_MSG_ACK);
+ assert(hdr.data_len == 0);
+ client->wait_for_ack = false;
+ /* don't send a response to a response, of course */
+ return;
+ }
+
switch (hdr.type) {
case WMEDIUMD_MSG_REGISTER:
if (!list_empty(&client->list)) {
@@ -900,6 +917,8 @@ static void wmediumd_api_handler(struct usfstl_loop_entry *entry)
nlmsg_free(nlmsg);
break;
+ case WMEDIUMD_MSG_ACK:
+ abort();
default:
response = WMEDIUMD_MSG_INVALID;
break;
diff --git a/wmediumd/wmediumd.h b/wmediumd/wmediumd.h
index e201788b9b52..fb7b47a43574 100644
--- a/wmediumd/wmediumd.h
+++ b/wmediumd/wmediumd.h
@@ -183,6 +183,7 @@ struct client {
/* for API socket */
struct usfstl_loop_entry loop;
+ bool wait_for_ack;
};
struct wmediumd {
--
2.26.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 3/9] wmediumd: sync with external scheduler on API socket
2020-06-25 13:08 wmediumd: further updates Johannes Berg
2020-06-25 13:08 ` [PATCH 1/9] wmediumd: add -lstdc++ for SANITIZE=1 Johannes Berg
2020-06-25 13:08 ` [PATCH 2/9] wmediumd: properly wait for control socket ACK Johannes Berg
@ 2020-06-25 13:08 ` Johannes Berg
2020-06-25 13:08 ` [PATCH 4/9] wmediumd: init time controller connection later Johannes Berg
` (6 subsequent siblings)
9 siblings, 0 replies; 13+ messages in thread
From: Johannes Berg @ 2020-06-25 13:08 UTC (permalink / raw)
To: me; +Cc: linux-wireless, Johannes Berg
From: Johannes Berg <johannes.berg@intel.com>
If there's a non-control message on the API socket, sync time
from the external scheduler to update the internal time and
handle updates correctly.
Also synchronize time to the external scheduler when we send
anything to the API socket, in case we were free-running for
a while.
---
wmediumd/wmediumd.c | 9 +++++++++
wmediumd/wmediumd.h | 2 ++
2 files changed, 11 insertions(+)
diff --git a/wmediumd/wmediumd.c b/wmediumd/wmediumd.c
index 8a9d97b6a427..0f45c75be9c9 100644
--- a/wmediumd/wmediumd.c
+++ b/wmediumd/wmediumd.c
@@ -508,6 +508,8 @@ static void send_tx_info_frame_nl(struct wmediumd *ctx, struct frame *frame)
goto out;
}
+ if (ctx->ctrl)
+ usfstl_sched_ctrl_sync_to(ctx->ctrl);
wmediumd_send_to_client(ctx, frame->src, msg);
out:
@@ -549,6 +551,9 @@ static void send_cloned_frame_msg(struct wmediumd *ctx, struct station *dst,
w_logf(ctx, LOG_DEBUG, "cloned msg dest " MAC_FMT " (radio: " MAC_FMT ") len %d\n",
MAC_ARGS(dst->addr), MAC_ARGS(dst->hwaddr), data_len);
+ if (ctx->ctrl)
+ usfstl_sched_ctrl_sync_to(ctx->ctrl);
+
if (dst->client) {
wmediumd_send_to_client(ctx, dst->client, msg);
} else {
@@ -904,6 +909,9 @@ static void wmediumd_api_handler(struct usfstl_loop_entry *entry)
list_del_init(&client->list);
break;
case WMEDIUMD_MSG_NETLINK:
+ if (ctx->ctrl)
+ usfstl_sched_ctrl_sync_from(ctx->ctrl);
+
if (!nlmsg_ok((const struct nlmsghdr *)data, len)) {
response = WMEDIUMD_MSG_INVALID;
break;
@@ -1180,6 +1188,7 @@ int main(int argc, char *argv[])
&scheduler);
vusrv.scheduler = &scheduler;
vusrv.ctrl = &ctrl;
+ ctx.ctrl = &ctrl;
} else {
usfstl_sched_wallclock_init(&scheduler, 1000);
}
diff --git a/wmediumd/wmediumd.h b/wmediumd/wmediumd.h
index fb7b47a43574..2360da75cdb2 100644
--- a/wmediumd/wmediumd.h
+++ b/wmediumd/wmediumd.h
@@ -192,6 +192,8 @@ struct wmediumd {
struct nl_sock *sock;
struct usfstl_loop_entry nl_loop;
+ struct usfstl_sched_ctrl *ctrl;
+
struct list_head clients;
struct client nl_client;
--
2.26.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 4/9] wmediumd: init time controller connection later
2020-06-25 13:08 wmediumd: further updates Johannes Berg
` (2 preceding siblings ...)
2020-06-25 13:08 ` [PATCH 3/9] wmediumd: sync with external scheduler on API socket Johannes Berg
@ 2020-06-25 13:08 ` Johannes Berg
2020-06-25 13:08 ` [PATCH 5/9] wmediumd: add a control message to the API socket Johannes Berg
` (5 subsequent siblings)
9 siblings, 0 replies; 13+ messages in thread
From: Johannes Berg @ 2020-06-25 13:08 UTC (permalink / raw)
To: me; +Cc: linux-wireless, Johannes Berg
From: Johannes Berg <johannes.berg@intel.com>
Some infrastructure that starts wmediumd might wait for it
to start up by checking the sockets it should offer exist,
yet have time stopped during startup for debug purposes.
Initialize the time connection later so that the startup
can happen regardless of such a scenario. Nothing can be
processed on any of the sockets until we actually get to
the mainloop anyway, so this is entirely safe.
---
wmediumd/wmediumd.c | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/wmediumd/wmediumd.c b/wmediumd/wmediumd.c
index 0f45c75be9c9..d7ffd8396d8a 100644
--- a/wmediumd/wmediumd.c
+++ b/wmediumd/wmediumd.c
@@ -1181,18 +1181,6 @@ int main(int argc, char *argv[])
usfstl_sched_add_job(&scheduler, &ctx.intf_job);
}
- if (time_socket) {
- usfstl_sched_ctrl_start(&ctrl, time_socket,
- 1000 /* nsec per usec */,
- (uint64_t)-1 /* no ID */,
- &scheduler);
- vusrv.scheduler = &scheduler;
- vusrv.ctrl = &ctrl;
- ctx.ctrl = &ctrl;
- } else {
- usfstl_sched_wallclock_init(&scheduler, 1000);
- }
-
if (vusrv.socket)
usfstl_vhost_user_server_start(&vusrv);
@@ -1213,6 +1201,18 @@ int main(int argc, char *argv[])
if (api_socket)
usfstl_uds_create(api_socket, wmediumd_api_connected, &ctx);
+ if (time_socket) {
+ usfstl_sched_ctrl_start(&ctrl, time_socket,
+ 1000 /* nsec per usec */,
+ (uint64_t)-1 /* no ID */,
+ &scheduler);
+ vusrv.scheduler = &scheduler;
+ vusrv.ctrl = &ctrl;
+ ctx.ctrl = &ctrl;
+ } else {
+ usfstl_sched_wallclock_init(&scheduler, 1000);
+ }
+
while (1) {
if (time_socket) {
usfstl_sched_next(&scheduler);
--
2.26.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 5/9] wmediumd: add a control message to the API socket
2020-06-25 13:08 wmediumd: further updates Johannes Berg
` (3 preceding siblings ...)
2020-06-25 13:08 ` [PATCH 4/9] wmediumd: init time controller connection later Johannes Berg
@ 2020-06-25 13:08 ` Johannes Berg
2020-06-25 13:08 ` [PATCH 6/9] wmediumd: fix RX message with cookie Johannes Berg
` (4 subsequent siblings)
9 siblings, 0 replies; 13+ messages in thread
From: Johannes Berg @ 2020-06-25 13:08 UTC (permalink / raw)
To: me; +Cc: linux-wireless, Johannes Berg
From: Johannes Berg <johannes.berg@intel.com>
Add a control message indicating two things:
* TX start should be notified
* all RX frames should be sent over
If all RX frames are reported, then we include the
HWSIM_ATTR_COOKIE attribute when reflecting the frame
back to the sender client, so it can identify this
(and which frame it was, if needed.)
---
wmediumd/api.h | 36 ++++++++++++++++
wmediumd/wmediumd.c | 103 ++++++++++++++++++++++++++++++++++++++------
wmediumd/wmediumd.h | 5 +++
3 files changed, 130 insertions(+), 14 deletions(-)
diff --git a/wmediumd/api.h b/wmediumd/api.h
index 6ecaa7bd94b9..24e9548defdb 100644
--- a/wmediumd/api.h
+++ b/wmediumd/api.h
@@ -5,6 +5,7 @@
*/
#ifndef _WMEDIUMD_API_H
#define _WMEDIUMD_API_H
+#include <stdint.h>
enum wmediumd_message {
/* invalid message */
@@ -26,6 +27,15 @@ enum wmediumd_message {
* netlink format, to avoid having a special format
*/
WMEDIUMD_MSG_NETLINK,
+
+ /* control message, see struct wmediumd_message_control */
+ WMEDIUMD_MSG_SET_CONTROL,
+
+ /*
+ * Indicates TX start if WMEDIUMD_RX_CTL_NOTIFY_TX_START is set,
+ * with struct wmediumd_tx_start as the payload.
+ */
+ WMEDIUMD_MSG_TX_START,
};
struct wmediumd_message_header {
@@ -38,4 +48,30 @@ struct wmediumd_message_header {
uint8_t data[];
};
+enum wmediumd_control_flags {
+ WMEDIUMD_CTL_NOTIFY_TX_START = 1 << 0,
+ WMEDIUMD_CTL_RX_ALL_FRAMES = 1 << 1,
+};
+
+struct wmediumd_message_control {
+ uint32_t flags;
+
+ /*
+ * For compatibility, wmediumd is meant to understand shorter
+ * (and ignore unknown parts of longer) control messages than
+ * what's sent to it, so always take care to have defaults as
+ * zero since that's what it assumes.
+ */
+};
+
+struct wmediumd_tx_start {
+ /*
+ * The cookie is set only when telling the sender, otherwise
+ * it's set to 0.
+ */
+ uint64_t cookie;
+ uint32_t freq;
+ uint32_t reserved[3];
+};
+
#endif /* _WMEDIUMD_API_H */
diff --git a/wmediumd/wmediumd.c b/wmediumd/wmediumd.c
index d7ffd8396d8a..aa169e1602be 100644
--- a/wmediumd/wmediumd.c
+++ b/wmediumd/wmediumd.c
@@ -274,6 +274,41 @@ static void wmediumd_wait_for_client_ack(struct wmediumd *ctx,
usfstl_loop_wait_and_handle();
}
+static void wmediumd_notify_frame_start(struct usfstl_job *job)
+{
+ struct frame *frame = container_of(job, struct frame, start_job);
+ struct wmediumd *ctx = job->data;
+ struct client *client;
+ struct {
+ struct wmediumd_message_header hdr;
+ struct wmediumd_tx_start start;
+ } __attribute__((packed)) msg = {
+ .hdr.type = WMEDIUMD_MSG_TX_START,
+ .hdr.data_len = sizeof(msg.start),
+ .start.freq = frame->freq,
+ };
+
+ if (ctx->ctrl)
+ usfstl_sched_ctrl_sync_to(ctx->ctrl);
+
+ list_for_each_entry(client, &ctx->clients, list) {
+ if (!(client->flags & WMEDIUMD_CTL_NOTIFY_TX_START))
+ continue;
+
+ if (client == frame->src)
+ msg.start.cookie = frame->cookie;
+ else
+ msg.start.cookie = 0;
+
+ /* must be API socket since flags cannot otherwise be set */
+ assert(client->type == CLIENT_API_SOCK);
+
+ write(client->loop.fd, &msg, sizeof(msg));
+
+ wmediumd_wait_for_client_ack(ctx, client);
+ }
+}
+
static void queue_frame(struct wmediumd *ctx, struct station *station,
struct frame *frame)
{
@@ -407,6 +442,15 @@ static void queue_frame(struct wmediumd *ctx, struct station *station,
frame->duration = send_time;
frame->src = station->client;
+
+ if (ctx->need_start_notify) {
+ frame->start_job.start = target - send_time;
+ frame->start_job.callback = wmediumd_notify_frame_start;
+ frame->start_job.data = ctx;
+ frame->start_job.name = "frame-start";
+ usfstl_sched_add_job(&scheduler, &frame->start_job);
+ }
+
frame->job.start = target;
frame->job.callback = wmediumd_deliver_frame;
frame->job.data = ctx;
@@ -473,6 +517,10 @@ static void wmediumd_remove_client(struct wmediumd *ctx, struct client *client)
if (!list_empty(&client->list))
list_del(&client->list);
+
+ if (client->flags & WMEDIUMD_CTL_NOTIFY_TX_START)
+ ctx->need_start_notify--;
+
free(client);
}
@@ -519,11 +567,13 @@ out:
/*
* Send a data frame to the kernel for reception at a specific radio.
*/
-static void send_cloned_frame_msg(struct wmediumd *ctx, struct station *dst,
- u8 *data, int data_len, int rate_idx,
- int signal, int freq)
+static void send_cloned_frame_msg(struct wmediumd *ctx, struct client *src,
+ struct station *dst, u8 *data, int data_len,
+ int rate_idx, int signal, int freq,
+ uint64_t cookie)
{
- struct nl_msg *msg;
+ struct client *client;
+ struct nl_msg *msg, *cmsg = NULL;
msg = nlmsg_alloc();
if (!msg) {
@@ -554,17 +604,25 @@ static void send_cloned_frame_msg(struct wmediumd *ctx, struct station *dst,
if (ctx->ctrl)
usfstl_sched_ctrl_sync_to(ctx->ctrl);
- if (dst->client) {
- wmediumd_send_to_client(ctx, dst->client, msg);
- } else {
- struct client *client;
-
- list_for_each_entry(client, &ctx->clients, list)
+ list_for_each_entry(client, &ctx->clients, list) {
+ if (client->flags & WMEDIUMD_CTL_RX_ALL_FRAMES) {
+ if (!cmsg) {
+ cmsg = nlmsg_convert(nlmsg_hdr(msg));
+ if (!cmsg)
+ continue;
+ nla_put_u64(msg, HWSIM_ATTR_COOKIE, cookie);
+ }
+ wmediumd_send_to_client(ctx, client,
+ src == client ? cmsg : msg);
+ } else if (!dst->client || dst->client == client) {
wmediumd_send_to_client(ctx, client, msg);
+ }
}
out:
nlmsg_free(msg);
+ if (cmsg)
+ nlmsg_free(cmsg);
}
static void wmediumd_deliver_frame(struct usfstl_job *job)
@@ -620,11 +678,13 @@ static void wmediumd_deliver_frame(struct usfstl_job *job)
continue;
}
- send_cloned_frame_msg(ctx, station,
+ send_cloned_frame_msg(ctx, frame->sender->client,
+ station,
frame->data,
frame->data_len,
1, signal,
- frame->freq);
+ frame->freq,
+ frame->cookie);
} else if (station_has_addr(station, dest)) {
if (set_interference_duration(ctx,
@@ -632,11 +692,13 @@ static void wmediumd_deliver_frame(struct usfstl_job *job)
frame->signal))
continue;
- send_cloned_frame_msg(ctx, station,
+ send_cloned_frame_msg(ctx, frame->sender->client,
+ station,
frame->data,
frame->data_len,
1, frame->signal,
- frame->freq);
+ frame->freq,
+ frame->cookie);
}
}
} else
@@ -865,6 +927,7 @@ static void wmediumd_api_handler(struct usfstl_loop_entry *entry)
struct wmediumd *ctx = entry->data;
struct wmediumd_message_header hdr;
enum wmediumd_message response = WMEDIUMD_MSG_ACK;
+ struct wmediumd_message_control control = {};
struct nl_msg *nlmsg;
unsigned char *data;
ssize_t len;
@@ -925,6 +988,18 @@ static void wmediumd_api_handler(struct usfstl_loop_entry *entry)
nlmsg_free(nlmsg);
break;
+ case WMEDIUMD_MSG_SET_CONTROL:
+ /* copy what we get and understand, leave the rest zeroed */
+ memcpy(&control, data,
+ min(sizeof(control), hdr.data_len));
+
+ if (client->flags & WMEDIUMD_CTL_NOTIFY_TX_START)
+ ctx->need_start_notify--;
+ if (control.flags & WMEDIUMD_CTL_NOTIFY_TX_START)
+ ctx->need_start_notify++;
+
+ client->flags = control.flags;
+ break;
case WMEDIUMD_MSG_ACK:
abort();
default:
diff --git a/wmediumd/wmediumd.h b/wmediumd/wmediumd.h
index 2360da75cdb2..6319bb70c8f6 100644
--- a/wmediumd/wmediumd.h
+++ b/wmediumd/wmediumd.h
@@ -184,6 +184,8 @@ struct client {
/* for API socket */
struct usfstl_loop_entry loop;
bool wait_for_ack;
+
+ u32 flags;
};
struct wmediumd {
@@ -223,6 +225,8 @@ struct wmediumd {
int (*get_fading_signal)(struct wmediumd *);
u8 log_lvl;
+
+ u32 need_start_notify;
};
struct hwsim_tx_rate {
@@ -233,6 +237,7 @@ struct hwsim_tx_rate {
struct frame {
struct list_head list; /* frame queue list */
struct usfstl_job job;
+ struct usfstl_job start_job;
struct client *src;
bool acked;
u64 cookie;
--
2.26.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 6/9] wmediumd: fix RX message with cookie
2020-06-25 13:08 wmediumd: further updates Johannes Berg
` (4 preceding siblings ...)
2020-06-25 13:08 ` [PATCH 5/9] wmediumd: add a control message to the API socket Johannes Berg
@ 2020-06-25 13:08 ` Johannes Berg
2020-06-25 13:08 ` [PATCH 7/9] wmediumd: add the ability to write a pcapng file Johannes Berg
` (3 subsequent siblings)
9 siblings, 0 replies; 13+ messages in thread
From: Johannes Berg @ 2020-06-25 13:08 UTC (permalink / raw)
To: me; +Cc: linux-wireless, Johannes Berg
From: Johannes Berg <johannes.berg@intel.com>
The cookie message needs to be built properly, fix the code to
do this, otherwise a client with WMEDIUMD_CTL_RX_ALL_FRAMES
doesn't know its own messages. The code was just completely
broken in all kinds of ways.
---
wmediumd/wmediumd.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/wmediumd/wmediumd.c b/wmediumd/wmediumd.c
index aa169e1602be..afc4f16d9ae9 100644
--- a/wmediumd/wmediumd.c
+++ b/wmediumd/wmediumd.c
@@ -606,11 +606,12 @@ static void send_cloned_frame_msg(struct wmediumd *ctx, struct client *src,
list_for_each_entry(client, &ctx->clients, list) {
if (client->flags & WMEDIUMD_CTL_RX_ALL_FRAMES) {
- if (!cmsg) {
- cmsg = nlmsg_convert(nlmsg_hdr(msg));
- if (!cmsg)
- continue;
- nla_put_u64(msg, HWSIM_ATTR_COOKIE, cookie);
+ if (src == client && !cmsg) {
+ struct nlmsghdr *nlh = nlmsg_hdr(msg);
+
+ cmsg = nlmsg_inherit(nlh);
+ nlmsg_append(cmsg, nlmsg_data(nlh), nlmsg_datalen(nlh), 0);
+ assert(nla_put_u64(cmsg, HWSIM_ATTR_COOKIE, cookie) == 0);
}
wmediumd_send_to_client(ctx, client,
src == client ? cmsg : msg);
--
2.26.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 7/9] wmediumd: add the ability to write a pcapng file
2020-06-25 13:08 wmediumd: further updates Johannes Berg
` (5 preceding siblings ...)
2020-06-25 13:08 ` [PATCH 6/9] wmediumd: fix RX message with cookie Johannes Berg
@ 2020-06-25 13:08 ` Johannes Berg
2020-06-26 3:10 ` Bob Copeland
2020-06-25 13:08 ` [PATCH 8/9] wmediumd: lib: minor code cleanups Johannes Berg
` (2 subsequent siblings)
9 siblings, 1 reply; 13+ messages in thread
From: Johannes Berg @ 2020-06-25 13:08 UTC (permalink / raw)
To: me; +Cc: linux-wireless, Johannes Berg
From: Johannes Berg <johannes.berg@intel.com>
Add the ability to write a pcapng file containing all the data.
The radiotap header is currently very minimal with only the
frequency and the signal strength.
---
wmediumd/wmediumd.c | 119 +++++++++++++++++++++++++++++++++++++++++++-
wmediumd/wmediumd.h | 2 +
2 files changed, 120 insertions(+), 1 deletion(-)
diff --git a/wmediumd/wmediumd.c b/wmediumd/wmediumd.c
index afc4f16d9ae9..5304931fbf74 100644
--- a/wmediumd/wmediumd.c
+++ b/wmediumd/wmediumd.c
@@ -36,6 +36,7 @@
#include <limits.h>
#include <unistd.h>
#include <stdarg.h>
+#include <endian.h>
#include <usfstl/loop.h>
#include <usfstl/sched.h>
#include <usfstl/schedctrl.h>
@@ -309,6 +310,48 @@ static void wmediumd_notify_frame_start(struct usfstl_job *job)
}
}
+static void log2pcap(struct wmediumd *ctx, struct frame *frame, uint64_t ts)
+{
+ struct {
+ uint8_t it_version;
+ uint8_t it_pad;
+ uint16_t it_len;
+ uint32_t it_present;
+ struct {
+ uint16_t freq, flags;
+ } channel;
+ uint8_t signal;
+ } __attribute__((packed)) radiotap_hdr = {
+ .it_len = htole16(sizeof(radiotap_hdr)),
+ .it_present = htole32(1 << 3 /* channel */ |
+ 1 << 5 /* signal dBm */),
+ .channel.freq = htole16(frame->freq),
+ .signal = frame->signal,
+ };
+ struct {
+ uint32_t type, blocklen, ifidx, ts_hi, ts_lo, caplen, pktlen;
+ } __attribute__((packed)) blockhdr = {
+ .type = 6,
+ .ts_hi = ts / (1ULL << 32),
+ .ts_lo = ts,
+ .caplen = frame->data_len + sizeof(radiotap_hdr),
+ .pktlen = frame->data_len + sizeof(radiotap_hdr),
+ };
+ static const uint8_t pad[3];
+ uint32_t sz, align;
+
+ sz = blockhdr.caplen + sizeof(blockhdr) + sizeof(uint32_t);
+ blockhdr.blocklen = (sz + 3) & ~3;
+ align = blockhdr.blocklen - sz;
+
+ fwrite(&blockhdr, sizeof(blockhdr), 1, ctx->pcap_file);
+ fwrite(&radiotap_hdr, sizeof(radiotap_hdr), 1, ctx->pcap_file);
+ fwrite(frame->data, frame->data_len, 1, ctx->pcap_file);
+ fwrite(pad, align, 1, ctx->pcap_file);
+ fwrite(&blockhdr.blocklen, sizeof(blockhdr.blocklen), 1, ctx->pcap_file);
+ fflush(ctx->pcap_file);
+}
+
static void queue_frame(struct wmediumd *ctx, struct station *station,
struct frame *frame)
{
@@ -438,6 +481,29 @@ static void queue_frame(struct wmediumd *ctx, struct station *station,
}
}
+ if (ctx->pcap_file) {
+ log2pcap(ctx, frame, target);
+
+ if (is_acked && !noack) {
+ struct {
+ struct frame frame;
+ uint16_t fc;
+ uint16_t dur;
+ uint8_t ra[6];
+ } __attribute__((packed, aligned(8))) ack = {
+ .fc = htole16(0xd4),
+ .dur = htole16(ack_time_usec),
+ };
+
+ memcpy(&ack.frame, frame, sizeof(ack.frame));
+ ack.frame.data_len = 10;
+ memcpy(ack.ra, frame->data + 10, 6);
+
+ log2pcap(ctx, &ack.frame,
+ target + send_time - ack_time_usec);
+ }
+ }
+
target += send_time;
frame->duration = send_time;
@@ -1141,10 +1207,58 @@ static void print_help(int exval)
printf(" -u socket expose vhost-user socket, don't use netlink\n");
printf(" -a socket expose wmediumd API socket\n");
printf(" -n force netlink use even with vhost-user\n");
+ printf(" -p FILE log packets to pcapng file FILE\n");
exit(exval);
}
+static void init_pcapng(struct wmediumd *ctx, const char *filename)
+{
+ struct {
+ uint32_t type, blocklen, byte_order;
+ uint16_t ver_maj, ver_min;
+ uint64_t seclen;
+ uint32_t blocklen2;
+ } __attribute__((packed)) blockhdr = {
+ .type = 0x0A0D0D0A,
+ .blocklen = sizeof(blockhdr),
+ .byte_order = 0x1A2B3C4D,
+ .ver_maj = 1,
+ .ver_min = 0,
+ .seclen = -1,
+ .blocklen2 = sizeof(blockhdr),
+ };
+ struct {
+ uint32_t type, blocklen;
+ uint16_t linktype, reserved;
+ uint32_t snaplen;
+ struct {
+ uint16_t code, len;
+ uint8_t val, pad[3];
+ } opt_if_tsresol;
+ struct {
+ uint16_t code, len;
+ } opt_endofopt;
+ uint32_t blocklen2;
+ } __attribute__((packed)) idb = {
+ .type = 1,
+ .blocklen = sizeof(idb),
+ .linktype = 127, // radiotap
+ .snaplen = -1,
+ .opt_if_tsresol.code = 9,
+ .opt_if_tsresol.len = 1,
+ .opt_if_tsresol.val = 6, // usec
+ .blocklen2 = sizeof(idb),
+ };
+
+ if (!filename)
+ return;
+
+ ctx->pcap_file = fopen(filename, "w+");
+ fwrite(&blockhdr, sizeof(blockhdr), 1, ctx->pcap_file);
+ fwrite(&idb, sizeof(idb), 1, ctx->pcap_file);
+}
+
int main(int argc, char *argv[])
{
int opt;
@@ -1174,7 +1288,7 @@ int main(int argc, char *argv[])
unsigned long int parse_log_lvl;
char* parse_end_token;
- while ((opt = getopt(argc, argv, "hVc:l:x:t:u:a:n")) != -1) {
+ while ((opt = getopt(argc, argv, "hVc:l:x:t:u:a:np:")) != -1) {
switch (opt) {
case 'h':
print_help(EXIT_SUCCESS);
@@ -1218,6 +1332,9 @@ int main(int argc, char *argv[])
case 'n':
force_netlink = true;
break;
+ case 'p':
+ init_pcapng(&ctx, optarg);
+ break;
case '?':
printf("wmediumd: Error - No such option: "
"`%c'\n\n", optopt);
diff --git a/wmediumd/wmediumd.h b/wmediumd/wmediumd.h
index 6319bb70c8f6..8619e28cbe9a 100644
--- a/wmediumd/wmediumd.h
+++ b/wmediumd/wmediumd.h
@@ -227,6 +227,8 @@ struct wmediumd {
u8 log_lvl;
u32 need_start_notify;
+
+ FILE *pcap_file;
};
struct hwsim_tx_rate {
--
2.26.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 8/9] wmediumd: lib: minor code cleanups
2020-06-25 13:08 wmediumd: further updates Johannes Berg
` (6 preceding siblings ...)
2020-06-25 13:08 ` [PATCH 7/9] wmediumd: add the ability to write a pcapng file Johannes Berg
@ 2020-06-25 13:08 ` Johannes Berg
2020-06-25 13:08 ` [PATCH 9/9] wmediumd: lib: wallclock: fix timerfd handling Johannes Berg
2020-06-26 3:10 ` wmediumd: further updates Bob Copeland
9 siblings, 0 replies; 13+ messages in thread
From: Johannes Berg @ 2020-06-25 13:08 UTC (permalink / raw)
To: me; +Cc: linux-wireless, Johannes Berg
From: Johannes Berg <johannes.berg@intel.com>
---
wmediumd/lib/loop.c | 1 +
wmediumd/lib/sched.c | 2 +-
wmediumd/lib/schedctrl.c | 3 ---
wmediumd/lib/vhost.c | 20 ++++++++++----------
wmediumd/lib/wallclock.c | 2 +-
5 files changed, 13 insertions(+), 15 deletions(-)
diff --git a/wmediumd/lib/loop.c b/wmediumd/lib/loop.c
index e5595a33234d..67f6876165c7 100644
--- a/wmediumd/lib/loop.c
+++ b/wmediumd/lib/loop.c
@@ -50,6 +50,7 @@ void usfstl_loop_wait_and_handle(void)
struct usfstl_loop_entry *tmp;
fd_set rd_set, exc_set;
unsigned int max = 0, num;
+
FD_ZERO(&rd_set);
FD_ZERO(&exc_set);
diff --git a/wmediumd/lib/sched.c b/wmediumd/lib/sched.c
index f23c8190fdce..2694a034d7dd 100644
--- a/wmediumd/lib/sched.c
+++ b/wmediumd/lib/sched.c
@@ -262,7 +262,7 @@ static void usfstl_sched_restore_blocked_jobs(struct usfstl_scheduler *sched)
entry) {
if (job == sched->allowed_job ||
!((1 << job->group) & sched->blocked_groups))
- usfstl_sched_restore_job(sched, job);
+ usfstl_sched_restore_job(sched, job);
}
}
diff --git a/wmediumd/lib/schedctrl.c b/wmediumd/lib/schedctrl.c
index ed5a9089124d..540826026d68 100644
--- a/wmediumd/lib/schedctrl.c
+++ b/wmediumd/lib/schedctrl.c
@@ -122,9 +122,6 @@ static void usfstl_sched_ctrl_wait(struct usfstl_scheduler *sched)
#define JOB_ASSERT_VAL(j) (j) ? (j)->name : "<NULL>"
-extern struct usfstl_sched_ctrl g_schedCtrl;
-extern struct usfstl_scheduler g_usfstl_task_scheduler;
-
void usfstl_sched_ctrl_start(struct usfstl_sched_ctrl *ctrl,
const char *socket,
uint32_t nsec_per_tick,
diff --git a/wmediumd/lib/vhost.c b/wmediumd/lib/vhost.c
index 9f116f57f04a..cc35d8cd7aa4 100644
--- a/wmediumd/lib/vhost.c
+++ b/wmediumd/lib/vhost.c
@@ -69,8 +69,8 @@ CONV(64)
static struct usfstl_vhost_user_buf *
usfstl_vhost_user_get_virtq_buf(struct usfstl_vhost_user_dev_int *dev,
- unsigned int virtq_idx,
- struct usfstl_vhost_user_buf *fixed)
+ unsigned int virtq_idx,
+ struct usfstl_vhost_user_buf *fixed)
{
struct usfstl_vhost_user_buf *buf = fixed;
struct vring *virtq = &dev->virtqs[virtq_idx].virtq;
@@ -103,8 +103,8 @@ usfstl_vhost_user_get_virtq_buf(struct usfstl_vhost_user_dev_int *dev,
} while (more);
if (n_in > fixed->n_in_sg || n_out > fixed->n_out_sg) {
- size_t sz = sizeof(*buf);
- struct iovec *vec;
+ size_t sz = sizeof(*buf);
+ struct iovec *vec;
sz += (n_in + n_out) * sizeof(*vec);
@@ -242,7 +242,7 @@ static void usfstl_vhost_user_send_virtq_buf(struct usfstl_vhost_user_dev_int *d
__sync_synchronize();
virtq->used->idx = cpu_to_virtio16(dev, widx);
-
+
if (call_fd < 0 &&
dev->ext.protocol_features &
(1ULL << VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS) &&
@@ -302,7 +302,7 @@ static void usfstl_vhost_user_send_virtq_buf(struct usfstl_vhost_user_dev_int *d
}
static void usfstl_vhost_user_handle_queue(struct usfstl_vhost_user_dev_int *dev,
- unsigned int virtq_idx)
+ unsigned int virtq_idx)
{
/* preallocate on the stack for most cases */
struct iovec in_sg[SG_STACK_PREALLOC] = { };
@@ -338,7 +338,7 @@ static void usfstl_vhost_user_job_callback(struct usfstl_job *job)
}
static void usfstl_vhost_user_virtq_kick(struct usfstl_vhost_user_dev_int *dev,
- unsigned int virtq)
+ unsigned int virtq)
{
if (!(dev->ext.server->input_queues & (1ULL << virtq)))
return;
@@ -439,7 +439,7 @@ static void usfstl_vhost_user_dev_free(struct usfstl_vhost_user_dev_int *dev)
}
static void usfstl_vhost_user_get_msg_fds(struct msghdr *msghdr,
- int *outfds, int max_fds)
+ int *outfds, int max_fds)
{
struct cmsghdr *msg;
int fds;
@@ -774,8 +774,8 @@ void *usfstl_vhost_user_to_va(struct usfstl_vhost_user_dev *extdev, uint64_t add
dev->regions[region].size)
return (uint8_t *)dev->region_vaddr[region] +
(addr -
- dev->regions[region].user_addr +
- dev->regions[region].mmap_offset);
+ dev->regions[region].user_addr +
+ dev->regions[region].mmap_offset);
}
USFSTL_ASSERT(0, "cannot translate address %"PRIx64"\n", addr);
diff --git a/wmediumd/lib/wallclock.c b/wmediumd/lib/wallclock.c
index b4750621348a..4f62a5894329 100644
--- a/wmediumd/lib/wallclock.c
+++ b/wmediumd/lib/wallclock.c
@@ -63,7 +63,7 @@ void usfstl_sched_wallclock_wait(struct usfstl_scheduler *sched)
}
void usfstl_sched_wallclock_init(struct usfstl_scheduler *sched,
- unsigned int ns_per_tick)
+ unsigned int ns_per_tick)
{
USFSTL_ASSERT(!sched->external_request && !sched->external_wait);
--
2.26.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 9/9] wmediumd: lib: wallclock: fix timerfd handling
2020-06-25 13:08 wmediumd: further updates Johannes Berg
` (7 preceding siblings ...)
2020-06-25 13:08 ` [PATCH 8/9] wmediumd: lib: minor code cleanups Johannes Berg
@ 2020-06-25 13:08 ` Johannes Berg
2020-06-26 3:10 ` wmediumd: further updates Bob Copeland
9 siblings, 0 replies; 13+ messages in thread
From: Johannes Berg @ 2020-06-25 13:08 UTC (permalink / raw)
To: me; +Cc: linux-wireless, Johannes Berg
From: Johannes Berg <johannes.berg@intel.com>
When we have a timerfd for wallclock integration, it is possible
that the following scenario happens:
* we insert an event in to the scheduler at time T
* some job handling handles the event loop and the fd
becomes readable and the read is handled
* we go back to the scheduler, now waiting for time T,
but the fd doesn't become readable because it already
had
This causes the scheduler to lose synchronization and nothing
really works - this manifested for example when having virtual
ethernet with a low latency, where the real processing time
may be more than the latency.
Fix this by keeping the loop entry only active when we need it,
so that the fd becomes readable we don't handle it until we're
in a situation where we actually want to.
---
wmediumd/lib/wallclock.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/wmediumd/lib/wallclock.c b/wmediumd/lib/wallclock.c
index 4f62a5894329..3fb09accba61 100644
--- a/wmediumd/lib/wallclock.c
+++ b/wmediumd/lib/wallclock.c
@@ -56,9 +56,13 @@ void usfstl_sched_wallclock_wait(struct usfstl_scheduler *sched)
{
sched->wallclock.timer_triggered = 0;
+ usfstl_loop_register(&sched->wallclock.entry);
+
while (!sched->wallclock.timer_triggered)
usfstl_loop_wait_and_handle();
+ usfstl_loop_unregister(&sched->wallclock.entry);
+
usfstl_sched_set_time(sched, sched->prev_external_sync);
}
@@ -76,8 +80,6 @@ void usfstl_sched_wallclock_init(struct usfstl_scheduler *sched,
sched->wallclock.entry.handler = usfstl_sched_wallclock_handle_fd;
sched->wallclock.nsec_per_tick = ns_per_tick;
-
- usfstl_loop_register(&sched->wallclock.entry);
}
void usfstl_sched_wallclock_exit(struct usfstl_scheduler *sched)
@@ -87,8 +89,6 @@ void usfstl_sched_wallclock_exit(struct usfstl_scheduler *sched)
sched->external_request = NULL;
sched->external_wait = NULL;
-
- usfstl_loop_unregister(&sched->wallclock.entry);
close(sched->wallclock.entry.fd);
}
--
2.26.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH 7/9] wmediumd: add the ability to write a pcapng file
2020-06-25 13:08 ` [PATCH 7/9] wmediumd: add the ability to write a pcapng file Johannes Berg
@ 2020-06-26 3:10 ` Bob Copeland
2020-06-26 8:10 ` Johannes Berg
0 siblings, 1 reply; 13+ messages in thread
From: Bob Copeland @ 2020-06-26 3:10 UTC (permalink / raw)
To: Johannes Berg; +Cc: me, linux-wireless, Johannes Berg
On Thu, Jun 25, 2020 at 03:08:42PM +0200, Johannes Berg wrote:
> From: Johannes Berg <johannes.berg@intel.com>
>
> Add the ability to write a pcapng file containing all the data.
> The radiotap header is currently very minimal with only the
> frequency and the signal strength.
> + if (!filename)
> + return;
> +
> + ctx->pcap_file = fopen(filename, "w+");
I know it doesn't actually matter, but would be nice to close this
somewhere.
--
Bob Copeland %% https://bobcopeland.com/
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: wmediumd: further updates
2020-06-25 13:08 wmediumd: further updates Johannes Berg
` (8 preceding siblings ...)
2020-06-25 13:08 ` [PATCH 9/9] wmediumd: lib: wallclock: fix timerfd handling Johannes Berg
@ 2020-06-26 3:10 ` Bob Copeland
9 siblings, 0 replies; 13+ messages in thread
From: Bob Copeland @ 2020-06-26 3:10 UTC (permalink / raw)
To: Johannes Berg; +Cc: me, linux-wireless
On Thu, Jun 25, 2020 at 03:08:35PM +0200, Johannes Berg wrote:
> Hi,
>
> I've been working on this some more, so I have a few fixes and
> updates. Notably, perhaps, the ability to write a pcapng file.
Thanks, applied all.
--
Bob Copeland %% https://bobcopeland.com/
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 7/9] wmediumd: add the ability to write a pcapng file
2020-06-26 3:10 ` Bob Copeland
@ 2020-06-26 8:10 ` Johannes Berg
0 siblings, 0 replies; 13+ messages in thread
From: Johannes Berg @ 2020-06-26 8:10 UTC (permalink / raw)
To: Bob Copeland; +Cc: me, linux-wireless
On Thu, 2020-06-25 at 23:10 -0400, Bob Copeland wrote:
> On Thu, Jun 25, 2020 at 03:08:42PM +0200, Johannes Berg wrote:
> > From: Johannes Berg <johannes.berg@intel.com>
> >
> > Add the ability to write a pcapng file containing all the data.
> > The radiotap header is currently very minimal with only the
> > frequency and the signal strength.
> > + if (!filename)
> > + return;
> > +
> > + ctx->pcap_file = fopen(filename, "w+");
>
> I know it doesn't actually matter, but would be nice to close this
> somewhere.
Hah, true.
I guess we could now add to the control socket a way to quit wediumd
that doesn't involve killing it, and then that starts being a bit more
relevant :)
johannes
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2020-06-26 8:10 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-06-25 13:08 wmediumd: further updates Johannes Berg
2020-06-25 13:08 ` [PATCH 1/9] wmediumd: add -lstdc++ for SANITIZE=1 Johannes Berg
2020-06-25 13:08 ` [PATCH 2/9] wmediumd: properly wait for control socket ACK Johannes Berg
2020-06-25 13:08 ` [PATCH 3/9] wmediumd: sync with external scheduler on API socket Johannes Berg
2020-06-25 13:08 ` [PATCH 4/9] wmediumd: init time controller connection later Johannes Berg
2020-06-25 13:08 ` [PATCH 5/9] wmediumd: add a control message to the API socket Johannes Berg
2020-06-25 13:08 ` [PATCH 6/9] wmediumd: fix RX message with cookie Johannes Berg
2020-06-25 13:08 ` [PATCH 7/9] wmediumd: add the ability to write a pcapng file Johannes Berg
2020-06-26 3:10 ` Bob Copeland
2020-06-26 8:10 ` Johannes Berg
2020-06-25 13:08 ` [PATCH 8/9] wmediumd: lib: minor code cleanups Johannes Berg
2020-06-25 13:08 ` [PATCH 9/9] wmediumd: lib: wallclock: fix timerfd handling Johannes Berg
2020-06-26 3:10 ` wmediumd: further updates Bob Copeland
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).