#include #include #include #include #include #include #include #include #include #include #define MAC_ADDR_LEN 6 #define STR_MAC_ADDR_LEN 17 #define OPENWRT_MAC_ADDR_1 "42:00:00:00:00:00" #define OPENWRT_MAC_ADDR_2 "42:00:00:00:01:00" #define TX_POWER_DEFAULT 10 #define APPEND_LAST -1 #define DEFAULT_RADIO_COUNT 2 #define DEFAULT_CUTTLEFISH_INSTANCE_COUNT 64 #define DEFAULT_MAC_PREFIX 5554 #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) // Adds MAC addresses for cuttlefish. Addresses will be 02:XX:XX:YY:YY:00 // where // - XX:XX prefix. enumerated from `mac_prefix`(default: 5554) to // `mac_prefix` + `instance_count`(default: 16) - 1 // - YY:YY radio index. enumerated from 0 to `radios`(default: 2) - 1 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; 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[3] = (radio_num >> 8) & 0xff; 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; } 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 *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_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; 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"); 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_1); config_setting_set_string_elem(ids, APPEND_LAST, OPENWRT_MAC_ADDR_2); 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 values if not specified */ if (radio_count == -1) { radio_count = DEFAULT_RADIO_COUNT; } if (cuttlefish_instance_count == -1) { cuttlefish_instance_count = DEFAULT_CUTTLEFISH_INSTANCE_COUNT; } if (mac_prefix == -1) { mac_prefix = DEFAULT_MAC_PREFIX; } 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_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) { 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; }