Search Linux Wireless

[PATCH 2/9] wmediumd: properly wait for control socket ACK

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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




[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Wireless Personal Area Network]     [Linux Bluetooth]     [Wireless Regulations]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite Hiking]     [MIPS Linux]     [ARM Linux]     [Linux RAID]

  Powered by Linux