blob: c823f83e866793a6994a0edb5e5d21c163d4f29f [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.
Jouni Malinen2feb9132021-11-16 00:53:06 +02004 * Copyright (c) 2018-2021, The Linux Foundation
Alexei Avshalom Lazara37dc162019-02-04 14:06:48 +02005 * Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi>
Jouni Malinencd4e3c32015-10-29 12:39:56 +02006 * All Rights Reserved.
7 * Licensed under the Clear BSD license. See README for more details.
8 */
9
10#include "sigma_dut.h"
Vinita Maloo54b78cf2020-03-30 12:18:19 +053011#include <sys/ioctl.h>
Jouni Malinencd4e3c32015-10-29 12:39:56 +020012#include <sys/stat.h>
13#include "wpa_helpers.h"
14
15enum driver_type wifi_chip_type = DRIVER_NOT_SET;
16enum openwrt_driver_type openwrt_chip_type = OPENWRT_DRIVER_NOT_SET;
17
Vinita Maloo54b78cf2020-03-30 12:18:19 +053018struct wcn_drv_priv_cmd {
19 char *buf;
20 int used_len;
21 int total_len;
22};
Jouni Malinencd4e3c32015-10-29 12:39:56 +020023
24int file_exists(const char *fname)
25{
26 struct stat s;
27 return stat(fname, &s) == 0;
28}
29
30
31int set_wifi_chip(const char *chip_type)
32{
33 if (!strncmp(chip_type, "WCN", strlen("WCN")))
34 wifi_chip_type = DRIVER_WCN;
35 else if (!strncmp(chip_type, "ATHEROS", strlen("ATHEROS")))
36 wifi_chip_type = DRIVER_ATHEROS;
37 else if (!strncmp(chip_type, "AR6003", strlen("AR6003")))
38 wifi_chip_type = DRIVER_AR6003;
39 else if (strcmp(chip_type, "MAC80211") == 0)
40 wifi_chip_type = DRIVER_MAC80211;
41 else if (strcmp(chip_type, "QNXNTO") == 0)
42 wifi_chip_type = DRIVER_QNXNTO;
43 else if (strcmp(chip_type, "OPENWRT") == 0)
44 wifi_chip_type = DRIVER_OPENWRT;
Sreelakshmi Konamkib692f102016-04-26 19:47:00 +053045 else if (!strncmp(chip_type, "LINUX-WCN", strlen("LINUX-WCN")))
46 wifi_chip_type = DRIVER_LINUX_WCN;
Jouni Malinencd4e3c32015-10-29 12:39:56 +020047 else
48 return -1;
49
50 return 0;
51}
52
53
Jouni Malinen016ae6c2019-11-04 17:00:01 +020054enum driver_type get_driver_type(struct sigma_dut *dut)
Jouni Malinencd4e3c32015-10-29 12:39:56 +020055{
56 struct stat s;
57 if (wifi_chip_type == DRIVER_NOT_SET) {
58 /* Check for 60G driver */
59 ssize_t len;
60 char link[256];
61 char buf[256];
Jouni Malinen016ae6c2019-11-04 17:00:01 +020062 const char *ifname = get_station_ifname(dut);
Jouni Malinencd4e3c32015-10-29 12:39:56 +020063
64 snprintf(buf, sizeof(buf), "/sys/class/net/%s/device/driver",
65 ifname);
66 len = readlink(buf, link, sizeof(link) - 1);
67 if (len >= 0) {
68 link[len] = '\0';
69 if (strstr(link, DRIVER_NAME_60G))
70 return DRIVER_WIL6210;
71 }
72
73 if (stat("/sys/module/mac80211", &s) == 0)
74 return DRIVER_MAC80211;
75 return DRIVER_ATHEROS;
76 }
77 return wifi_chip_type;
78}
79
80
Venkateswara Naralasettyf0f88052020-11-11 19:15:17 +053081void sigma_dut_get_device_driver_name(const char *ifname, char *name,
82 size_t size)
83{
84 char fname[128], path[128];
85 struct stat s;
86 ssize_t res;
87 char *pos;
88
89 name[0] = '\0';
90
91 snprintf(path, sizeof(path), "/sys/class/net/%s/phy80211", ifname);
92 if (stat(path, &s) != 0)
93 return;
94
95 res = snprintf(fname, sizeof(fname),
96 "/sys/class/net/%s/device/driver", ifname);
97 if (res < 0 || res >= sizeof(fname))
98 return;
99 res = readlink(fname, path, sizeof(path));
100 if (res < 0)
101 return;
102
103 if (res >= (int) sizeof(path))
104 res = sizeof(path) - 1;
105 path[res] = '\0';
106 pos = strrchr(path, '/');
107 if (!pos)
108 pos = path;
109 else
110 pos++;
111 snprintf(name, size, "%s", pos);
112}
113
114
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200115enum openwrt_driver_type get_openwrt_driver_type(void)
116{
117 struct stat s;
118
119 if (openwrt_chip_type == OPENWRT_DRIVER_NOT_SET) {
priyadharshini gowthaman00bbdf12018-01-29 12:42:00 -0800120 if (stat("/sys/module/umac", &s) == 0 ||
121 stat("/sys/module/atd", &s) == 0)
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200122 openwrt_chip_type = OPENWRT_DRIVER_ATHEROS;
123 }
124
125 return openwrt_chip_type;
126}
127
128
129enum sigma_program sigma_program_to_enum(const char *prog)
130{
131 if (prog == NULL)
132 return PROGRAM_UNKNOWN;
133
134 if (strcasecmp(prog, "TDLS") == 0)
135 return PROGRAM_TDLS;
136 if (strcasecmp(prog, "HS2") == 0)
137 return PROGRAM_HS2;
138 if (strcasecmp(prog, "HS2_R2") == 0 ||
Jouni Malinenba630452018-06-22 11:49:59 +0300139 strcasecmp(prog, "HS2-R2") == 0)
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200140 return PROGRAM_HS2_R2;
Jouni Malinenba630452018-06-22 11:49:59 +0300141 if (strcasecmp(prog, "HS2-R3") == 0)
142 return PROGRAM_HS2_R3;
Jouni Malinen9a742ff2022-01-27 00:43:14 +0200143 if (strcasecmp(prog, "HS2-R4") == 0)
144 return PROGRAM_HS2_R4;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200145 if (strcasecmp(prog, "WFD") == 0)
146 return PROGRAM_WFD;
Amarnath Hullur Subramanyam659a34c2017-03-17 00:04:41 -0700147 if (strcasecmp(prog, "DisplayR2") == 0)
148 return PROGRAM_DISPLAYR2;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200149 if (strcasecmp(prog, "PMF") == 0)
150 return PROGRAM_PMF;
151 if (strcasecmp(prog, "WPS") == 0)
152 return PROGRAM_WPS;
153 if (strcasecmp(prog, "11n") == 0)
154 return PROGRAM_HT;
155 if (strcasecmp(prog, "VHT") == 0)
156 return PROGRAM_VHT;
157 if (strcasecmp(prog, "60GHZ") == 0)
158 return PROGRAM_60GHZ;
159 if (strcasecmp(prog, "NAN") == 0)
160 return PROGRAM_NAN;
priyadharshini gowthaman12dd4142016-06-22 22:47:14 -0700161 if (strcasecmp(prog, "LOC") == 0)
162 return PROGRAM_LOC;
priyadharshini gowthamanb4e05fc2016-10-13 15:02:35 -0700163 if (strcasecmp(prog, "MBO") == 0)
164 return PROGRAM_MBO;
Adil Saeed Musthafa33ea2872017-04-10 23:13:24 -0700165 if (strcasecmp(prog, "IoTLP") == 0)
166 return PROGRAM_IOTLP;
Jouni Malinen5c3813a2017-08-26 13:30:39 +0300167 if (strcasecmp(prog, "DPP") == 0)
168 return PROGRAM_DPP;
Ankita Bajaja2cb5672017-10-25 16:08:28 +0530169 if (strcasecmp(prog, "OCE") == 0)
170 return PROGRAM_OCE;
priyadharshini gowthaman0e209fc2018-01-26 15:15:37 -0800171 if (strcasecmp(prog, "WPA3") == 0)
172 return PROGRAM_WPA3;
Amarnath Hullur Subramanyam8f9c8682018-01-30 19:01:51 -0800173 if (strcasecmp(prog, "HE") == 0)
174 return PROGRAM_HE;
Vamsi Krishnaf642d6a2020-03-27 12:33:14 +0530175 if (strcasecmp(prog, "QM") == 0)
176 return PROGRAM_QM;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200177
178 return PROGRAM_UNKNOWN;
179}
priyadharshini gowthaman72462ef2016-06-22 22:47:14 -0700180
181
182static int parse_hex(char c)
183{
184 if (c >= '0' && c <= '9')
185 return c - '0';
186 if (c >= 'a' && c <= 'f')
187 return c - 'a' + 10;
188 if (c >= 'A' && c <= 'F')
189 return c - 'A' + 10;
190 return -1;
191}
192
193
Alexei Avshalom Lazar9a4f98d2019-05-02 13:35:22 +0300194int hex_byte(const char *str)
priyadharshini gowthaman72462ef2016-06-22 22:47:14 -0700195{
196 int res1, res2;
197
198 res1 = parse_hex(str[0]);
199 if (res1 < 0)
200 return -1;
201 res2 = parse_hex(str[1]);
202 if (res2 < 0)
203 return -1;
204 return (res1 << 4) | res2;
205}
206
207
Jouni Malinen08cf2312017-09-04 13:39:47 +0300208int parse_hexstr(const char *hex, unsigned char *buf, size_t buflen)
209{
210 size_t i;
211 const char *pos = hex;
212
213 for (i = 0; i < buflen; i++) {
214 int val;
215
216 if (*pos == '\0')
217 break;
218 val = hex_byte(pos);
219 if (val < 0)
220 return -1;
221 buf[i] = val;
222 pos += 2;
223 }
224
225 return i;
226}
227
228
priyadharshini gowthaman72462ef2016-06-22 22:47:14 -0700229int parse_mac_address(struct sigma_dut *dut, const char *arg,
230 unsigned char *addr)
231{
232 int i;
233 const char *pos = arg;
234
235 if (strlen(arg) != 17)
236 goto fail;
237
238 for (i = 0; i < ETH_ALEN; i++) {
239 int val;
240
241 val = hex_byte(pos);
242 if (val < 0)
243 goto fail;
244 addr[i] = val;
245 if (i + 1 < ETH_ALEN) {
246 pos += 2;
247 if (*pos != ':')
248 goto fail;
249 pos++;
250 }
251 }
252
253 return 0;
254
255fail:
256 sigma_dut_print(dut, DUT_MSG_ERROR,
257 "Invalid MAC address %s (expected format xx:xx:xx:xx:xx:xx)",
258 arg);
259 return -1;
260}
Rakesh Sunki7192dc42017-03-30 14:47:55 -0700261
262
Alexei Avshalom Lazar093569f2018-11-13 14:08:17 +0200263int is_60g_sigma_dut(struct sigma_dut *dut)
Rakesh Sunki7192dc42017-03-30 14:47:55 -0700264{
Alexei Avshalom Lazar093569f2018-11-13 14:08:17 +0200265 return dut->program == PROGRAM_60GHZ ||
266 (dut->program == PROGRAM_WPS &&
Jouni Malinen016ae6c2019-11-04 17:00:01 +0200267 (get_driver_type(dut) == DRIVER_WIL6210));
Alexei Avshalom Lazar093569f2018-11-13 14:08:17 +0200268}
269
270
271unsigned int channel_to_freq(struct sigma_dut *dut, unsigned int channel)
272{
273 if (is_60g_sigma_dut(dut)) {
274 if (channel >= 1 && channel <= 4)
275 return 58320 + 2160 * channel;
276
277 return 0;
278 }
279
Rakesh Sunki7192dc42017-03-30 14:47:55 -0700280 if (channel >= 1 && channel <= 13)
281 return 2407 + 5 * channel;
282 if (channel == 14)
283 return 2484;
284 if (channel >= 36 && channel <= 165)
285 return 5000 + 5 * channel;
286
287 return 0;
288}
289
290
291unsigned int freq_to_channel(unsigned int freq)
292{
293 if (freq >= 2412 && freq <= 2472)
294 return (freq - 2407) / 5;
295 if (freq == 2484)
296 return 14;
297 if (freq >= 5180 && freq <= 5825)
298 return (freq - 5000) / 5;
Alexei Avshalom Lazar093569f2018-11-13 14:08:17 +0200299 if (freq >= 58320 && freq <= 64800)
300 return (freq - 58320) / 2160;
Rakesh Sunki7192dc42017-03-30 14:47:55 -0700301 return 0;
302}
Peng Xu769731a2017-05-10 17:27:28 -0700303
304
Peng Xu525965b2018-06-26 16:40:14 -0700305int is_ipv6_addr(const char *str)
306{
307 struct sockaddr_in6 addr;
308
309 return inet_pton(AF_INET6, str, &(addr.sin6_addr));
310}
311
312
Rakesh Sunki8f8e74b2017-05-16 15:42:12 -0700313void convert_mac_addr_to_ipv6_lladdr(u8 *mac_addr, char *ipv6_buf,
314 size_t buf_len)
315{
316 u8 temp = mac_addr[0] ^ 0x02;
317
318 snprintf(ipv6_buf, buf_len, "fe80::%02x%02x:%02xff:fe%02x:%02x%02x",
319 temp, mac_addr[1], mac_addr[2],
320 mac_addr[3], mac_addr[4], mac_addr[5]);
321}
322
323
Peng Xu8863ec72018-08-06 11:50:37 -0700324size_t convert_mac_addr_to_ipv6_linklocal(const u8 *mac_addr, u8 *ipv6)
325{
326 int i;
327
328 ipv6[0] = 0xfe;
329 ipv6[1] = 0x80;
330 for (i = 2; i < 8; i++)
331 ipv6[i] = 0;
332 ipv6[8] = mac_addr[0] ^ 0x02;
333 ipv6[9] = mac_addr[1];
334 ipv6[10] = mac_addr[2];
335 ipv6[11] = 0xff;
336 ipv6[12] = 0xfe;
337 ipv6[13] = mac_addr[3];
338 ipv6[14] = mac_addr[4];
339 ipv6[15] = mac_addr[5];
340
341 return 16;
342}
343
344
Peng Xu769731a2017-05-10 17:27:28 -0700345#ifndef ANDROID
346
347size_t strlcpy(char *dest, const char *src, size_t siz)
348{
349 const char *s = src;
350 size_t left = siz;
351
352 if (left) {
353 /* Copy string up to the maximum size of the dest buffer */
354 while (--left != 0) {
355 if ((*dest++ = *s++) == '\0')
356 break;
357 }
358 }
359
360 if (left == 0) {
361 /* Not enough room for the string; force NUL-termination */
362 if (siz != 0)
363 *dest = '\0';
364 while (*s++)
365 ; /* determine total src string length */
366 }
367
368 return s - src - 1;
369}
370
371
372size_t strlcat(char *dst, const char *str, size_t size)
373{
374 char *pos;
375 size_t dstlen, srclen, copy;
376
377 srclen = strlen(str);
P Praneeshbce09062021-07-13 18:57:16 +0530378 dstlen = strlen(dst);
379 pos = dst + dstlen;
380
381 if (dstlen >= size)
Peng Xu769731a2017-05-10 17:27:28 -0700382 return dstlen + srclen;
P Praneeshbce09062021-07-13 18:57:16 +0530383
384 if (dstlen + srclen >= size)
Peng Xu769731a2017-05-10 17:27:28 -0700385 copy = size - dstlen - 1;
386 else
387 copy = srclen;
P Praneeshbce09062021-07-13 18:57:16 +0530388
Peng Xu769731a2017-05-10 17:27:28 -0700389 memcpy(pos, str, copy);
390 pos[copy] = '\0';
391 return dstlen + srclen;
392}
393
394#endif /* ANDROID */
Ankita Bajaj1bde7942018-01-09 19:15:01 +0530395
396
397void hex_dump(struct sigma_dut *dut, u8 *data, size_t len)
398{
399 char buf[1024];
400 size_t index;
401 u8 *ptr;
402 int pos;
403
404 memset(buf, 0, sizeof(buf));
405 ptr = data;
406 pos = 0;
407 for (index = 0; index < len; index++) {
408 pos += snprintf(&(buf[pos]), sizeof(buf) - pos,
409 "%02x ", *ptr++);
410 if (pos > 1020)
411 break;
412 }
413 sigma_dut_print(dut, DUT_MSG_INFO, "HEXDUMP len=[%d]", (int) len);
414 sigma_dut_print(dut, DUT_MSG_INFO, "buf:%s", buf);
415}
Peng Xu291d97d2018-01-31 16:34:03 -0800416
417
418#ifdef NL80211_SUPPORT
419
420void * nl80211_cmd(struct sigma_dut *dut, struct nl80211_ctx *ctx,
421 struct nl_msg *msg, int flags, uint8_t cmd)
422{
Sai Pavan Akhil Remella6469f0c2021-12-20 15:49:53 +0530423 if (!ctx)
424 return NULL;
Peng Xu291d97d2018-01-31 16:34:03 -0800425 return genlmsg_put(msg, 0, 0, ctx->netlink_familyid,
426 0, flags, cmd, 0);
427}
428
429
430static struct nl_msg *
431nl80211_ifindex_msg(struct sigma_dut *dut, struct nl80211_ctx *ctx, int ifindex,
432 int flags, uint8_t cmd)
433{
434 struct nl_msg *msg;
435
436 msg = nlmsg_alloc();
437 if (!msg) {
438 sigma_dut_print(dut, DUT_MSG_ERROR,
439 "Failed to allocate NL message");
440 return NULL;
441 }
442
443 if (!nl80211_cmd(dut, ctx, msg, flags, cmd) ||
444 nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifindex)) {
445 nlmsg_free(msg);
446 return NULL;
447 }
448
449 return msg;
450}
451
452
453struct nl_msg * nl80211_drv_msg(struct sigma_dut *dut, struct nl80211_ctx *ctx,
454 int ifindex, int flags, uint8_t cmd)
455{
456 return nl80211_ifindex_msg(dut, ctx, ifindex, flags, cmd);
457}
458
459
Kiran Kumar Lokeref61a7432021-06-24 00:19:19 -0700460static int no_seq_check(struct nl_msg *msg, void *arg)
461{
462 return NL_OK;
463}
464
465
Peng Xu291d97d2018-01-31 16:34:03 -0800466static int ack_handler(struct nl_msg *msg, void *arg)
467{
468 int *err = arg;
469 *err = 0;
470 return NL_STOP;
471}
472
473
474static int finish_handler(struct nl_msg *msg, void *arg)
475{
476 int *ret = arg;
477 *ret = 0;
478 return NL_SKIP;
479}
480
481
482static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
483 void *arg)
484{
485 int *ret = arg;
486 *ret = err->error;
487 return NL_SKIP;
488}
489
490
491int send_and_recv_msgs(struct sigma_dut *dut, struct nl80211_ctx *ctx,
492 struct nl_msg *nlmsg,
493 int (*valid_handler)(struct nl_msg *, void *),
494 void *valid_data)
495{
496 struct nl_cb *cb;
497 int err = -ENOMEM;
498
499 if (!nlmsg)
500 return -ENOMEM;
501
502 cb = nl_cb_alloc(NL_CB_DEFAULT);
503 if (!cb)
504 goto out;
505
506 err = nl_send_auto_complete(ctx->sock, nlmsg);
507 if (err < 0) {
508 sigma_dut_print(dut, DUT_MSG_ERROR,
509 "nl80211: failed to send err=%d", err);
510 goto out;
511 }
512
513 err = 1;
514
515 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
516 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
517 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
518
519 if (valid_handler)
520 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
521 valid_handler, valid_data);
522
523 while (err > 0) {
524 int res = nl_recvmsgs(ctx->sock, cb);
525
526 if (res < 0) {
527 sigma_dut_print(dut, DUT_MSG_ERROR,
528 "nl80211: %s->nl_recvmsgs failed: res=%d, err=%d",
529 __func__, res, err);
530 }
531 }
532 out:
533 nl_cb_put(cb);
534 if (!valid_handler && valid_data == (void *) -1) {
535 if (nlmsg) {
536 struct nlmsghdr *hdr = nlmsg_hdr(nlmsg);
537 void *data = nlmsg_data(hdr);
538 int len = hdr->nlmsg_len - NLMSG_HDRLEN;
539
540 memset(data, 0, len);
541 }
542 }
543
544 nlmsg_free(nlmsg);
545 return err;
546}
547
548
Kiran Kumar Lokeref61a7432021-06-24 00:19:19 -0700549struct family_data {
550 struct sigma_dut *dut;
551 const char *group;
552 int id;
553};
554
555static int family_handler(struct nl_msg *msg, void *arg)
556{
557 struct family_data *res = arg;
558 struct nlattr *tb[CTRL_ATTR_MAX + 1];
559 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
560 struct nlattr *mcgrp;
561 int i;
562 struct sigma_dut *dut = res->dut;
563
564 nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
565 genlmsg_attrlen(gnlh, 0), NULL);
566
567 if (!tb[CTRL_ATTR_MCAST_GROUPS]) {
568 sigma_dut_print(dut, DUT_MSG_ERROR,
569 "mcast groups is not present");
570 return NL_SKIP;
571 }
572
573 nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {
574 struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1];
575
576 nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mcgrp),
577 nla_len(mcgrp), NULL);
578 if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] ||
579 !tb2[CTRL_ATTR_MCAST_GRP_ID] ||
580 strncmp(nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]),
581 res->group,
582 nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME])) != 0)
583 continue;
584 res->id = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]);
585 break;
586 };
587
588 return NL_SKIP;
589}
590
591
592static int nl_get_multicast_id(struct sigma_dut *dut, struct nl80211_ctx *ctx,
593 const char *family, const char *group)
594{
595 struct nl_msg *msg;
596 int ret;
597 struct family_data res = { dut, group, -ENOENT };
598
599 res.dut = dut;
600
601 msg = nlmsg_alloc();
602 if (!msg)
603 return -ENOMEM;
604 if (!genlmsg_put(msg, 0, 0, genl_ctrl_resolve(ctx->sock, "nlctrl"),
605 0, 0, CTRL_CMD_GETFAMILY, 0) ||
606 nla_put_string(msg, CTRL_ATTR_FAMILY_NAME, family)) {
607 nlmsg_free(msg);
608 return -1;
609 }
610
611 ret = send_and_recv_msgs(dut, ctx, msg, family_handler, &res);
612 if (ret == 0)
613 ret = res.id;
614 return ret;
615}
616
617
Peng Xu291d97d2018-01-31 16:34:03 -0800618struct nl80211_ctx * nl80211_init(struct sigma_dut *dut)
619{
620 struct nl80211_ctx *ctx;
621
622 ctx = calloc(1, sizeof(struct nl80211_ctx));
623 if (!ctx) {
624 sigma_dut_print(dut, DUT_MSG_ERROR,
625 "Failed to alloc nl80211_ctx");
626 return NULL;
627 }
628
629 ctx->sock = nl_socket_alloc();
630 if (!ctx->sock) {
631 sigma_dut_print(dut, DUT_MSG_ERROR,
632 "Failed to create NL socket, err: %s",
633 strerror(errno));
634 goto cleanup;
635 }
636
637 if (nl_connect(ctx->sock, NETLINK_GENERIC)) {
638 sigma_dut_print(dut, DUT_MSG_ERROR,
639 "Could not connect socket, err: %s",
640 strerror(errno));
641 goto cleanup;
642 }
643
644 if (nl_socket_set_buffer_size(ctx->sock, SOCK_BUF_SIZE, 0) < 0) {
645 sigma_dut_print(dut, DUT_MSG_INFO,
646 "Could not set nl_socket RX buffer size for sock: %s",
647 strerror(errno));
648 }
649
650 ctx->netlink_familyid = genl_ctrl_resolve(ctx->sock, "nl80211");
651 if (ctx->netlink_familyid < 0) {
652 sigma_dut_print(dut, DUT_MSG_ERROR,
653 "Could not resolve nl80211 family id");
654 goto cleanup;
655 }
656
657 ctx->nlctrl_familyid = genl_ctrl_resolve(ctx->sock, "nlctrl");
658 if (ctx->nlctrl_familyid < 0) {
659 sigma_dut_print(dut, DUT_MSG_ERROR,
660 "net link family nlctrl is not present: %d err:%s",
661 ctx->nlctrl_familyid, strerror(errno));
662 goto cleanup;
663 }
664
Kiran Kumar Lokere94829ce2022-01-20 10:49:08 -0800665 return ctx;
666
667cleanup:
668 if (ctx->sock)
669 nl_socket_free(ctx->sock);
670
671 free(ctx);
672 return NULL;
673}
674
675
676int nl80211_open_event_sock(struct sigma_dut *dut)
677{
678 struct nl_cb *cb = NULL;
679 int ret;
680 struct nl80211_ctx *ctx = dut->nl_ctx;
681
682 if (!ctx) {
683 sigma_dut_print(dut, DUT_MSG_ERROR, "nl80211 context is NULL");
684 return -1;
685 }
686
687 nl80211_close_event_sock(dut);
Kiran Kumar Lokeref61a7432021-06-24 00:19:19 -0700688 ctx->event_sock = nl_socket_alloc();
689 if (!ctx->event_sock) {
690 sigma_dut_print(dut, DUT_MSG_ERROR,
691 "Failed to create NL event socket, err: %s",
692 strerror(errno));
Kiran Kumar Lokere94829ce2022-01-20 10:49:08 -0800693 return -1;
Kiran Kumar Lokeref61a7432021-06-24 00:19:19 -0700694 }
695
696 if (nl_connect(ctx->event_sock, NETLINK_GENERIC)) {
697 sigma_dut_print(dut, DUT_MSG_ERROR,
698 "Could not connect event socket, err: %s",
699 strerror(errno));
Kiran Kumar Lokere94829ce2022-01-20 10:49:08 -0800700 return -1;
Kiran Kumar Lokeref61a7432021-06-24 00:19:19 -0700701 }
702
703 if (nl_socket_set_buffer_size(ctx->event_sock, SOCK_BUF_SIZE, 0) < 0) {
704 sigma_dut_print(dut, DUT_MSG_INFO,
705 "Fail to set nl_socket RX buff size for event sock: %s",
706 strerror(errno));
707 }
708
709 cb = nl_socket_get_cb(ctx->event_sock);
710 if (!cb) {
711 sigma_dut_print(dut, DUT_MSG_INFO,
712 "Failed to get NL control block for event socket port");
Kiran Kumar Lokere94829ce2022-01-20 10:49:08 -0800713 return -1;
Kiran Kumar Lokeref61a7432021-06-24 00:19:19 -0700714 }
715
716 ret = nl_get_multicast_id(dut, ctx, "nl80211", "vendor");
717 if (ret >= 0)
718 ret = nl_socket_add_membership(ctx->event_sock, ret);
719 if (ret < 0) {
720 sigma_dut_print(dut, DUT_MSG_INFO,
721 "nl80211: Could not add multicast "
722 "membership for vendor events: %d (%s)",
723 ret, nl_geterror(ret));
724 /* Continue without vendor events */
725 }
726 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &ret);
727 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &ret);
728 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &ret);
729 nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
730 nl_cb_put(cb);
731
Kiran Kumar Lokere94829ce2022-01-20 10:49:08 -0800732 return 0;
Peng Xu291d97d2018-01-31 16:34:03 -0800733}
734
735
736void nl80211_deinit(struct sigma_dut *dut, struct nl80211_ctx *ctx)
737{
Kiran Kumar Lokeref61a7432021-06-24 00:19:19 -0700738 if (!ctx) {
739 sigma_dut_print(dut, DUT_MSG_ERROR, "%s: ctx is NULL",
Peng Xu291d97d2018-01-31 16:34:03 -0800740 __func__);
741 return;
742 }
Kiran Kumar Lokeref61a7432021-06-24 00:19:19 -0700743 if (ctx->sock)
744 nl_socket_free(ctx->sock);
745 if (ctx->event_sock)
746 nl_socket_free(ctx->event_sock);
Peng Xu291d97d2018-01-31 16:34:03 -0800747 free(ctx);
748}
749
Veerendranath Jakkam050b85a2020-07-04 04:00:32 +0530750
Kiran Kumar Lokere94829ce2022-01-20 10:49:08 -0800751void nl80211_close_event_sock(struct sigma_dut *dut)
752{
753 struct nl80211_ctx *ctx = dut->nl_ctx;
754
755 if (ctx && ctx->event_sock) {
756 nl_socket_free(ctx->event_sock);
757 ctx->event_sock = NULL;
758 }
759}
760
761
Veerendranath Jakkam050b85a2020-07-04 04:00:32 +0530762static struct nl_msg *
763wcn_create_wifi_test_config_msg(struct sigma_dut *dut, const char *intf)
764{
765 int ifindex;
766 struct nl_msg *msg;
767
768 ifindex = if_nametoindex(intf);
769 if (ifindex == 0) {
770 sigma_dut_print(dut, DUT_MSG_ERROR,
771 "%s: Index for interface %s failed",
772 __func__, intf);
773 return NULL;
774 }
775
776 if (!(msg = nl80211_drv_msg(dut, dut->nl_ctx, ifindex, 0,
777 NL80211_CMD_VENDOR)) ||
778 nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifindex) ||
779 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
780 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
781 QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION)) {
782 nlmsg_free(msg);
783 return NULL;
784 }
785
786 return msg;
787}
788
789
790static int wcn_send_wifi_test_config_msg(struct sigma_dut *dut,
791 struct nl_msg *msg,
792 struct nlattr *params, int attr_id)
793{
794 int ret;
795
796 nla_nest_end(msg, params);
797
798 ret = send_and_recv_msgs(dut, dut->nl_ctx, msg, NULL, NULL);
799 if (ret) {
800 sigma_dut_print(dut, DUT_MSG_ERROR,
801 "%s: err in send_and_recv_msgs, ret=%d for %d",
802 __func__, ret, attr_id);
803 }
804
805 return ret;
806}
807
808
809int wcn_wifi_test_config_set_flag(struct sigma_dut *dut, const char *intf,
810 int attr_id)
811{
812 struct nl_msg *msg;
813 struct nlattr *params;
814
815 if (!(msg = wcn_create_wifi_test_config_msg(dut, intf)) ||
816 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
817 nla_put_flag(msg, attr_id)) {
818 sigma_dut_print(dut, DUT_MSG_ERROR,
819 "%s: err in adding test config data for %d",
820 __func__, attr_id);
821 nlmsg_free(msg);
822 return -1;
823 }
824
825 return wcn_send_wifi_test_config_msg(dut, msg, params, attr_id);
826}
827
828
829int wcn_wifi_test_config_set_u8(struct sigma_dut *dut, const char *intf,
830 int attr_id, uint8_t val)
831{
832 struct nl_msg *msg;
833 struct nlattr *params;
834
835 if (!(msg = wcn_create_wifi_test_config_msg(dut, intf)) ||
836 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
837 nla_put_u8(msg, attr_id, val)) {
838 sigma_dut_print(dut, DUT_MSG_ERROR,
839 "%s: err in adding test config data for %d",
840 __func__, attr_id);
841 nlmsg_free(msg);
842 return -1;
843 }
844
845 return wcn_send_wifi_test_config_msg(dut, msg, params, attr_id);
846}
847
848
849int wcn_wifi_test_config_set_u16(struct sigma_dut *dut, const char *intf,
850 int attr_id, uint16_t val)
851{
852 struct nl_msg *msg;
853 struct nlattr *params;
854
855 if (!(msg = wcn_create_wifi_test_config_msg(dut, intf)) ||
856 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
857 nla_put_u16(msg, attr_id, val)) {
858 sigma_dut_print(dut, DUT_MSG_ERROR,
859 "%s: err in adding test config data for %d",
860 __func__, attr_id);
861 nlmsg_free(msg);
862 return -1;
863 }
864
865 return wcn_send_wifi_test_config_msg(dut, msg, params, attr_id);
866}
867
Peng Xu291d97d2018-01-31 16:34:03 -0800868#endif /* NL80211_SUPPORT */
Alexei Avshalom Lazar64279692018-12-23 16:49:49 +0200869
870
Alexei Avshalom Lazar0dae51c2018-12-18 16:00:18 +0200871static int get_wps_pin_checksum(int pin)
872{
873 int a = 0;
874
875 while (pin > 0) {
876 a += 3 * (pin % 10);
877 pin = pin / 10;
878 a += (pin % 10);
879 pin = pin / 10;
880 }
881
882 return (10 - (a % 10)) % 10;
883}
884
885
886int get_wps_pin_from_mac(struct sigma_dut *dut, const char *macaddr,
887 char *pin, size_t len)
888{
889 unsigned char mac[ETH_ALEN];
890 int tmp, checksum;
891
892 if (len < 9)
893 return -1;
894 if (parse_mac_address(dut, macaddr, mac))
895 return -1;
896
897 /*
898 * get 7 digit PIN from the last 24 bits of MAC
899 * range 1000000 - 9999999
900 */
901 tmp = (mac[5] & 0xFF) | ((mac[4] & 0xFF) << 8) |
902 ((mac[3] & 0xFF) << 16);
903 tmp = (tmp % 9000000) + 1000000;
904 checksum = get_wps_pin_checksum(tmp);
905 snprintf(pin, len, "%07d%01d", tmp, checksum);
906 return 0;
907}
908
909
Alexei Avshalom Lazar744ae8a2019-01-31 17:26:46 +0200910int get_wps_forced_version(struct sigma_dut *dut, const char *str)
911{
912 int major, minor, result = 0;
913 int count = sscanf(str, "%d.%d", &major, &minor);
914
915 if (count == 2) {
916 result = major * 16 + minor;
917 sigma_dut_print(dut, DUT_MSG_DEBUG,
918 "Force WPS version to 0x%02x (%s)",
919 result, str);
920 } else {
921 sigma_dut_print(dut, DUT_MSG_ERROR,
922 "Invalid WPS version %s", str);
923 }
924
925 return result;
926}
927
928
Alexei Avshalom Lazar64279692018-12-23 16:49:49 +0200929void str_remove_chars(char *str, char ch)
930{
931 char *pr = str, *pw = str;
932
933 while (*pr) {
934 *pw = *pr++;
935 if (*pw != ch)
936 pw++;
937 }
938 *pw = '\0';
939}
Alexei Avshalom Lazara37dc162019-02-04 14:06:48 +0200940
941
942static const char base64_table[65] =
943 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
944
945
946int base64_encode(const char *src, size_t len, char *out, size_t out_len)
947{
948 unsigned char *pos;
949 const unsigned char *end, *in;
950 size_t olen;
951
952 olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */
953 olen++; /* nul termination */
954 if (olen < len || olen > out_len)
955 return -1;
956
957 end = (unsigned char *)(src + len);
958 in = (unsigned char *)src;
959 pos = (unsigned char *)out;
960 while (end - in >= 3) {
961 *pos++ = base64_table[(in[0] >> 2) & 0x3f];
962 *pos++ = base64_table[(((in[0] & 0x03) << 4) |
963 (in[1] >> 4)) & 0x3f];
964 *pos++ = base64_table[(((in[1] & 0x0f) << 2) |
965 (in[2] >> 6)) & 0x3f];
966 *pos++ = base64_table[in[2] & 0x3f];
967 in += 3;
968 }
969
970 if (end - in) {
971 *pos++ = base64_table[(in[0] >> 2) & 0x3f];
972 if (end - in == 1) {
973 *pos++ = base64_table[((in[0] & 0x03) << 4) & 0x3f];
974 *pos++ = '=';
975 } else {
976 *pos++ = base64_table[(((in[0] & 0x03) << 4) |
977 (in[1] >> 4)) & 0x3f];
978 *pos++ = base64_table[((in[1] & 0x0f) << 2) & 0x3f];
979 }
980 *pos++ = '=';
981 }
982
983 *pos = '\0';
984 return 0;
985}
986
987
988int random_get_bytes(char *buf, size_t len)
989{
990 FILE *f;
991 size_t rc;
992
993 f = fopen("/dev/urandom", "rb");
994 if (!f)
995 return -1;
996
997 rc = fread(buf, 1, len, f);
998 fclose(f);
999
1000 return rc != len ? -1 : 0;
1001}
Jouni Malinen3c740ab2019-10-10 15:55:11 +03001002
1003
1004int get_enable_disable(const char *val)
1005{
1006 if (strcasecmp(val, "enable") == 0 ||
1007 strcasecmp(val, "enabled") == 0 ||
1008 strcasecmp(val, "on") == 0 ||
1009 strcasecmp(val, "yes") == 0)
1010 return 1;
1011 return atoi(val);
1012}
Vinita Maloo54b78cf2020-03-30 12:18:19 +05301013
1014
1015int wcn_driver_cmd(const char *ifname, char *buf)
1016{
1017 int s, res;
1018 size_t buf_len;
1019 struct wcn_drv_priv_cmd priv_cmd;
1020 struct ifreq ifr;
1021
1022 s = socket(PF_INET, SOCK_DGRAM, 0);
1023 if (s < 0) {
1024 perror("socket");
1025 return -1;
1026 }
1027
1028 memset(&ifr, 0, sizeof(ifr));
1029 memset(&priv_cmd, 0, sizeof(priv_cmd));
1030 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1031 buf_len = strlen(buf);
1032 priv_cmd.buf = buf;
1033 priv_cmd.used_len = buf_len;
1034 priv_cmd.total_len = buf_len;
1035 ifr.ifr_data = (void *) &priv_cmd;
1036 res = ioctl(s, SIOCDEVPRIVATE + 1, &ifr);
1037 close(s);
1038 return res;
1039}
Veerendranath Jakkam176181c2020-05-16 00:19:21 +05301040
1041
1042int set_ipv6_addr(struct sigma_dut *dut, const char *ip, const char *mask,
1043 const char *ifname)
1044{
1045 char buf[200];
1046
1047 snprintf(buf, sizeof(buf), "ip -6 addr del %s/%s dev %s", ip, mask,
1048 ifname);
1049 sigma_dut_print(dut, DUT_MSG_DEBUG, "Run: %s", buf);
1050 if (system(buf) != 0) {
1051 /*
1052 * This command may fail if the address being deleted does not
1053 * exist. Inaction here is intentional.
1054 */
1055 }
1056
1057 snprintf(buf, sizeof(buf), "ip -6 addr add %s/%s dev %s", ip, mask,
1058 ifname);
1059 sigma_dut_print(dut, DUT_MSG_DEBUG, "Run: %s", buf);
1060 if (system(buf) != 0)
1061 return -1;
1062
1063 return 0;
1064}
Veerendranath Jakkam9ceb3b12021-09-10 03:18:17 +05301065
1066
1067int snprintf_error(size_t size, int res)
1068{
1069 return res < 0 || (unsigned int) res >= size;
1070}