Merge "Add cmd line utility that generates wmediumd configuration file" am: a23df325eb
Original change: https://android-review.googlesource.com/c/platform/external/wmediumd/+/1784368
Change-Id: Ifdb22e656e6fa4103c9efa65f6344528dbbf296c
diff --git a/Android.bp b/Android.bp
index 526485d..324c6ee 100644
--- a/Android.bp
+++ b/Android.bp
@@ -16,6 +16,19 @@
wmediumd_version = "0.3.1"
cc_binary_host {
+ name: "wmediumd_gen_config",
+ srcs: [
+ "util/wmediumd_gen_config.c",
+ ],
+ static_libs: [
+ "libconfig",
+ ],
+ visibility: [
+ "//visibility:private"
+ ],
+}
+
+cc_binary_host {
name: "wmediumd",
srcs: [
"wmediumd/*.c",
diff --git a/util/wmediumd_gen_config.c b/util/wmediumd_gen_config.c
new file mode 100644
index 0000000..d199024
--- /dev/null
+++ b/util/wmediumd_gen_config.c
@@ -0,0 +1,274 @@
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+#include <libconfig.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define MAC_ADDR_LEN 6
+#define STR_MAC_ADDR_LEN 17
+
+#define OPENWRT_MAC_ADDR "02:00:00:00:00:00"
+
+#define APPEND_LAST -1
+
+#define PREVENT_MULTIPLE_OPTION(var, zero_val) \
+ do { \
+ if ((var) != (zero_val)) { \
+ fprintf(stderr, "Error - cannot use option '%c' multiple times\n\n", \
+ opt); \
+ print_help(-1); \
+ } \
+ } while (0)
+
+int add_cuttlefish_mac_addresses(config_setting_t *ids, int mac_prefix,
+ int instance_count, int radios) {
+ for (int instance_num = 0; instance_num < instance_count; ++instance_num) {
+ char iface_id[STR_MAC_ADDR_LEN + 1] = {
+ 0,
+ };
+ uint8_t mac[MAC_ADDR_LEN] = {
+ 0,
+ };
+ uint32_t instance_mac_prefix = mac_prefix + instance_num * 2;
+
+ mac[0] = 0x02;
+ mac[1] = (instance_mac_prefix >> 8) & 0xff;
+ mac[2] = instance_mac_prefix & 0xff;
+
+ for (int radio_num = 0; radio_num < radios; ++radio_num) {
+ mac[4] = radio_num;
+
+ snprintf(iface_id, sizeof(iface_id), "%02x:%02x:%02x:%02x:%02x:%02x",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+
+ config_setting_set_string_elem(ids, APPEND_LAST, iface_id);
+ }
+ }
+
+ return 0;
+}
+
+bool valid_mac_addr(const char *mac_addr) {
+ if (strlen(mac_addr) != STR_MAC_ADDR_LEN) return false;
+
+ if (mac_addr[2] != ':' || mac_addr[5] != ':' || mac_addr[8] != ':' ||
+ mac_addr[11] != ':' || mac_addr[14] != ':') {
+ return false;
+ }
+
+ for (int i = 0; i < STR_MAC_ADDR_LEN; ++i) {
+ if ((i - 2) % 3 == 0) continue;
+ char c = mac_addr[i];
+
+ if (isupper(c)) {
+ c = tolower(c);
+ }
+
+ if ((c < '0' || c > '9') && (c < 'a' || c > 'f')) return false;
+ }
+
+ return true;
+}
+
+void print_help(int exit_code) {
+ printf("wmediumd_gen_config - wmediumd config generator\n");
+ printf(
+ "wmediumd_gen_config [-h] [-n count] [-r count] [-p prefix] [-m "
+ "MAC_ADDR] [-o "
+ "PATH]\n");
+ printf(" -h print help and exit\n");
+ printf(
+ " -n count cuttlefish instance count for adding pre-defined mac "
+ "address\n");
+ printf(
+ " -r count radio count of each cuttlefish instance (default: "
+ "2)\n");
+ printf(
+ " -p prefix set prefix for cuttlefish mac address (default: "
+ "5554)\n");
+ printf(
+ " second and third byte of mac address will be set to "
+ "prefix\n");
+ printf(" ex) -p 5554 ex) -p 0x15b2\n");
+ printf(" -m MAC_ADDR add mac address as pre-defined mac address\n");
+ printf(" ex) -m 02:15:b2:00:00:00\n");
+ printf(
+ " -o PATH if specified, output result to file (default: "
+ "stdout)\n");
+ printf("\n");
+
+ exit(exit_code);
+}
+
+int parse_count_option(const char *value, int opt) {
+ char *parse_end_token;
+
+ int result = strtol(value, &parse_end_token, 10);
+
+ if ((result == LONG_MAX && errno == ERANGE) || optarg == parse_end_token ||
+ result <= 0) {
+ fprintf(stderr, "Error - Invalid count value '%s' at option '%c'\n\n",
+ value, opt);
+ return -1;
+ }
+
+ return result;
+}
+
+int parse_prefix_option(const char *value, int opt) {
+ char *parse_end_token;
+ int base = 10;
+
+ if (strlen(value) >= 2 && value[0] == '0' && value[1] == 'x') {
+ value += 2;
+ base = 16;
+ }
+
+ int result = strtol(value, &parse_end_token, base);
+
+ if ((result == LONG_MAX && errno == ERANGE) || optarg == parse_end_token ||
+ result < 0) {
+ fprintf(stderr, "Error - Invalid prefix value '%s' at option '%c'\n\n",
+ value, opt);
+ return -1;
+ }
+
+ if (result > 0xffff) {
+ fprintf(
+ stderr,
+ "Error - Prefix value should not be greater than 0xffff(65535) \n\n",
+ value, opt);
+ return -1;
+ }
+
+ return result;
+}
+
+int main(int argc, char **argv) {
+ config_t cfg;
+
+ config_init(&cfg);
+
+ config_setting_t *root = config_root_setting(&cfg);
+ config_setting_t *ifaces =
+ config_setting_add(root, "ifaces", CONFIG_TYPE_GROUP);
+
+ config_setting_t *count =
+ config_setting_add(ifaces, "count", CONFIG_TYPE_INT);
+ config_setting_t *ids = config_setting_add(ifaces, "ids", CONFIG_TYPE_ARRAY);
+
+ config_setting_set_string_elem(ids, APPEND_LAST, OPENWRT_MAC_ADDR);
+
+ FILE *output = stdout;
+ char *out_path = NULL;
+ int opt;
+ int cuttlefish_instance_count = -1;
+ int radio_count = -1;
+ int mac_prefix = -1;
+
+ while ((opt = getopt(argc, argv, "hn:p:r:m:o:")) != -1) {
+ switch (opt) {
+ case ':':
+ fprintf(stderr, "Error - Option '%c' needs a value\n\n", optopt);
+ print_help(-1);
+ break;
+ case 'h':
+ print_help(0);
+ break;
+ case 'n':
+ PREVENT_MULTIPLE_OPTION(cuttlefish_instance_count, -1);
+
+ cuttlefish_instance_count = parse_count_option(optarg, opt);
+
+ if (cuttlefish_instance_count < 0) {
+ print_help(-1);
+ }
+ break;
+ case 'p':
+ PREVENT_MULTIPLE_OPTION(mac_prefix, -1);
+
+ mac_prefix = parse_prefix_option(optarg, opt);
+
+ if (mac_prefix < 0) {
+ print_help(-1);
+ }
+ break;
+ case 'r':
+ PREVENT_MULTIPLE_OPTION(radio_count, -1);
+
+ radio_count = parse_count_option(optarg, opt);
+
+ if (radio_count < 0) {
+ print_help(-1);
+ }
+ break;
+ case 'm':
+ if (!valid_mac_addr(optarg)) {
+ fprintf(stderr, "Error - '%s' is not a valid mac address\n\n",
+ optarg);
+ print_help(-1);
+ }
+
+ config_setting_set_string_elem(ids, APPEND_LAST, optarg);
+ break;
+ case 'o':
+ PREVENT_MULTIPLE_OPTION(out_path, NULL);
+
+ out_path = strdup(optarg);
+ break;
+ case '?':
+ fprintf(stderr, "Error - Unknown option '%c'\n\n", optopt);
+ print_help(-1);
+ break;
+ }
+ }
+
+ /* Use default radio count if not specified */
+
+ if (radio_count == -1) {
+ radio_count = 2;
+ }
+
+ if (cuttlefish_instance_count == -1) {
+ cuttlefish_instance_count = 16;
+ }
+
+ if (mac_prefix == -1) {
+ mac_prefix = 5554;
+ }
+
+ if (add_cuttlefish_mac_addresses(ids, mac_prefix, cuttlefish_instance_count,
+ radio_count) < 0) {
+ fprintf(stderr, "Error - Failed to add cuttlefish mac address\n\n");
+ print_help(-1);
+ }
+
+ config_setting_set_int(count, config_setting_length(ids));
+
+ if (out_path != NULL) {
+ FILE *out_file = fopen(out_path, "w");
+
+ if (out_file == NULL) {
+ perror("fopen");
+ fprintf(stderr, "Error - Cannot open '%s'\n\n", out_path);
+ return -1;
+ }
+
+ output = out_file;
+ }
+
+ config_write(&cfg, output);
+
+ if (out_path != NULL) {
+ free(out_path);
+ }
+
+ config_destroy(&cfg);
+
+ return 0;
+}