Add API for listing stations at wmediumd am: ab76216841 am: 0c959925e1 am: 5ddafbfabc

Original change: https://android-review.googlesource.com/c/platform/external/wmediumd/+/1990341

Change-Id: I754dacb6a1e3fd5a6da4cbf24687835e520ff0da
diff --git a/Android.bp b/Android.bp
index e165e93..97dbe73 100644
--- a/Android.bp
+++ b/Android.bp
@@ -73,3 +73,17 @@
     stl: "none",
     static_executable: true,
 }
+
+cc_library_headers {
+    name: "wmediumd_headers",
+    export_include_dirs: [
+        ".",
+    ],
+    visibility: [
+        "//device/google/cuttlefish/host/libs/wmediumd_controller",
+        "//device/google/cuttlefish/host/commands/wmediumd_control",
+    ],
+    stl: "none",
+    host_supported: true,
+    vendor_available: true,
+}
diff --git a/wmediumd/api.h b/wmediumd/api.h
index d157e5c..ba507e4 100644
--- a/wmediumd/api.h
+++ b/wmediumd/api.h
@@ -7,6 +7,8 @@
 #define _WMEDIUMD_API_H
 #include <stdint.h>
 
+#include "ieee80211.h"
+
 enum wmediumd_message {
 	/* invalid message */
 	WMEDIUMD_MSG_INVALID,
@@ -37,10 +39,7 @@
 	 */
 	WMEDIUMD_MSG_TX_START,
 
-	/*
-	 * TODO(@jaeman) Get list of currnet nodes.
-	 */
-	WMEDIUMD_MSG_GET_NODES,
+	WMEDIUMD_MSG_GET_STATIONS,
 
 	/*
 	 * Set SNR between two nodes.
@@ -69,6 +68,8 @@
 	 * Stop packet capture
 	 */
 	WMEDIUMD_MSG_STOP_PCAP,
+
+	WMEDIUMD_MSG_STATIONS_LIST,
 };
 
 struct wmediumd_message_header {
@@ -127,4 +128,21 @@
 	char pcap_path[0];
 };
 
+#pragma pack(push, 1)
+struct wmediumd_station_info {
+	char addr[ETH_ALEN];
+	char hwaddr[ETH_ALEN];
+
+	double x;
+	double y;
+
+	int tx_power;
+};
+
+struct wmediumd_station_infos {
+	uint32_t count;
+	struct wmediumd_station_info stations[0];
+};
+#pragma pack(pop)
+
 #endif /* _WMEDIUMD_API_H */
diff --git a/wmediumd/wmediumd.c b/wmediumd/wmediumd.c
index 9c1eeeb..6b3ae5d 100644
--- a/wmediumd/wmediumd.c
+++ b/wmediumd/wmediumd.c
@@ -1106,6 +1106,42 @@
 	return result;
 }
 
+static int process_get_stations_message(struct wmediumd *ctx, ssize_t *response_len, unsigned char **response_data) {
+	struct station *station;
+	int station_count = 0;
+
+	list_for_each_entry(station, &ctx->stations, list) {
+		if (station->client != NULL) {
+			++station_count;
+		}
+	}
+
+	*response_len = sizeof(uint32_t) + sizeof(struct wmediumd_station_info) * station_count;
+	struct wmediumd_station_infos *station_infos = malloc(*response_len);
+
+	station_infos->count = station_count;
+	int station_index = 0;
+
+	list_for_each_entry(station, &ctx->stations, list) {
+		if (station->client != NULL) {
+			struct wmediumd_station_info *station_info = &station_infos->stations[station_index];
+			memcpy(station_info->addr, station->addr, ETH_ALEN);
+			memcpy(station_info->hwaddr, station->hwaddr, ETH_ALEN);
+
+			station_info->x = station->x;
+			station_info->y = station->y;
+
+			station_info->tx_power = station->tx_power;
+
+			station_index++;
+		}
+	}
+
+	*response_data = (unsigned char *)station_infos;
+
+	return 0;
+}
+
 static const struct usfstl_vhost_user_ops wmediumd_vu_ops = {
 	.connected = wmediumd_vu_connected,
 	.handle = wmediumd_vu_handle,
@@ -1134,6 +1170,8 @@
 	struct wmediumd_message_control control = {};
 	struct nl_msg *nlmsg;
 	unsigned char *data;
+	ssize_t response_len = 0;
+	unsigned char *response_data = NULL;
 	ssize_t len;
 
 	len = read(entry->fd, &hdr, sizeof(hdr));
@@ -1196,7 +1234,11 @@
 
 		client->flags = control.flags;
 		break;
-	case WMEDIUMD_MSG_GET_NODES:
+	case WMEDIUMD_MSG_GET_STATIONS:
+		if (process_get_stations_message(ctx, &response_len, &response_data) < 0) {
+			response = WMEDIUMD_MSG_INVALID;
+		}
+		response = WMEDIUMD_MSG_STATIONS_LIST;
 		break;
 	case WMEDIUMD_MSG_SET_SNR:
 		if (process_set_snr_message(ctx, (struct wmediumd_set_snr *)data) < 0) {
@@ -1233,11 +1275,25 @@
 
 	/* return a response */
 	hdr.type = response;
-	hdr.data_len = 0;
+	hdr.data_len = response_len;
 	len = write(entry->fd, &hdr, sizeof(hdr));
 	if (len != sizeof(hdr))
 		goto disconnect;
 
+	if (response_data != NULL) {
+		if (response_len != 0) {
+			len = write(entry->fd, response_data, response_len);
+
+			if (len != response_len) {
+				free(response_data);
+				goto disconnect;
+			}
+		}
+
+		free(response_data);
+		response_data = NULL;
+	}
+
 	return;
 disconnect:
 	usfstl_loop_unregister(&client->loop);