xref: /aosp_15_r20/external/wmediumd/util/wmediumd_gen_config.c (revision 621120a22a0cd8ba80b131fe8bcb37c86ff453e3)
1 #include <ctype.h>
2 #include <errno.h>
3 #include <getopt.h>
4 #include <libconfig.h>
5 #include <limits.h>
6 #include <stdbool.h>
7 #include <stdint.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 
12 #define MAC_ADDR_LEN 6
13 #define STR_MAC_ADDR_LEN 17
14 
15 #define OPENWRT_MAC_ADDR_1 "42:00:00:00:00:00"
16 #define OPENWRT_MAC_ADDR_2 "42:00:00:00:01:00"
17 
18 #define TX_POWER_DEFAULT 10
19 
20 #define APPEND_LAST -1
21 
22 #define DEFAULT_RADIO_COUNT 2
23 #define DEFAULT_CUTTLEFISH_INSTANCE_COUNT 64
24 #define DEFAULT_MAC_PREFIX 5554
25 
26 #define PREVENT_MULTIPLE_OPTION(var, zero_val)                             \
27   do {                                                                     \
28     if ((var) != (zero_val)) {                                             \
29       fprintf(stderr, "Error - cannot use option '%c' multiple times\n\n", \
30               opt);                                                        \
31       print_help(-1);                                                      \
32     }                                                                      \
33   } while (0)
34 
35 // Adds MAC addresses for cuttlefish. Addresses will be 02:XX:XX:YY:YY:00
36 // where
37 //  - XX:XX prefix. enumerated from `mac_prefix`(default: 5554) to
38 //          `mac_prefix` + `instance_count`(default: 16) - 1
39 //  - YY:YY radio index. enumerated from 0 to `radios`(default: 2) - 1
add_cuttlefish_mac_addresses(config_setting_t * ids,int mac_prefix,int instance_count,int radios)40 int add_cuttlefish_mac_addresses(config_setting_t *ids, int mac_prefix,
41                                  int instance_count, int radios) {
42   for (int instance_num = 0; instance_num < instance_count; ++instance_num) {
43     char iface_id[STR_MAC_ADDR_LEN + 1] = {
44         0,
45     };
46     uint8_t mac[MAC_ADDR_LEN] = {
47         0,
48     };
49     uint32_t instance_mac_prefix = mac_prefix + instance_num;
50 
51     mac[0] = 0x02;
52     mac[1] = (instance_mac_prefix >> 8) & 0xff;
53     mac[2] = instance_mac_prefix & 0xff;
54 
55     for (int radio_num = 0; radio_num < radios; ++radio_num) {
56       mac[3] = (radio_num >> 8) & 0xff;
57       mac[4] = radio_num;
58 
59       snprintf(iface_id, sizeof(iface_id), "%02x:%02x:%02x:%02x:%02x:%02x",
60                mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
61 
62       config_setting_set_string_elem(ids, APPEND_LAST, iface_id);
63     }
64   }
65 
66   return 0;
67 }
68 
add_cuttlefish_path_loss_model(config_setting_t * model,int instance_count)69 int add_cuttlefish_path_loss_model(config_setting_t *model,
70                                    int instance_count) {
71   config_setting_t *type =
72       config_setting_add(model, "type", CONFIG_TYPE_STRING);
73   config_setting_set_string(type, "path_loss");
74 
75   config_setting_t *model_name =
76       config_setting_add(model, "model_name", CONFIG_TYPE_STRING);
77   config_setting_set_string(model_name, "free_space");
78 
79   config_setting_t *positions =
80       config_setting_add(model, "positions", CONFIG_TYPE_LIST);
81   config_setting_t *tx_powers =
82       config_setting_add(model, "tx_powers", CONFIG_TYPE_ARRAY);
83 
84   for (int idx = 0; idx < instance_count; ++idx) {
85     config_setting_t *position =
86         config_setting_add(positions, NULL, CONFIG_TYPE_LIST);
87     config_setting_set_float_elem(position, APPEND_LAST, 0.0);
88     config_setting_set_float_elem(position, APPEND_LAST, 0.0);
89 
90     config_setting_set_float_elem(tx_powers, APPEND_LAST, TX_POWER_DEFAULT);
91   }
92 
93   return 0;
94 }
95 
valid_mac_addr(const char * mac_addr)96 bool valid_mac_addr(const char *mac_addr) {
97   if (strlen(mac_addr) != STR_MAC_ADDR_LEN) return false;
98 
99   if (mac_addr[2] != ':' || mac_addr[5] != ':' || mac_addr[8] != ':' ||
100       mac_addr[11] != ':' || mac_addr[14] != ':') {
101     return false;
102   }
103 
104   for (int i = 0; i < STR_MAC_ADDR_LEN; ++i) {
105     if ((i - 2) % 3 == 0) continue;
106     char c = mac_addr[i];
107 
108     if (isupper(c)) {
109       c = tolower(c);
110     }
111 
112     if ((c < '0' || c > '9') && (c < 'a' || c > 'f')) return false;
113   }
114 
115   return true;
116 }
117 
print_help(int exit_code)118 void print_help(int exit_code) {
119   printf("wmediumd_gen_config - wmediumd config generator\n");
120   printf(
121       "wmediumd_gen_config [-h] [-n count] [-r count] [-p prefix] [-m "
122       "MAC_ADDR] [-o "
123       "PATH]\n");
124   printf("  -h              print help and exit\n");
125   printf(
126       "  -n count        cuttlefish instance count for adding pre-defined mac "
127       "address\n");
128   printf(
129       "  -r count        radio count of each cuttlefish instance (default: "
130       "2)\n");
131   printf(
132       "  -p prefix       set prefix for cuttlefish mac address (default: "
133       "5554)\n");
134   printf(
135       "                  second and third byte of mac address will be set to "
136       "prefix\n");
137   printf("                    ex) -p 5554    ex) -p 0x15b2\n");
138   printf("  -m MAC_ADDR     add mac address as pre-defined mac address\n");
139   printf("                    ex) -m 02:15:b2:00:00:00\n");
140   printf(
141       "  -o PATH         if specified, output result to file (default: "
142       "stdout)\n");
143   printf("\n");
144 
145   exit(exit_code);
146 }
147 
parse_count_option(const char * value,int opt)148 int parse_count_option(const char *value, int opt) {
149   char *parse_end_token;
150 
151   int result = strtol(value, &parse_end_token, 10);
152 
153   if ((result == LONG_MAX && errno == ERANGE) || optarg == parse_end_token ||
154       result <= 0) {
155     fprintf(stderr, "Error - Invalid count value '%s' at option '%c'\n\n",
156             value, opt);
157     return -1;
158   }
159 
160   return result;
161 }
162 
parse_prefix_option(const char * value,int opt)163 int parse_prefix_option(const char *value, int opt) {
164   char *parse_end_token;
165   int base = 10;
166 
167   if (strlen(value) >= 2 && value[0] == '0' && value[1] == 'x') {
168     value += 2;
169     base = 16;
170   }
171 
172   int result = strtol(value, &parse_end_token, base);
173 
174   if ((result == LONG_MAX && errno == ERANGE) || optarg == parse_end_token ||
175       result < 0) {
176     fprintf(stderr, "Error - Invalid prefix value '%s' at option '%c'\n\n",
177             value, opt);
178     return -1;
179   }
180 
181   if (result > 0xffff) {
182     fprintf(
183         stderr,
184         "Error - Prefix value should not be greater than 0xffff(65535) \n\n");
185     return -1;
186   }
187 
188   return result;
189 }
190 
main(int argc,char ** argv)191 int main(int argc, char **argv) {
192   config_t cfg;
193 
194   config_init(&cfg);
195 
196   config_setting_t *root = config_root_setting(&cfg);
197   config_setting_t *ifaces =
198       config_setting_add(root, "ifaces", CONFIG_TYPE_GROUP);
199 
200   config_setting_t *count =
201       config_setting_add(ifaces, "count", CONFIG_TYPE_INT);
202   config_setting_t *ids = config_setting_add(ifaces, "ids", CONFIG_TYPE_ARRAY);
203 
204   config_setting_set_string_elem(ids, APPEND_LAST, OPENWRT_MAC_ADDR_1);
205   config_setting_set_string_elem(ids, APPEND_LAST, OPENWRT_MAC_ADDR_2);
206 
207   FILE *output = stdout;
208   char *out_path = NULL;
209   int opt;
210   int cuttlefish_instance_count = -1;
211   int radio_count = -1;
212   int mac_prefix = -1;
213 
214   while ((opt = getopt(argc, argv, "hn:p:r:m:o:")) != -1) {
215     switch (opt) {
216       case ':':
217         fprintf(stderr, "Error - Option '%c' needs a value\n\n", optopt);
218         print_help(-1);
219         break;
220       case 'h':
221         print_help(0);
222         break;
223       case 'n':
224         PREVENT_MULTIPLE_OPTION(cuttlefish_instance_count, -1);
225 
226         cuttlefish_instance_count = parse_count_option(optarg, opt);
227 
228         if (cuttlefish_instance_count < 0) {
229           print_help(-1);
230         }
231         break;
232       case 'p':
233         PREVENT_MULTIPLE_OPTION(mac_prefix, -1);
234 
235         mac_prefix = parse_prefix_option(optarg, opt);
236 
237         if (mac_prefix < 0) {
238           print_help(-1);
239         }
240         break;
241       case 'r':
242         PREVENT_MULTIPLE_OPTION(radio_count, -1);
243 
244         radio_count = parse_count_option(optarg, opt);
245 
246         if (radio_count < 0) {
247           print_help(-1);
248         }
249         break;
250       case 'm':
251         if (!valid_mac_addr(optarg)) {
252           fprintf(stderr, "Error - '%s' is not a valid mac address\n\n",
253                   optarg);
254           print_help(-1);
255         }
256 
257         config_setting_set_string_elem(ids, APPEND_LAST, optarg);
258         break;
259       case 'o':
260         PREVENT_MULTIPLE_OPTION(out_path, NULL);
261 
262         out_path = strdup(optarg);
263         break;
264       case '?':
265         fprintf(stderr, "Error - Unknown option '%c'\n\n", optopt);
266         print_help(-1);
267         break;
268     }
269   }
270 
271   /* Use default values if not specified */
272 
273   if (radio_count == -1) {
274     radio_count = DEFAULT_RADIO_COUNT;
275   }
276 
277   if (cuttlefish_instance_count == -1) {
278     cuttlefish_instance_count = DEFAULT_CUTTLEFISH_INSTANCE_COUNT;
279   }
280 
281   if (mac_prefix == -1) {
282     mac_prefix = DEFAULT_MAC_PREFIX;
283   }
284 
285   if (add_cuttlefish_mac_addresses(ids, mac_prefix, cuttlefish_instance_count,
286                                    radio_count) < 0) {
287     fprintf(stderr, "Error - Failed to add cuttlefish mac address\n\n");
288     print_help(-1);
289   }
290 
291   config_setting_t *model =
292       config_setting_add(root, "model", CONFIG_TYPE_GROUP);
293   add_cuttlefish_path_loss_model(model, config_setting_length(ids));
294 
295   config_setting_set_int(count, config_setting_length(ids));
296 
297   if (out_path != NULL) {
298     FILE *out_file = fopen(out_path, "w");
299 
300     if (out_file == NULL) {
301       perror("fopen");
302       fprintf(stderr, "Error - Cannot open '%s'\n\n", out_path);
303       return -1;
304     }
305 
306     output = out_file;
307   }
308 
309   config_write(&cfg, output);
310 
311   if (out_path != NULL) {
312     free(out_path);
313   }
314 
315   config_destroy(&cfg);
316 
317   return 0;
318 }
319