blob: 201dad5900ecd5751ee158676fc9bb86d2ded1f0 [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>
Shivani Baranwal31182012021-12-07 21:11:13 +053013#include <signal.h>
Jouni Malinencd4e3c32015-10-29 12:39:56 +020014#include "wpa_helpers.h"
15
16enum driver_type wifi_chip_type = DRIVER_NOT_SET;
17enum openwrt_driver_type openwrt_chip_type = OPENWRT_DRIVER_NOT_SET;
18
Vinita Maloo54b78cf2020-03-30 12:18:19 +053019struct wcn_drv_priv_cmd {
20 char *buf;
21 int used_len;
22 int total_len;
23};
Jouni Malinencd4e3c32015-10-29 12:39:56 +020024
25int file_exists(const char *fname)
26{
27 struct stat s;
28 return stat(fname, &s) == 0;
29}
30
31
32int set_wifi_chip(const char *chip_type)
33{
34 if (!strncmp(chip_type, "WCN", strlen("WCN")))
35 wifi_chip_type = DRIVER_WCN;
36 else if (!strncmp(chip_type, "ATHEROS", strlen("ATHEROS")))
37 wifi_chip_type = DRIVER_ATHEROS;
38 else if (!strncmp(chip_type, "AR6003", strlen("AR6003")))
39 wifi_chip_type = DRIVER_AR6003;
40 else if (strcmp(chip_type, "MAC80211") == 0)
41 wifi_chip_type = DRIVER_MAC80211;
42 else if (strcmp(chip_type, "QNXNTO") == 0)
43 wifi_chip_type = DRIVER_QNXNTO;
44 else if (strcmp(chip_type, "OPENWRT") == 0)
45 wifi_chip_type = DRIVER_OPENWRT;
Sreelakshmi Konamkib692f102016-04-26 19:47:00 +053046 else if (!strncmp(chip_type, "LINUX-WCN", strlen("LINUX-WCN")))
47 wifi_chip_type = DRIVER_LINUX_WCN;
Jouni Malinencd4e3c32015-10-29 12:39:56 +020048 else
49 return -1;
50
51 return 0;
52}
53
54
Jouni Malinen016ae6c2019-11-04 17:00:01 +020055enum driver_type get_driver_type(struct sigma_dut *dut)
Jouni Malinencd4e3c32015-10-29 12:39:56 +020056{
57 struct stat s;
58 if (wifi_chip_type == DRIVER_NOT_SET) {
59 /* Check for 60G driver */
60 ssize_t len;
61 char link[256];
62 char buf[256];
Jouni Malinen016ae6c2019-11-04 17:00:01 +020063 const char *ifname = get_station_ifname(dut);
Jouni Malinencd4e3c32015-10-29 12:39:56 +020064
65 snprintf(buf, sizeof(buf), "/sys/class/net/%s/device/driver",
66 ifname);
67 len = readlink(buf, link, sizeof(link) - 1);
68 if (len >= 0) {
69 link[len] = '\0';
70 if (strstr(link, DRIVER_NAME_60G))
71 return DRIVER_WIL6210;
72 }
73
74 if (stat("/sys/module/mac80211", &s) == 0)
75 return DRIVER_MAC80211;
76 return DRIVER_ATHEROS;
77 }
78 return wifi_chip_type;
79}
80
81
Venkateswara Naralasettyf0f88052020-11-11 19:15:17 +053082void sigma_dut_get_device_driver_name(const char *ifname, char *name,
83 size_t size)
84{
85 char fname[128], path[128];
86 struct stat s;
87 ssize_t res;
88 char *pos;
89
90 name[0] = '\0';
91
92 snprintf(path, sizeof(path), "/sys/class/net/%s/phy80211", ifname);
93 if (stat(path, &s) != 0)
94 return;
95
96 res = snprintf(fname, sizeof(fname),
97 "/sys/class/net/%s/device/driver", ifname);
98 if (res < 0 || res >= sizeof(fname))
99 return;
100 res = readlink(fname, path, sizeof(path));
101 if (res < 0)
102 return;
103
104 if (res >= (int) sizeof(path))
105 res = sizeof(path) - 1;
106 path[res] = '\0';
107 pos = strrchr(path, '/');
108 if (!pos)
109 pos = path;
110 else
111 pos++;
112 snprintf(name, size, "%s", pos);
113}
114
115
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200116enum openwrt_driver_type get_openwrt_driver_type(void)
117{
118 struct stat s;
119
120 if (openwrt_chip_type == OPENWRT_DRIVER_NOT_SET) {
priyadharshini gowthaman00bbdf12018-01-29 12:42:00 -0800121 if (stat("/sys/module/umac", &s) == 0 ||
122 stat("/sys/module/atd", &s) == 0)
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200123 openwrt_chip_type = OPENWRT_DRIVER_ATHEROS;
124 }
125
126 return openwrt_chip_type;
127}
128
129
130enum sigma_program sigma_program_to_enum(const char *prog)
131{
132 if (prog == NULL)
133 return PROGRAM_UNKNOWN;
134
135 if (strcasecmp(prog, "TDLS") == 0)
136 return PROGRAM_TDLS;
137 if (strcasecmp(prog, "HS2") == 0)
138 return PROGRAM_HS2;
139 if (strcasecmp(prog, "HS2_R2") == 0 ||
Jouni Malinenba630452018-06-22 11:49:59 +0300140 strcasecmp(prog, "HS2-R2") == 0)
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200141 return PROGRAM_HS2_R2;
Jouni Malinenba630452018-06-22 11:49:59 +0300142 if (strcasecmp(prog, "HS2-R3") == 0)
143 return PROGRAM_HS2_R3;
Jouni Malinen9a742ff2022-01-27 00:43:14 +0200144 if (strcasecmp(prog, "HS2-R4") == 0)
145 return PROGRAM_HS2_R4;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200146 if (strcasecmp(prog, "WFD") == 0)
147 return PROGRAM_WFD;
Amarnath Hullur Subramanyam659a34c2017-03-17 00:04:41 -0700148 if (strcasecmp(prog, "DisplayR2") == 0)
149 return PROGRAM_DISPLAYR2;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200150 if (strcasecmp(prog, "PMF") == 0)
151 return PROGRAM_PMF;
152 if (strcasecmp(prog, "WPS") == 0)
153 return PROGRAM_WPS;
154 if (strcasecmp(prog, "11n") == 0)
155 return PROGRAM_HT;
156 if (strcasecmp(prog, "VHT") == 0)
157 return PROGRAM_VHT;
158 if (strcasecmp(prog, "60GHZ") == 0)
159 return PROGRAM_60GHZ;
160 if (strcasecmp(prog, "NAN") == 0)
161 return PROGRAM_NAN;
priyadharshini gowthaman12dd4142016-06-22 22:47:14 -0700162 if (strcasecmp(prog, "LOC") == 0)
163 return PROGRAM_LOC;
priyadharshini gowthamanb4e05fc2016-10-13 15:02:35 -0700164 if (strcasecmp(prog, "MBO") == 0)
165 return PROGRAM_MBO;
Adil Saeed Musthafa33ea2872017-04-10 23:13:24 -0700166 if (strcasecmp(prog, "IoTLP") == 0)
167 return PROGRAM_IOTLP;
Jouni Malinen5c3813a2017-08-26 13:30:39 +0300168 if (strcasecmp(prog, "DPP") == 0)
169 return PROGRAM_DPP;
Ankita Bajaja2cb5672017-10-25 16:08:28 +0530170 if (strcasecmp(prog, "OCE") == 0)
171 return PROGRAM_OCE;
priyadharshini gowthaman0e209fc2018-01-26 15:15:37 -0800172 if (strcasecmp(prog, "WPA3") == 0)
173 return PROGRAM_WPA3;
Amarnath Hullur Subramanyam8f9c8682018-01-30 19:01:51 -0800174 if (strcasecmp(prog, "HE") == 0)
175 return PROGRAM_HE;
Vamsi Krishnaf642d6a2020-03-27 12:33:14 +0530176 if (strcasecmp(prog, "QM") == 0)
177 return PROGRAM_QM;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200178
179 return PROGRAM_UNKNOWN;
180}
priyadharshini gowthaman72462ef2016-06-22 22:47:14 -0700181
182
183static int parse_hex(char c)
184{
185 if (c >= '0' && c <= '9')
186 return c - '0';
187 if (c >= 'a' && c <= 'f')
188 return c - 'a' + 10;
189 if (c >= 'A' && c <= 'F')
190 return c - 'A' + 10;
191 return -1;
192}
193
194
Alexei Avshalom Lazar9a4f98d2019-05-02 13:35:22 +0300195int hex_byte(const char *str)
priyadharshini gowthaman72462ef2016-06-22 22:47:14 -0700196{
197 int res1, res2;
198
199 res1 = parse_hex(str[0]);
200 if (res1 < 0)
201 return -1;
202 res2 = parse_hex(str[1]);
203 if (res2 < 0)
204 return -1;
205 return (res1 << 4) | res2;
206}
207
208
Jouni Malinen08cf2312017-09-04 13:39:47 +0300209int parse_hexstr(const char *hex, unsigned char *buf, size_t buflen)
210{
211 size_t i;
212 const char *pos = hex;
213
214 for (i = 0; i < buflen; i++) {
215 int val;
216
217 if (*pos == '\0')
218 break;
219 val = hex_byte(pos);
220 if (val < 0)
221 return -1;
222 buf[i] = val;
223 pos += 2;
224 }
225
226 return i;
227}
228
229
priyadharshini gowthaman72462ef2016-06-22 22:47:14 -0700230int parse_mac_address(struct sigma_dut *dut, const char *arg,
231 unsigned char *addr)
232{
233 int i;
234 const char *pos = arg;
235
236 if (strlen(arg) != 17)
237 goto fail;
238
239 for (i = 0; i < ETH_ALEN; i++) {
240 int val;
241
242 val = hex_byte(pos);
243 if (val < 0)
244 goto fail;
245 addr[i] = val;
246 if (i + 1 < ETH_ALEN) {
247 pos += 2;
248 if (*pos != ':')
249 goto fail;
250 pos++;
251 }
252 }
253
254 return 0;
255
256fail:
257 sigma_dut_print(dut, DUT_MSG_ERROR,
258 "Invalid MAC address %s (expected format xx:xx:xx:xx:xx:xx)",
259 arg);
260 return -1;
261}
Rakesh Sunki7192dc42017-03-30 14:47:55 -0700262
263
Alexei Avshalom Lazar093569f2018-11-13 14:08:17 +0200264int is_60g_sigma_dut(struct sigma_dut *dut)
Rakesh Sunki7192dc42017-03-30 14:47:55 -0700265{
Alexei Avshalom Lazar093569f2018-11-13 14:08:17 +0200266 return dut->program == PROGRAM_60GHZ ||
267 (dut->program == PROGRAM_WPS &&
Jouni Malinen016ae6c2019-11-04 17:00:01 +0200268 (get_driver_type(dut) == DRIVER_WIL6210));
Alexei Avshalom Lazar093569f2018-11-13 14:08:17 +0200269}
270
271
272unsigned int channel_to_freq(struct sigma_dut *dut, unsigned int channel)
273{
274 if (is_60g_sigma_dut(dut)) {
275 if (channel >= 1 && channel <= 4)
276 return 58320 + 2160 * channel;
277
278 return 0;
279 }
280
Rakesh Sunki7192dc42017-03-30 14:47:55 -0700281 if (channel >= 1 && channel <= 13)
282 return 2407 + 5 * channel;
283 if (channel == 14)
284 return 2484;
285 if (channel >= 36 && channel <= 165)
286 return 5000 + 5 * channel;
287
288 return 0;
289}
290
291
292unsigned int freq_to_channel(unsigned int freq)
293{
294 if (freq >= 2412 && freq <= 2472)
295 return (freq - 2407) / 5;
296 if (freq == 2484)
297 return 14;
298 if (freq >= 5180 && freq <= 5825)
299 return (freq - 5000) / 5;
Alexei Avshalom Lazar093569f2018-11-13 14:08:17 +0200300 if (freq >= 58320 && freq <= 64800)
301 return (freq - 58320) / 2160;
Rakesh Sunki7192dc42017-03-30 14:47:55 -0700302 return 0;
303}
Peng Xu769731a2017-05-10 17:27:28 -0700304
305
Peng Xu525965b2018-06-26 16:40:14 -0700306int is_ipv6_addr(const char *str)
307{
308 struct sockaddr_in6 addr;
309
310 return inet_pton(AF_INET6, str, &(addr.sin6_addr));
311}
312
313
Rakesh Sunki8f8e74b2017-05-16 15:42:12 -0700314void convert_mac_addr_to_ipv6_lladdr(u8 *mac_addr, char *ipv6_buf,
315 size_t buf_len)
316{
317 u8 temp = mac_addr[0] ^ 0x02;
318
319 snprintf(ipv6_buf, buf_len, "fe80::%02x%02x:%02xff:fe%02x:%02x%02x",
320 temp, mac_addr[1], mac_addr[2],
321 mac_addr[3], mac_addr[4], mac_addr[5]);
322}
323
324
Peng Xu8863ec72018-08-06 11:50:37 -0700325size_t convert_mac_addr_to_ipv6_linklocal(const u8 *mac_addr, u8 *ipv6)
326{
327 int i;
328
329 ipv6[0] = 0xfe;
330 ipv6[1] = 0x80;
331 for (i = 2; i < 8; i++)
332 ipv6[i] = 0;
333 ipv6[8] = mac_addr[0] ^ 0x02;
334 ipv6[9] = mac_addr[1];
335 ipv6[10] = mac_addr[2];
336 ipv6[11] = 0xff;
337 ipv6[12] = 0xfe;
338 ipv6[13] = mac_addr[3];
339 ipv6[14] = mac_addr[4];
340 ipv6[15] = mac_addr[5];
341
342 return 16;
343}
344
345
Peng Xu769731a2017-05-10 17:27:28 -0700346#ifndef ANDROID
347
348size_t strlcpy(char *dest, const char *src, size_t siz)
349{
350 const char *s = src;
351 size_t left = siz;
352
353 if (left) {
354 /* Copy string up to the maximum size of the dest buffer */
355 while (--left != 0) {
356 if ((*dest++ = *s++) == '\0')
357 break;
358 }
359 }
360
361 if (left == 0) {
362 /* Not enough room for the string; force NUL-termination */
363 if (siz != 0)
364 *dest = '\0';
365 while (*s++)
366 ; /* determine total src string length */
367 }
368
369 return s - src - 1;
370}
371
372
373size_t strlcat(char *dst, const char *str, size_t size)
374{
375 char *pos;
376 size_t dstlen, srclen, copy;
377
378 srclen = strlen(str);
P Praneeshbce09062021-07-13 18:57:16 +0530379 dstlen = strlen(dst);
380 pos = dst + dstlen;
381
382 if (dstlen >= size)
Peng Xu769731a2017-05-10 17:27:28 -0700383 return dstlen + srclen;
P Praneeshbce09062021-07-13 18:57:16 +0530384
385 if (dstlen + srclen >= size)
Peng Xu769731a2017-05-10 17:27:28 -0700386 copy = size - dstlen - 1;
387 else
388 copy = srclen;
P Praneeshbce09062021-07-13 18:57:16 +0530389
Peng Xu769731a2017-05-10 17:27:28 -0700390 memcpy(pos, str, copy);
391 pos[copy] = '\0';
392 return dstlen + srclen;
393}
394
395#endif /* ANDROID */
Ankita Bajaj1bde7942018-01-09 19:15:01 +0530396
397
398void hex_dump(struct sigma_dut *dut, u8 *data, size_t len)
399{
400 char buf[1024];
401 size_t index;
402 u8 *ptr;
403 int pos;
404
405 memset(buf, 0, sizeof(buf));
406 ptr = data;
407 pos = 0;
408 for (index = 0; index < len; index++) {
409 pos += snprintf(&(buf[pos]), sizeof(buf) - pos,
410 "%02x ", *ptr++);
411 if (pos > 1020)
412 break;
413 }
414 sigma_dut_print(dut, DUT_MSG_INFO, "HEXDUMP len=[%d]", (int) len);
415 sigma_dut_print(dut, DUT_MSG_INFO, "buf:%s", buf);
416}
Peng Xu291d97d2018-01-31 16:34:03 -0800417
418
419#ifdef NL80211_SUPPORT
420
421void * nl80211_cmd(struct sigma_dut *dut, struct nl80211_ctx *ctx,
422 struct nl_msg *msg, int flags, uint8_t cmd)
423{
Sai Pavan Akhil Remella6469f0c2021-12-20 15:49:53 +0530424 if (!ctx)
425 return NULL;
Peng Xu291d97d2018-01-31 16:34:03 -0800426 return genlmsg_put(msg, 0, 0, ctx->netlink_familyid,
427 0, flags, cmd, 0);
428}
429
430
431static struct nl_msg *
432nl80211_ifindex_msg(struct sigma_dut *dut, struct nl80211_ctx *ctx, int ifindex,
433 int flags, uint8_t cmd)
434{
435 struct nl_msg *msg;
436
437 msg = nlmsg_alloc();
438 if (!msg) {
439 sigma_dut_print(dut, DUT_MSG_ERROR,
440 "Failed to allocate NL message");
441 return NULL;
442 }
443
444 if (!nl80211_cmd(dut, ctx, msg, flags, cmd) ||
445 nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifindex)) {
446 nlmsg_free(msg);
447 return NULL;
448 }
449
450 return msg;
451}
452
453
454struct nl_msg * nl80211_drv_msg(struct sigma_dut *dut, struct nl80211_ctx *ctx,
455 int ifindex, int flags, uint8_t cmd)
456{
457 return nl80211_ifindex_msg(dut, ctx, ifindex, flags, cmd);
458}
459
460
Kiran Kumar Lokeref61a7432021-06-24 00:19:19 -0700461static int no_seq_check(struct nl_msg *msg, void *arg)
462{
463 return NL_OK;
464}
465
466
Peng Xu291d97d2018-01-31 16:34:03 -0800467static int ack_handler(struct nl_msg *msg, void *arg)
468{
469 int *err = arg;
470 *err = 0;
471 return NL_STOP;
472}
473
474
475static int finish_handler(struct nl_msg *msg, void *arg)
476{
477 int *ret = arg;
478 *ret = 0;
479 return NL_SKIP;
480}
481
482
483static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
484 void *arg)
485{
486 int *ret = arg;
487 *ret = err->error;
488 return NL_SKIP;
489}
490
491
492int send_and_recv_msgs(struct sigma_dut *dut, struct nl80211_ctx *ctx,
493 struct nl_msg *nlmsg,
494 int (*valid_handler)(struct nl_msg *, void *),
495 void *valid_data)
496{
497 struct nl_cb *cb;
498 int err = -ENOMEM;
499
500 if (!nlmsg)
501 return -ENOMEM;
502
503 cb = nl_cb_alloc(NL_CB_DEFAULT);
504 if (!cb)
505 goto out;
506
507 err = nl_send_auto_complete(ctx->sock, nlmsg);
508 if (err < 0) {
509 sigma_dut_print(dut, DUT_MSG_ERROR,
510 "nl80211: failed to send err=%d", err);
511 goto out;
512 }
513
514 err = 1;
515
516 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
517 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
518 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
519
520 if (valid_handler)
521 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
522 valid_handler, valid_data);
523
524 while (err > 0) {
525 int res = nl_recvmsgs(ctx->sock, cb);
526
527 if (res < 0) {
528 sigma_dut_print(dut, DUT_MSG_ERROR,
529 "nl80211: %s->nl_recvmsgs failed: res=%d, err=%d",
530 __func__, res, err);
531 }
532 }
533 out:
534 nl_cb_put(cb);
535 if (!valid_handler && valid_data == (void *) -1) {
536 if (nlmsg) {
537 struct nlmsghdr *hdr = nlmsg_hdr(nlmsg);
538 void *data = nlmsg_data(hdr);
539 int len = hdr->nlmsg_len - NLMSG_HDRLEN;
540
541 memset(data, 0, len);
542 }
543 }
544
545 nlmsg_free(nlmsg);
546 return err;
547}
548
549
Kiran Kumar Lokeref61a7432021-06-24 00:19:19 -0700550struct family_data {
551 struct sigma_dut *dut;
552 const char *group;
553 int id;
554};
555
556static int family_handler(struct nl_msg *msg, void *arg)
557{
558 struct family_data *res = arg;
559 struct nlattr *tb[CTRL_ATTR_MAX + 1];
560 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
561 struct nlattr *mcgrp;
562 int i;
563 struct sigma_dut *dut = res->dut;
564
565 nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
566 genlmsg_attrlen(gnlh, 0), NULL);
567
568 if (!tb[CTRL_ATTR_MCAST_GROUPS]) {
569 sigma_dut_print(dut, DUT_MSG_ERROR,
570 "mcast groups is not present");
571 return NL_SKIP;
572 }
573
574 nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {
575 struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1];
576
577 nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mcgrp),
578 nla_len(mcgrp), NULL);
579 if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] ||
580 !tb2[CTRL_ATTR_MCAST_GRP_ID] ||
581 strncmp(nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]),
582 res->group,
583 nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME])) != 0)
584 continue;
585 res->id = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]);
586 break;
587 };
588
589 return NL_SKIP;
590}
591
592
593static int nl_get_multicast_id(struct sigma_dut *dut, struct nl80211_ctx *ctx,
594 const char *family, const char *group)
595{
596 struct nl_msg *msg;
597 int ret;
598 struct family_data res = { dut, group, -ENOENT };
599
600 res.dut = dut;
601
602 msg = nlmsg_alloc();
603 if (!msg)
604 return -ENOMEM;
605 if (!genlmsg_put(msg, 0, 0, genl_ctrl_resolve(ctx->sock, "nlctrl"),
606 0, 0, CTRL_CMD_GETFAMILY, 0) ||
607 nla_put_string(msg, CTRL_ATTR_FAMILY_NAME, family)) {
608 nlmsg_free(msg);
609 return -1;
610 }
611
612 ret = send_and_recv_msgs(dut, ctx, msg, family_handler, &res);
613 if (ret == 0)
614 ret = res.id;
615 return ret;
616}
617
618
Peng Xu291d97d2018-01-31 16:34:03 -0800619struct nl80211_ctx * nl80211_init(struct sigma_dut *dut)
620{
621 struct nl80211_ctx *ctx;
622
623 ctx = calloc(1, sizeof(struct nl80211_ctx));
624 if (!ctx) {
625 sigma_dut_print(dut, DUT_MSG_ERROR,
626 "Failed to alloc nl80211_ctx");
627 return NULL;
628 }
629
630 ctx->sock = nl_socket_alloc();
631 if (!ctx->sock) {
632 sigma_dut_print(dut, DUT_MSG_ERROR,
633 "Failed to create NL socket, err: %s",
634 strerror(errno));
635 goto cleanup;
636 }
637
638 if (nl_connect(ctx->sock, NETLINK_GENERIC)) {
639 sigma_dut_print(dut, DUT_MSG_ERROR,
640 "Could not connect socket, err: %s",
641 strerror(errno));
642 goto cleanup;
643 }
644
645 if (nl_socket_set_buffer_size(ctx->sock, SOCK_BUF_SIZE, 0) < 0) {
646 sigma_dut_print(dut, DUT_MSG_INFO,
647 "Could not set nl_socket RX buffer size for sock: %s",
648 strerror(errno));
649 }
650
651 ctx->netlink_familyid = genl_ctrl_resolve(ctx->sock, "nl80211");
652 if (ctx->netlink_familyid < 0) {
653 sigma_dut_print(dut, DUT_MSG_ERROR,
654 "Could not resolve nl80211 family id");
655 goto cleanup;
656 }
657
658 ctx->nlctrl_familyid = genl_ctrl_resolve(ctx->sock, "nlctrl");
659 if (ctx->nlctrl_familyid < 0) {
660 sigma_dut_print(dut, DUT_MSG_ERROR,
661 "net link family nlctrl is not present: %d err:%s",
662 ctx->nlctrl_familyid, strerror(errno));
663 goto cleanup;
664 }
665
Kiran Kumar Lokere94829ce2022-01-20 10:49:08 -0800666 return ctx;
667
668cleanup:
669 if (ctx->sock)
670 nl_socket_free(ctx->sock);
671
672 free(ctx);
673 return NULL;
674}
675
676
677int nl80211_open_event_sock(struct sigma_dut *dut)
678{
679 struct nl_cb *cb = NULL;
680 int ret;
681 struct nl80211_ctx *ctx = dut->nl_ctx;
682
683 if (!ctx) {
684 sigma_dut_print(dut, DUT_MSG_ERROR, "nl80211 context is NULL");
685 return -1;
686 }
687
688 nl80211_close_event_sock(dut);
Kiran Kumar Lokeref61a7432021-06-24 00:19:19 -0700689 ctx->event_sock = nl_socket_alloc();
690 if (!ctx->event_sock) {
691 sigma_dut_print(dut, DUT_MSG_ERROR,
692 "Failed to create NL event socket, err: %s",
693 strerror(errno));
Kiran Kumar Lokere94829ce2022-01-20 10:49:08 -0800694 return -1;
Kiran Kumar Lokeref61a7432021-06-24 00:19:19 -0700695 }
696
697 if (nl_connect(ctx->event_sock, NETLINK_GENERIC)) {
698 sigma_dut_print(dut, DUT_MSG_ERROR,
699 "Could not connect event socket, err: %s",
700 strerror(errno));
Kiran Kumar Lokere94829ce2022-01-20 10:49:08 -0800701 return -1;
Kiran Kumar Lokeref61a7432021-06-24 00:19:19 -0700702 }
703
704 if (nl_socket_set_buffer_size(ctx->event_sock, SOCK_BUF_SIZE, 0) < 0) {
705 sigma_dut_print(dut, DUT_MSG_INFO,
706 "Fail to set nl_socket RX buff size for event sock: %s",
707 strerror(errno));
708 }
709
710 cb = nl_socket_get_cb(ctx->event_sock);
711 if (!cb) {
712 sigma_dut_print(dut, DUT_MSG_INFO,
713 "Failed to get NL control block for event socket port");
Kiran Kumar Lokere94829ce2022-01-20 10:49:08 -0800714 return -1;
Kiran Kumar Lokeref61a7432021-06-24 00:19:19 -0700715 }
716
717 ret = nl_get_multicast_id(dut, ctx, "nl80211", "vendor");
718 if (ret >= 0)
719 ret = nl_socket_add_membership(ctx->event_sock, ret);
720 if (ret < 0) {
721 sigma_dut_print(dut, DUT_MSG_INFO,
722 "nl80211: Could not add multicast "
723 "membership for vendor events: %d (%s)",
724 ret, nl_geterror(ret));
725 /* Continue without vendor events */
726 }
727 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &ret);
728 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &ret);
729 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &ret);
730 nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
731 nl_cb_put(cb);
732
Kiran Kumar Lokere94829ce2022-01-20 10:49:08 -0800733 return 0;
Peng Xu291d97d2018-01-31 16:34:03 -0800734}
735
736
737void nl80211_deinit(struct sigma_dut *dut, struct nl80211_ctx *ctx)
738{
Kiran Kumar Lokeref61a7432021-06-24 00:19:19 -0700739 if (!ctx) {
740 sigma_dut_print(dut, DUT_MSG_ERROR, "%s: ctx is NULL",
Peng Xu291d97d2018-01-31 16:34:03 -0800741 __func__);
742 return;
743 }
Kiran Kumar Lokeref61a7432021-06-24 00:19:19 -0700744 if (ctx->sock)
745 nl_socket_free(ctx->sock);
746 if (ctx->event_sock)
747 nl_socket_free(ctx->event_sock);
Peng Xu291d97d2018-01-31 16:34:03 -0800748 free(ctx);
749}
750
Veerendranath Jakkam050b85a2020-07-04 04:00:32 +0530751
Kiran Kumar Lokere94829ce2022-01-20 10:49:08 -0800752void nl80211_close_event_sock(struct sigma_dut *dut)
753{
754 struct nl80211_ctx *ctx = dut->nl_ctx;
755
756 if (ctx && ctx->event_sock) {
757 nl_socket_free(ctx->event_sock);
758 ctx->event_sock = NULL;
759 }
760}
761
762
Veerendranath Jakkam050b85a2020-07-04 04:00:32 +0530763static struct nl_msg *
764wcn_create_wifi_test_config_msg(struct sigma_dut *dut, const char *intf)
765{
766 int ifindex;
767 struct nl_msg *msg;
768
769 ifindex = if_nametoindex(intf);
770 if (ifindex == 0) {
771 sigma_dut_print(dut, DUT_MSG_ERROR,
772 "%s: Index for interface %s failed",
773 __func__, intf);
774 return NULL;
775 }
776
777 if (!(msg = nl80211_drv_msg(dut, dut->nl_ctx, ifindex, 0,
778 NL80211_CMD_VENDOR)) ||
779 nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifindex) ||
780 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
781 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
782 QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION)) {
783 nlmsg_free(msg);
784 return NULL;
785 }
786
787 return msg;
788}
789
790
791static int wcn_send_wifi_test_config_msg(struct sigma_dut *dut,
792 struct nl_msg *msg,
793 struct nlattr *params, int attr_id)
794{
795 int ret;
796
797 nla_nest_end(msg, params);
798
799 ret = send_and_recv_msgs(dut, dut->nl_ctx, msg, NULL, NULL);
800 if (ret) {
801 sigma_dut_print(dut, DUT_MSG_ERROR,
802 "%s: err in send_and_recv_msgs, ret=%d for %d",
803 __func__, ret, attr_id);
804 }
805
806 return ret;
807}
808
809
810int wcn_wifi_test_config_set_flag(struct sigma_dut *dut, const char *intf,
811 int attr_id)
812{
813 struct nl_msg *msg;
814 struct nlattr *params;
815
816 if (!(msg = wcn_create_wifi_test_config_msg(dut, intf)) ||
817 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
818 nla_put_flag(msg, attr_id)) {
819 sigma_dut_print(dut, DUT_MSG_ERROR,
820 "%s: err in adding test config data for %d",
821 __func__, attr_id);
822 nlmsg_free(msg);
823 return -1;
824 }
825
826 return wcn_send_wifi_test_config_msg(dut, msg, params, attr_id);
827}
828
829
830int wcn_wifi_test_config_set_u8(struct sigma_dut *dut, const char *intf,
831 int attr_id, uint8_t val)
832{
833 struct nl_msg *msg;
834 struct nlattr *params;
835
836 if (!(msg = wcn_create_wifi_test_config_msg(dut, intf)) ||
837 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
838 nla_put_u8(msg, attr_id, val)) {
839 sigma_dut_print(dut, DUT_MSG_ERROR,
840 "%s: err in adding test config data for %d",
841 __func__, attr_id);
842 nlmsg_free(msg);
843 return -1;
844 }
845
846 return wcn_send_wifi_test_config_msg(dut, msg, params, attr_id);
847}
848
849
850int wcn_wifi_test_config_set_u16(struct sigma_dut *dut, const char *intf,
851 int attr_id, uint16_t val)
852{
853 struct nl_msg *msg;
854 struct nlattr *params;
855
856 if (!(msg = wcn_create_wifi_test_config_msg(dut, intf)) ||
857 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
858 nla_put_u16(msg, attr_id, val)) {
859 sigma_dut_print(dut, DUT_MSG_ERROR,
860 "%s: err in adding test config data for %d",
861 __func__, attr_id);
862 nlmsg_free(msg);
863 return -1;
864 }
865
866 return wcn_send_wifi_test_config_msg(dut, msg, params, attr_id);
867}
868
Peng Xu291d97d2018-01-31 16:34:03 -0800869#endif /* NL80211_SUPPORT */
Alexei Avshalom Lazar64279692018-12-23 16:49:49 +0200870
871
Alexei Avshalom Lazar0dae51c2018-12-18 16:00:18 +0200872static int get_wps_pin_checksum(int pin)
873{
874 int a = 0;
875
876 while (pin > 0) {
877 a += 3 * (pin % 10);
878 pin = pin / 10;
879 a += (pin % 10);
880 pin = pin / 10;
881 }
882
883 return (10 - (a % 10)) % 10;
884}
885
886
887int get_wps_pin_from_mac(struct sigma_dut *dut, const char *macaddr,
888 char *pin, size_t len)
889{
890 unsigned char mac[ETH_ALEN];
891 int tmp, checksum;
892
893 if (len < 9)
894 return -1;
895 if (parse_mac_address(dut, macaddr, mac))
896 return -1;
897
898 /*
899 * get 7 digit PIN from the last 24 bits of MAC
900 * range 1000000 - 9999999
901 */
902 tmp = (mac[5] & 0xFF) | ((mac[4] & 0xFF) << 8) |
903 ((mac[3] & 0xFF) << 16);
904 tmp = (tmp % 9000000) + 1000000;
905 checksum = get_wps_pin_checksum(tmp);
906 snprintf(pin, len, "%07d%01d", tmp, checksum);
907 return 0;
908}
909
910
Alexei Avshalom Lazar744ae8a2019-01-31 17:26:46 +0200911int get_wps_forced_version(struct sigma_dut *dut, const char *str)
912{
913 int major, minor, result = 0;
914 int count = sscanf(str, "%d.%d", &major, &minor);
915
916 if (count == 2) {
917 result = major * 16 + minor;
918 sigma_dut_print(dut, DUT_MSG_DEBUG,
919 "Force WPS version to 0x%02x (%s)",
920 result, str);
921 } else {
922 sigma_dut_print(dut, DUT_MSG_ERROR,
923 "Invalid WPS version %s", str);
924 }
925
926 return result;
927}
928
929
Alexei Avshalom Lazar64279692018-12-23 16:49:49 +0200930void str_remove_chars(char *str, char ch)
931{
932 char *pr = str, *pw = str;
933
934 while (*pr) {
935 *pw = *pr++;
936 if (*pw != ch)
937 pw++;
938 }
939 *pw = '\0';
940}
Alexei Avshalom Lazara37dc162019-02-04 14:06:48 +0200941
942
943static const char base64_table[65] =
944 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
945
946
947int base64_encode(const char *src, size_t len, char *out, size_t out_len)
948{
949 unsigned char *pos;
950 const unsigned char *end, *in;
951 size_t olen;
952
953 olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */
954 olen++; /* nul termination */
955 if (olen < len || olen > out_len)
956 return -1;
957
958 end = (unsigned char *)(src + len);
959 in = (unsigned char *)src;
960 pos = (unsigned char *)out;
961 while (end - in >= 3) {
962 *pos++ = base64_table[(in[0] >> 2) & 0x3f];
963 *pos++ = base64_table[(((in[0] & 0x03) << 4) |
964 (in[1] >> 4)) & 0x3f];
965 *pos++ = base64_table[(((in[1] & 0x0f) << 2) |
966 (in[2] >> 6)) & 0x3f];
967 *pos++ = base64_table[in[2] & 0x3f];
968 in += 3;
969 }
970
971 if (end - in) {
972 *pos++ = base64_table[(in[0] >> 2) & 0x3f];
973 if (end - in == 1) {
974 *pos++ = base64_table[((in[0] & 0x03) << 4) & 0x3f];
975 *pos++ = '=';
976 } else {
977 *pos++ = base64_table[(((in[0] & 0x03) << 4) |
978 (in[1] >> 4)) & 0x3f];
979 *pos++ = base64_table[((in[1] & 0x0f) << 2) & 0x3f];
980 }
981 *pos++ = '=';
982 }
983
984 *pos = '\0';
985 return 0;
986}
987
988
989int random_get_bytes(char *buf, size_t len)
990{
991 FILE *f;
992 size_t rc;
993
994 f = fopen("/dev/urandom", "rb");
995 if (!f)
996 return -1;
997
998 rc = fread(buf, 1, len, f);
999 fclose(f);
1000
1001 return rc != len ? -1 : 0;
1002}
Jouni Malinen3c740ab2019-10-10 15:55:11 +03001003
1004
1005int get_enable_disable(const char *val)
1006{
1007 if (strcasecmp(val, "enable") == 0 ||
1008 strcasecmp(val, "enabled") == 0 ||
1009 strcasecmp(val, "on") == 0 ||
1010 strcasecmp(val, "yes") == 0)
1011 return 1;
1012 return atoi(val);
1013}
Vinita Maloo54b78cf2020-03-30 12:18:19 +05301014
1015
1016int wcn_driver_cmd(const char *ifname, char *buf)
1017{
1018 int s, res;
1019 size_t buf_len;
1020 struct wcn_drv_priv_cmd priv_cmd;
1021 struct ifreq ifr;
1022
1023 s = socket(PF_INET, SOCK_DGRAM, 0);
1024 if (s < 0) {
1025 perror("socket");
1026 return -1;
1027 }
1028
1029 memset(&ifr, 0, sizeof(ifr));
1030 memset(&priv_cmd, 0, sizeof(priv_cmd));
1031 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1032 buf_len = strlen(buf);
1033 priv_cmd.buf = buf;
1034 priv_cmd.used_len = buf_len;
1035 priv_cmd.total_len = buf_len;
1036 ifr.ifr_data = (void *) &priv_cmd;
1037 res = ioctl(s, SIOCDEVPRIVATE + 1, &ifr);
1038 close(s);
1039 return res;
1040}
Veerendranath Jakkam176181c2020-05-16 00:19:21 +05301041
1042
1043int set_ipv6_addr(struct sigma_dut *dut, const char *ip, const char *mask,
1044 const char *ifname)
1045{
1046 char buf[200];
1047
1048 snprintf(buf, sizeof(buf), "ip -6 addr del %s/%s dev %s", ip, mask,
1049 ifname);
1050 sigma_dut_print(dut, DUT_MSG_DEBUG, "Run: %s", buf);
1051 if (system(buf) != 0) {
1052 /*
1053 * This command may fail if the address being deleted does not
1054 * exist. Inaction here is intentional.
1055 */
1056 }
1057
1058 snprintf(buf, sizeof(buf), "ip -6 addr add %s/%s dev %s", ip, mask,
1059 ifname);
1060 sigma_dut_print(dut, DUT_MSG_DEBUG, "Run: %s", buf);
1061 if (system(buf) != 0)
1062 return -1;
1063
1064 return 0;
1065}
Veerendranath Jakkam9ceb3b12021-09-10 03:18:17 +05301066
1067
1068int snprintf_error(size_t size, int res)
1069{
1070 return res < 0 || (unsigned int) res >= size;
1071}
Shivani Baranwal31182012021-12-07 21:11:13 +05301072
1073
1074void kill_pid(struct sigma_dut *dut, const char *pid_file)
1075{
1076 int pid;
1077 FILE *f;
1078
1079 f = fopen(pid_file, "r");
1080 if (!f)
1081 return; /* process is not running */
1082
1083 if (fscanf(f, "%d", &pid) != 1 || pid <= 0) {
1084 sigma_dut_print(dut, DUT_MSG_ERROR,
1085 "No PID for process in %s", pid_file);
1086 fclose(f);
1087 unlink(pid_file);
1088 return;
1089 }
1090 fclose(f);
1091
1092 sigma_dut_print(dut, DUT_MSG_DEBUG, "Process PID found in %s: %d",
1093 pid_file, pid);
1094 if (kill(pid, SIGINT) < 0 && errno != ESRCH)
1095 sigma_dut_print(dut, DUT_MSG_DEBUG, "kill failed: %s",
1096 strerror(errno));
1097
1098 unlink(pid_file);
1099 sleep(1);
1100}