Add set position API in wmediumd

With set position API in wmediumd, we can connect/disconnect wifi
connection with distance between stations like real world.

Type command "wmediumd_control set_position" to use it.

Bug: 230432123
Test: Creating several cuttlefish instance with "launch_cvd", and
change X/Y position of station with "wmediumd_control set_position".
Then the result could be seen with "wmediumd_control list_stations" and
the cuttlefish screen.

Change-Id: I0036878bdcd2174a050ac987b015a410ce54e6c8
diff --git a/util/wmediumd_gen_config.c b/util/wmediumd_gen_config.c
index 73c1ee5..14e568b 100644
--- a/util/wmediumd_gen_config.c
+++ b/util/wmediumd_gen_config.c
@@ -14,6 +14,8 @@
 
 #define OPENWRT_MAC_ADDR "42:00:00:00:00:00"
 
+#define TX_POWER_DEFAULT 10
+
 #define APPEND_LAST -1
 
 #define PREVENT_MULTIPLE_OPTION(var, zero_val)                             \
@@ -59,6 +61,32 @@
   return 0;
 }
 
+int add_cuttlefish_path_loss_model(config_setting_t *model, int instance_count) {
+  config_setting_t *type = config_setting_add(model, "type", CONFIG_TYPE_STRING);
+  config_setting_set_string(type, "path_loss");
+
+  config_setting_t *model_name = config_setting_add(model, "model_name", CONFIG_TYPE_STRING);
+  config_setting_set_string(model_name, "free_space");
+
+  config_setting_t *positions = config_setting_add(model, "positions", CONFIG_TYPE_LIST);
+  config_setting_t *directions = config_setting_add(model, "directions", CONFIG_TYPE_LIST);
+  config_setting_t *tx_powers = config_setting_add(model, "tx_powers", CONFIG_TYPE_ARRAY);
+
+  for (int idx = 0; idx < instance_count; ++idx) {
+    config_setting_t *position = config_setting_add(positions, NULL, CONFIG_TYPE_LIST);
+    config_setting_set_float_elem(position, APPEND_LAST, 0.0);
+    config_setting_set_float_elem(position, APPEND_LAST, 0.0);
+
+    config_setting_t *direction = config_setting_add(directions, NULL, CONFIG_TYPE_LIST);
+    config_setting_set_float_elem(direction, APPEND_LAST, 0.0);
+    config_setting_set_float_elem(direction, APPEND_LAST, 0.0);
+
+    config_setting_set_float_elem(tx_powers, APPEND_LAST, TX_POWER_DEFAULT);
+  }
+
+  return 0;
+}
+
 bool valid_mac_addr(const char *mac_addr) {
   if (strlen(mac_addr) != STR_MAC_ADDR_LEN) return false;
 
@@ -253,6 +281,9 @@
     print_help(-1);
   }
 
+  config_setting_t *model = config_setting_add(root, "model", CONFIG_TYPE_GROUP);
+  add_cuttlefish_path_loss_model(model, config_setting_length(ids));
+
   config_setting_set_int(count, config_setting_length(ids));
 
   if (out_path != NULL) {
diff --git a/wmediumd/api.h b/wmediumd/api.h
index ba507e4..8fa8fe0 100644
--- a/wmediumd/api.h
+++ b/wmediumd/api.h
@@ -70,6 +70,11 @@
 	WMEDIUMD_MSG_STOP_PCAP,
 
 	WMEDIUMD_MSG_STATIONS_LIST,
+
+	/*
+	 * Set position of station.
+	 */
+	WMEDIUMD_MSG_SET_POSITION,
 };
 
 struct wmediumd_message_header {
@@ -109,7 +114,7 @@
 };
 
 #pragma pack(push, 1)
-	struct wmediumd_set_snr {
+struct wmediumd_set_snr {
 	/* MAC address of node 1 */
 	uint8_t node1_mac[6];
 	/* MAC address of node 2 */
@@ -143,6 +148,15 @@
 	uint32_t count;
 	struct wmediumd_station_info stations[0];
 };
+
+struct wmediumd_set_position {
+	/* MAC address */
+	uint8_t mac[6];
+	/* X position of station */
+	double x;
+	/* Y position of station */
+	double y;
+};
 #pragma pack(pop)
 
 #endif /* _WMEDIUMD_API_H */
diff --git a/wmediumd/config.c b/wmediumd/config.c
index fc4986a..cdc3466 100644
--- a/wmediumd/config.c
+++ b/wmediumd/config.c
@@ -110,7 +110,7 @@
 	 * https://en.wikipedia.org/wiki/Free-space_path_loss
 	 */
 	PL = 20.0 * log10(4.0 * M_PI * d * FREQ_1CH / SPEED_LIGHT);
-	return PL;
+	return PL > 0 ? PL : 0;
 }
 /*
  * Calculate path loss based on a log distance model
@@ -146,7 +146,7 @@
 	 */
 	PL = PL0 + 10.0 * param->path_loss_exponent * log10(d) + param->Xg;
 
-	return PL;
+	return PL > 0 ? PL : 0;
 }
 /*
  * Calculate path loss based on a itu model
@@ -176,7 +176,7 @@
 	 * nFLOORS: number of floors
 	 */
 	PL = 20.0 * log10(FREQ_1CH) + N * log10(d) + param->LF * param->nFLOORS - 28;
-	return PL;
+	return PL > 0 ? PL : 0;
 }
 
 static void recalc_path_loss(struct wmediumd *ctx)
@@ -700,3 +700,7 @@
 
 	return 0;
 }
+
+void calc_path_loss(struct wmediumd *ctx) {
+	recalc_path_loss(ctx);
+}
diff --git a/wmediumd/config.h b/wmediumd/config.h
index 471ffe1..feac4c2 100644
--- a/wmediumd/config.h
+++ b/wmediumd/config.h
@@ -24,6 +24,7 @@
 #ifndef CONFIG_H_
 #define CONFIG_H_
 
+void calc_path_loss(struct wmediumd *ctx);
 int clear_config(struct wmediumd *ctx);
 int validate_config(const char* file);
 int load_config(struct wmediumd *ctx, const char *file, const char *per_file);
diff --git a/wmediumd/wmediumd.c b/wmediumd/wmediumd.c
index 860c214..31f2ce3 100644
--- a/wmediumd/wmediumd.c
+++ b/wmediumd/wmediumd.c
@@ -1148,6 +1148,21 @@
 	return 0;
 }
 
+static int process_set_position_message(struct wmediumd *ctx, struct wmediumd_set_position *set_position) {
+	struct station *node = get_station_by_addr(ctx, set_position->mac);
+
+	if (node == NULL) {
+		return -1;
+	}
+
+	node->x = set_position->x;
+	node->y = set_position->y;
+
+	calc_path_loss(ctx);
+
+	return 0;
+}
+
 static const struct usfstl_vhost_user_ops wmediumd_vu_ops = {
 	.connected = wmediumd_vu_connected,
 	.handle = wmediumd_vu_handle,
@@ -1268,6 +1283,11 @@
 	case WMEDIUMD_MSG_STOP_PCAP:
 		close_pcapng(ctx);
 		break;
+	case WMEDIUMD_MSG_SET_POSITION:
+		if (process_set_position_message(ctx, (struct wmediumd_set_position *)data) < 0) {
+			response = WMEDIUMD_MSG_INVALID;
+		}
+		break;
 	case WMEDIUMD_MSG_ACK:
 		assert(client->wait_for_ack == true);
 		assert(hdr.data_len == 0);
diff --git a/wmediumd/wmediumd.h b/wmediumd/wmediumd.h
index 4001998..f8bc395 100644
--- a/wmediumd/wmediumd.h
+++ b/wmediumd/wmediumd.h
@@ -110,7 +110,7 @@
 
 #define VERSION_NR 1
 
-#define SNR_DEFAULT 90
+#define SNR_DEFAULT 30
 
 #include <stdint.h>
 #include <stdbool.h>