From: Johannes Berg <johannes.berg@xxxxxxxxx> 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