280 lines
7.3 KiB
C
280 lines
7.3 KiB
C
#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)
|
|
|
|
// 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;
|
|
}
|
|
|
|
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);
|
|
|
|
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;
|
|
}
|