blob: 88215d7846e51234dd70347be94f618027fa2d5a [file] [log] [blame]
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001/*
2 * Sigma Control API DUT (station/AP)
Amarnath Hullur Subramanyam659a34c2017-03-17 00:04:41 -07003 * Copyright (c) 2014-2017, Qualcomm Atheros, Inc.
Ankita Bajaj1bde7942018-01-09 19:15:01 +05304 * Copyright (c) 2018, The Linux Foundation
Jouni Malinencd4e3c32015-10-29 12:39:56 +02005 * All Rights Reserved.
6 * Licensed under the Clear BSD license. See README for more details.
7 */
8
9#include "sigma_dut.h"
10#include <sys/stat.h>
11#include "wpa_helpers.h"
12
13enum driver_type wifi_chip_type = DRIVER_NOT_SET;
14enum openwrt_driver_type openwrt_chip_type = OPENWRT_DRIVER_NOT_SET;
15
16
17int file_exists(const char *fname)
18{
19 struct stat s;
20 return stat(fname, &s) == 0;
21}
22
23
24int set_wifi_chip(const char *chip_type)
25{
26 if (!strncmp(chip_type, "WCN", strlen("WCN")))
27 wifi_chip_type = DRIVER_WCN;
28 else if (!strncmp(chip_type, "ATHEROS", strlen("ATHEROS")))
29 wifi_chip_type = DRIVER_ATHEROS;
30 else if (!strncmp(chip_type, "AR6003", strlen("AR6003")))
31 wifi_chip_type = DRIVER_AR6003;
32 else if (strcmp(chip_type, "MAC80211") == 0)
33 wifi_chip_type = DRIVER_MAC80211;
34 else if (strcmp(chip_type, "QNXNTO") == 0)
35 wifi_chip_type = DRIVER_QNXNTO;
36 else if (strcmp(chip_type, "OPENWRT") == 0)
37 wifi_chip_type = DRIVER_OPENWRT;
Sreelakshmi Konamkib692f102016-04-26 19:47:00 +053038 else if (!strncmp(chip_type, "LINUX-WCN", strlen("LINUX-WCN")))
39 wifi_chip_type = DRIVER_LINUX_WCN;
Jouni Malinencd4e3c32015-10-29 12:39:56 +020040 else
41 return -1;
42
43 return 0;
44}
45
46
47enum driver_type get_driver_type(void)
48{
49 struct stat s;
50 if (wifi_chip_type == DRIVER_NOT_SET) {
51 /* Check for 60G driver */
52 ssize_t len;
53 char link[256];
54 char buf[256];
55 char *ifname = get_station_ifname();
56
57 snprintf(buf, sizeof(buf), "/sys/class/net/%s/device/driver",
58 ifname);
59 len = readlink(buf, link, sizeof(link) - 1);
60 if (len >= 0) {
61 link[len] = '\0';
62 if (strstr(link, DRIVER_NAME_60G))
63 return DRIVER_WIL6210;
64 }
65
66 if (stat("/sys/module/mac80211", &s) == 0)
67 return DRIVER_MAC80211;
68 return DRIVER_ATHEROS;
69 }
70 return wifi_chip_type;
71}
72
73
74enum openwrt_driver_type get_openwrt_driver_type(void)
75{
76 struct stat s;
77
78 if (openwrt_chip_type == OPENWRT_DRIVER_NOT_SET) {
priyadharshini gowthaman00bbdf12018-01-29 12:42:00 -080079 if (stat("/sys/module/umac", &s) == 0 ||
80 stat("/sys/module/atd", &s) == 0)
Jouni Malinencd4e3c32015-10-29 12:39:56 +020081 openwrt_chip_type = OPENWRT_DRIVER_ATHEROS;
82 }
83
84 return openwrt_chip_type;
85}
86
87
88enum sigma_program sigma_program_to_enum(const char *prog)
89{
90 if (prog == NULL)
91 return PROGRAM_UNKNOWN;
92
93 if (strcasecmp(prog, "TDLS") == 0)
94 return PROGRAM_TDLS;
95 if (strcasecmp(prog, "HS2") == 0)
96 return PROGRAM_HS2;
97 if (strcasecmp(prog, "HS2_R2") == 0 ||
Jouni Malinenba630452018-06-22 11:49:59 +030098 strcasecmp(prog, "HS2-R2") == 0)
Jouni Malinencd4e3c32015-10-29 12:39:56 +020099 return PROGRAM_HS2_R2;
Jouni Malinenba630452018-06-22 11:49:59 +0300100 if (strcasecmp(prog, "HS2-R3") == 0)
101 return PROGRAM_HS2_R3;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200102 if (strcasecmp(prog, "WFD") == 0)
103 return PROGRAM_WFD;
Amarnath Hullur Subramanyam659a34c2017-03-17 00:04:41 -0700104 if (strcasecmp(prog, "DisplayR2") == 0)
105 return PROGRAM_DISPLAYR2;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200106 if (strcasecmp(prog, "PMF") == 0)
107 return PROGRAM_PMF;
108 if (strcasecmp(prog, "WPS") == 0)
109 return PROGRAM_WPS;
110 if (strcasecmp(prog, "11n") == 0)
111 return PROGRAM_HT;
112 if (strcasecmp(prog, "VHT") == 0)
113 return PROGRAM_VHT;
114 if (strcasecmp(prog, "60GHZ") == 0)
115 return PROGRAM_60GHZ;
116 if (strcasecmp(prog, "NAN") == 0)
117 return PROGRAM_NAN;
priyadharshini gowthaman12dd4142016-06-22 22:47:14 -0700118 if (strcasecmp(prog, "LOC") == 0)
119 return PROGRAM_LOC;
priyadharshini gowthamanb4e05fc2016-10-13 15:02:35 -0700120 if (strcasecmp(prog, "MBO") == 0)
121 return PROGRAM_MBO;
Adil Saeed Musthafa33ea2872017-04-10 23:13:24 -0700122 if (strcasecmp(prog, "IoTLP") == 0)
123 return PROGRAM_IOTLP;
Jouni Malinen5c3813a2017-08-26 13:30:39 +0300124 if (strcasecmp(prog, "DPP") == 0)
125 return PROGRAM_DPP;
Ankita Bajaja2cb5672017-10-25 16:08:28 +0530126 if (strcasecmp(prog, "OCE") == 0)
127 return PROGRAM_OCE;
priyadharshini gowthaman0e209fc2018-01-26 15:15:37 -0800128 if (strcasecmp(prog, "WPA3") == 0)
129 return PROGRAM_WPA3;
Amarnath Hullur Subramanyam8f9c8682018-01-30 19:01:51 -0800130 if (strcasecmp(prog, "HE") == 0)
131 return PROGRAM_HE;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200132
133 return PROGRAM_UNKNOWN;
134}
priyadharshini gowthaman72462ef2016-06-22 22:47:14 -0700135
136
137static int parse_hex(char c)
138{
139 if (c >= '0' && c <= '9')
140 return c - '0';
141 if (c >= 'a' && c <= 'f')
142 return c - 'a' + 10;
143 if (c >= 'A' && c <= 'F')
144 return c - 'A' + 10;
145 return -1;
146}
147
148
149static int hex_byte(const char *str)
150{
151 int res1, res2;
152
153 res1 = parse_hex(str[0]);
154 if (res1 < 0)
155 return -1;
156 res2 = parse_hex(str[1]);
157 if (res2 < 0)
158 return -1;
159 return (res1 << 4) | res2;
160}
161
162
Jouni Malinen08cf2312017-09-04 13:39:47 +0300163int parse_hexstr(const char *hex, unsigned char *buf, size_t buflen)
164{
165 size_t i;
166 const char *pos = hex;
167
168 for (i = 0; i < buflen; i++) {
169 int val;
170
171 if (*pos == '\0')
172 break;
173 val = hex_byte(pos);
174 if (val < 0)
175 return -1;
176 buf[i] = val;
177 pos += 2;
178 }
179
180 return i;
181}
182
183
priyadharshini gowthaman72462ef2016-06-22 22:47:14 -0700184int parse_mac_address(struct sigma_dut *dut, const char *arg,
185 unsigned char *addr)
186{
187 int i;
188 const char *pos = arg;
189
190 if (strlen(arg) != 17)
191 goto fail;
192
193 for (i = 0; i < ETH_ALEN; i++) {
194 int val;
195
196 val = hex_byte(pos);
197 if (val < 0)
198 goto fail;
199 addr[i] = val;
200 if (i + 1 < ETH_ALEN) {
201 pos += 2;
202 if (*pos != ':')
203 goto fail;
204 pos++;
205 }
206 }
207
208 return 0;
209
210fail:
211 sigma_dut_print(dut, DUT_MSG_ERROR,
212 "Invalid MAC address %s (expected format xx:xx:xx:xx:xx:xx)",
213 arg);
214 return -1;
215}
Rakesh Sunki7192dc42017-03-30 14:47:55 -0700216
217
Alexei Avshalom Lazar093569f2018-11-13 14:08:17 +0200218int is_60g_sigma_dut(struct sigma_dut *dut)
Rakesh Sunki7192dc42017-03-30 14:47:55 -0700219{
Alexei Avshalom Lazar093569f2018-11-13 14:08:17 +0200220 return dut->program == PROGRAM_60GHZ ||
221 (dut->program == PROGRAM_WPS &&
222 (get_driver_type() == DRIVER_WIL6210));
223}
224
225
226unsigned int channel_to_freq(struct sigma_dut *dut, unsigned int channel)
227{
228 if (is_60g_sigma_dut(dut)) {
229 if (channel >= 1 && channel <= 4)
230 return 58320 + 2160 * channel;
231
232 return 0;
233 }
234
Rakesh Sunki7192dc42017-03-30 14:47:55 -0700235 if (channel >= 1 && channel <= 13)
236 return 2407 + 5 * channel;
237 if (channel == 14)
238 return 2484;
239 if (channel >= 36 && channel <= 165)
240 return 5000 + 5 * channel;
241
242 return 0;
243}
244
245
246unsigned int freq_to_channel(unsigned int freq)
247{
248 if (freq >= 2412 && freq <= 2472)
249 return (freq - 2407) / 5;
250 if (freq == 2484)
251 return 14;
252 if (freq >= 5180 && freq <= 5825)
253 return (freq - 5000) / 5;
Alexei Avshalom Lazar093569f2018-11-13 14:08:17 +0200254 if (freq >= 58320 && freq <= 64800)
255 return (freq - 58320) / 2160;
Rakesh Sunki7192dc42017-03-30 14:47:55 -0700256 return 0;
257}
Peng Xu769731a2017-05-10 17:27:28 -0700258
259
Peng Xu525965b2018-06-26 16:40:14 -0700260int is_ipv6_addr(const char *str)
261{
262 struct sockaddr_in6 addr;
263
264 return inet_pton(AF_INET6, str, &(addr.sin6_addr));
265}
266
267
Rakesh Sunki8f8e74b2017-05-16 15:42:12 -0700268void convert_mac_addr_to_ipv6_lladdr(u8 *mac_addr, char *ipv6_buf,
269 size_t buf_len)
270{
271 u8 temp = mac_addr[0] ^ 0x02;
272
273 snprintf(ipv6_buf, buf_len, "fe80::%02x%02x:%02xff:fe%02x:%02x%02x",
274 temp, mac_addr[1], mac_addr[2],
275 mac_addr[3], mac_addr[4], mac_addr[5]);
276}
277
278
Peng Xu8863ec72018-08-06 11:50:37 -0700279size_t convert_mac_addr_to_ipv6_linklocal(const u8 *mac_addr, u8 *ipv6)
280{
281 int i;
282
283 ipv6[0] = 0xfe;
284 ipv6[1] = 0x80;
285 for (i = 2; i < 8; i++)
286 ipv6[i] = 0;
287 ipv6[8] = mac_addr[0] ^ 0x02;
288 ipv6[9] = mac_addr[1];
289 ipv6[10] = mac_addr[2];
290 ipv6[11] = 0xff;
291 ipv6[12] = 0xfe;
292 ipv6[13] = mac_addr[3];
293 ipv6[14] = mac_addr[4];
294 ipv6[15] = mac_addr[5];
295
296 return 16;
297}
298
299
Peng Xu769731a2017-05-10 17:27:28 -0700300#ifndef ANDROID
301
302size_t strlcpy(char *dest, const char *src, size_t siz)
303{
304 const char *s = src;
305 size_t left = siz;
306
307 if (left) {
308 /* Copy string up to the maximum size of the dest buffer */
309 while (--left != 0) {
310 if ((*dest++ = *s++) == '\0')
311 break;
312 }
313 }
314
315 if (left == 0) {
316 /* Not enough room for the string; force NUL-termination */
317 if (siz != 0)
318 *dest = '\0';
319 while (*s++)
320 ; /* determine total src string length */
321 }
322
323 return s - src - 1;
324}
325
326
327size_t strlcat(char *dst, const char *str, size_t size)
328{
329 char *pos;
330 size_t dstlen, srclen, copy;
331
332 srclen = strlen(str);
333 for (pos = dst; pos - dst < size && *dst; pos++)
334 ;
335 dstlen = pos - dst;
336 if (*dst)
337 return dstlen + srclen;
338 if (dstlen + srclen + 1 > size)
339 copy = size - dstlen - 1;
340 else
341 copy = srclen;
342 memcpy(pos, str, copy);
343 pos[copy] = '\0';
344 return dstlen + srclen;
345}
346
347#endif /* ANDROID */
Ankita Bajaj1bde7942018-01-09 19:15:01 +0530348
349
350void hex_dump(struct sigma_dut *dut, u8 *data, size_t len)
351{
352 char buf[1024];
353 size_t index;
354 u8 *ptr;
355 int pos;
356
357 memset(buf, 0, sizeof(buf));
358 ptr = data;
359 pos = 0;
360 for (index = 0; index < len; index++) {
361 pos += snprintf(&(buf[pos]), sizeof(buf) - pos,
362 "%02x ", *ptr++);
363 if (pos > 1020)
364 break;
365 }
366 sigma_dut_print(dut, DUT_MSG_INFO, "HEXDUMP len=[%d]", (int) len);
367 sigma_dut_print(dut, DUT_MSG_INFO, "buf:%s", buf);
368}
Peng Xu291d97d2018-01-31 16:34:03 -0800369
370
371#ifdef NL80211_SUPPORT
372
373void * nl80211_cmd(struct sigma_dut *dut, struct nl80211_ctx *ctx,
374 struct nl_msg *msg, int flags, uint8_t cmd)
375{
376 return genlmsg_put(msg, 0, 0, ctx->netlink_familyid,
377 0, flags, cmd, 0);
378}
379
380
381static struct nl_msg *
382nl80211_ifindex_msg(struct sigma_dut *dut, struct nl80211_ctx *ctx, int ifindex,
383 int flags, uint8_t cmd)
384{
385 struct nl_msg *msg;
386
387 msg = nlmsg_alloc();
388 if (!msg) {
389 sigma_dut_print(dut, DUT_MSG_ERROR,
390 "Failed to allocate NL message");
391 return NULL;
392 }
393
394 if (!nl80211_cmd(dut, ctx, msg, flags, cmd) ||
395 nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifindex)) {
396 nlmsg_free(msg);
397 return NULL;
398 }
399
400 return msg;
401}
402
403
404struct nl_msg * nl80211_drv_msg(struct sigma_dut *dut, struct nl80211_ctx *ctx,
405 int ifindex, int flags, uint8_t cmd)
406{
407 return nl80211_ifindex_msg(dut, ctx, ifindex, flags, cmd);
408}
409
410
411static int ack_handler(struct nl_msg *msg, void *arg)
412{
413 int *err = arg;
414 *err = 0;
415 return NL_STOP;
416}
417
418
419static int finish_handler(struct nl_msg *msg, void *arg)
420{
421 int *ret = arg;
422 *ret = 0;
423 return NL_SKIP;
424}
425
426
427static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
428 void *arg)
429{
430 int *ret = arg;
431 *ret = err->error;
432 return NL_SKIP;
433}
434
435
436int send_and_recv_msgs(struct sigma_dut *dut, struct nl80211_ctx *ctx,
437 struct nl_msg *nlmsg,
438 int (*valid_handler)(struct nl_msg *, void *),
439 void *valid_data)
440{
441 struct nl_cb *cb;
442 int err = -ENOMEM;
443
444 if (!nlmsg)
445 return -ENOMEM;
446
447 cb = nl_cb_alloc(NL_CB_DEFAULT);
448 if (!cb)
449 goto out;
450
451 err = nl_send_auto_complete(ctx->sock, nlmsg);
452 if (err < 0) {
453 sigma_dut_print(dut, DUT_MSG_ERROR,
454 "nl80211: failed to send err=%d", err);
455 goto out;
456 }
457
458 err = 1;
459
460 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
461 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
462 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
463
464 if (valid_handler)
465 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
466 valid_handler, valid_data);
467
468 while (err > 0) {
469 int res = nl_recvmsgs(ctx->sock, cb);
470
471 if (res < 0) {
472 sigma_dut_print(dut, DUT_MSG_ERROR,
473 "nl80211: %s->nl_recvmsgs failed: res=%d, err=%d",
474 __func__, res, err);
475 }
476 }
477 out:
478 nl_cb_put(cb);
479 if (!valid_handler && valid_data == (void *) -1) {
480 if (nlmsg) {
481 struct nlmsghdr *hdr = nlmsg_hdr(nlmsg);
482 void *data = nlmsg_data(hdr);
483 int len = hdr->nlmsg_len - NLMSG_HDRLEN;
484
485 memset(data, 0, len);
486 }
487 }
488
489 nlmsg_free(nlmsg);
490 return err;
491}
492
493
494struct nl80211_ctx * nl80211_init(struct sigma_dut *dut)
495{
496 struct nl80211_ctx *ctx;
497
498 ctx = calloc(1, sizeof(struct nl80211_ctx));
499 if (!ctx) {
500 sigma_dut_print(dut, DUT_MSG_ERROR,
501 "Failed to alloc nl80211_ctx");
502 return NULL;
503 }
504
505 ctx->sock = nl_socket_alloc();
506 if (!ctx->sock) {
507 sigma_dut_print(dut, DUT_MSG_ERROR,
508 "Failed to create NL socket, err: %s",
509 strerror(errno));
510 goto cleanup;
511 }
512
513 if (nl_connect(ctx->sock, NETLINK_GENERIC)) {
514 sigma_dut_print(dut, DUT_MSG_ERROR,
515 "Could not connect socket, err: %s",
516 strerror(errno));
517 goto cleanup;
518 }
519
520 if (nl_socket_set_buffer_size(ctx->sock, SOCK_BUF_SIZE, 0) < 0) {
521 sigma_dut_print(dut, DUT_MSG_INFO,
522 "Could not set nl_socket RX buffer size for sock: %s",
523 strerror(errno));
524 }
525
526 ctx->netlink_familyid = genl_ctrl_resolve(ctx->sock, "nl80211");
527 if (ctx->netlink_familyid < 0) {
528 sigma_dut_print(dut, DUT_MSG_ERROR,
529 "Could not resolve nl80211 family id");
530 goto cleanup;
531 }
532
533 ctx->nlctrl_familyid = genl_ctrl_resolve(ctx->sock, "nlctrl");
534 if (ctx->nlctrl_familyid < 0) {
535 sigma_dut_print(dut, DUT_MSG_ERROR,
536 "net link family nlctrl is not present: %d err:%s",
537 ctx->nlctrl_familyid, strerror(errno));
538 goto cleanup;
539 }
540
541 return ctx;
542
543cleanup:
544 if (ctx->sock)
545 nl_socket_free(ctx->sock);
546
547 free(ctx);
548 return NULL;
549}
550
551
552void nl80211_deinit(struct sigma_dut *dut, struct nl80211_ctx *ctx)
553{
554 if (!ctx || !ctx->sock) {
555 sigma_dut_print(dut, DUT_MSG_ERROR, "%s: ctx/sock is NULL",
556 __func__);
557 return;
558 }
559 nl_socket_free(ctx->sock);
560 free(ctx);
561}
562
563#endif /* NL80211_SUPPORT */
Alexei Avshalom Lazar64279692018-12-23 16:49:49 +0200564
565
566void str_remove_chars(char *str, char ch)
567{
568 char *pr = str, *pw = str;
569
570 while (*pr) {
571 *pw = *pr++;
572 if (*pw != ch)
573 pw++;
574 }
575 *pw = '\0';
576}