blob: 9869453c34c543d816a8cf278e6dc8f16128a9ff [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
Jouni Malinen409fc122022-09-29 18:54:09 +0300183bool is_passpoint_r2_or_newer(enum sigma_program prog)
184{
185 return prog == PROGRAM_HS2_R2 ||
186 prog == PROGRAM_HS2_R3 ||
187 prog == PROGRAM_HS2_R4;
188}
189
190
191bool is_passpoint(enum sigma_program prog)
192{
193 return prog == PROGRAM_HS2 ||
194 is_passpoint_r2_or_newer(prog);
195}
196
197
priyadharshini gowthaman72462ef2016-06-22 22:47:14 -0700198static int parse_hex(char c)
199{
200 if (c >= '0' && c <= '9')
201 return c - '0';
202 if (c >= 'a' && c <= 'f')
203 return c - 'a' + 10;
204 if (c >= 'A' && c <= 'F')
205 return c - 'A' + 10;
206 return -1;
207}
208
209
Alexei Avshalom Lazar9a4f98d2019-05-02 13:35:22 +0300210int hex_byte(const char *str)
priyadharshini gowthaman72462ef2016-06-22 22:47:14 -0700211{
212 int res1, res2;
213
214 res1 = parse_hex(str[0]);
215 if (res1 < 0)
216 return -1;
217 res2 = parse_hex(str[1]);
218 if (res2 < 0)
219 return -1;
220 return (res1 << 4) | res2;
221}
222
223
Jouni Malinen08cf2312017-09-04 13:39:47 +0300224int parse_hexstr(const char *hex, unsigned char *buf, size_t buflen)
225{
226 size_t i;
227 const char *pos = hex;
228
229 for (i = 0; i < buflen; i++) {
230 int val;
231
232 if (*pos == '\0')
233 break;
234 val = hex_byte(pos);
235 if (val < 0)
236 return -1;
237 buf[i] = val;
238 pos += 2;
239 }
240
241 return i;
242}
243
244
priyadharshini gowthaman72462ef2016-06-22 22:47:14 -0700245int parse_mac_address(struct sigma_dut *dut, const char *arg,
246 unsigned char *addr)
247{
248 int i;
249 const char *pos = arg;
250
251 if (strlen(arg) != 17)
252 goto fail;
253
254 for (i = 0; i < ETH_ALEN; i++) {
255 int val;
256
257 val = hex_byte(pos);
258 if (val < 0)
259 goto fail;
260 addr[i] = val;
261 if (i + 1 < ETH_ALEN) {
262 pos += 2;
263 if (*pos != ':')
264 goto fail;
265 pos++;
266 }
267 }
268
269 return 0;
270
271fail:
272 sigma_dut_print(dut, DUT_MSG_ERROR,
273 "Invalid MAC address %s (expected format xx:xx:xx:xx:xx:xx)",
274 arg);
275 return -1;
276}
Rakesh Sunki7192dc42017-03-30 14:47:55 -0700277
278
Alexei Avshalom Lazar093569f2018-11-13 14:08:17 +0200279int is_60g_sigma_dut(struct sigma_dut *dut)
Rakesh Sunki7192dc42017-03-30 14:47:55 -0700280{
Alexei Avshalom Lazar093569f2018-11-13 14:08:17 +0200281 return dut->program == PROGRAM_60GHZ ||
282 (dut->program == PROGRAM_WPS &&
Jouni Malinen016ae6c2019-11-04 17:00:01 +0200283 (get_driver_type(dut) == DRIVER_WIL6210));
Alexei Avshalom Lazar093569f2018-11-13 14:08:17 +0200284}
285
286
287unsigned int channel_to_freq(struct sigma_dut *dut, unsigned int channel)
288{
289 if (is_60g_sigma_dut(dut)) {
290 if (channel >= 1 && channel <= 4)
291 return 58320 + 2160 * channel;
292
293 return 0;
294 }
295
Rakesh Sunki7192dc42017-03-30 14:47:55 -0700296 if (channel >= 1 && channel <= 13)
297 return 2407 + 5 * channel;
298 if (channel == 14)
299 return 2484;
300 if (channel >= 36 && channel <= 165)
301 return 5000 + 5 * channel;
302
303 return 0;
304}
305
306
307unsigned int freq_to_channel(unsigned int freq)
308{
309 if (freq >= 2412 && freq <= 2472)
310 return (freq - 2407) / 5;
311 if (freq == 2484)
312 return 14;
313 if (freq >= 5180 && freq <= 5825)
314 return (freq - 5000) / 5;
Alexei Avshalom Lazar093569f2018-11-13 14:08:17 +0200315 if (freq >= 58320 && freq <= 64800)
316 return (freq - 58320) / 2160;
Rakesh Sunki7192dc42017-03-30 14:47:55 -0700317 return 0;
318}
Peng Xu769731a2017-05-10 17:27:28 -0700319
320
Peng Xu525965b2018-06-26 16:40:14 -0700321int is_ipv6_addr(const char *str)
322{
323 struct sockaddr_in6 addr;
324
325 return inet_pton(AF_INET6, str, &(addr.sin6_addr));
326}
327
328
Rakesh Sunki8f8e74b2017-05-16 15:42:12 -0700329void convert_mac_addr_to_ipv6_lladdr(u8 *mac_addr, char *ipv6_buf,
330 size_t buf_len)
331{
332 u8 temp = mac_addr[0] ^ 0x02;
333
334 snprintf(ipv6_buf, buf_len, "fe80::%02x%02x:%02xff:fe%02x:%02x%02x",
335 temp, mac_addr[1], mac_addr[2],
336 mac_addr[3], mac_addr[4], mac_addr[5]);
337}
338
339
Peng Xu8863ec72018-08-06 11:50:37 -0700340size_t convert_mac_addr_to_ipv6_linklocal(const u8 *mac_addr, u8 *ipv6)
341{
342 int i;
343
344 ipv6[0] = 0xfe;
345 ipv6[1] = 0x80;
346 for (i = 2; i < 8; i++)
347 ipv6[i] = 0;
348 ipv6[8] = mac_addr[0] ^ 0x02;
349 ipv6[9] = mac_addr[1];
350 ipv6[10] = mac_addr[2];
351 ipv6[11] = 0xff;
352 ipv6[12] = 0xfe;
353 ipv6[13] = mac_addr[3];
354 ipv6[14] = mac_addr[4];
355 ipv6[15] = mac_addr[5];
356
357 return 16;
358}
359
360
Peng Xu769731a2017-05-10 17:27:28 -0700361#ifndef ANDROID
362
363size_t strlcpy(char *dest, const char *src, size_t siz)
364{
365 const char *s = src;
366 size_t left = siz;
367
368 if (left) {
369 /* Copy string up to the maximum size of the dest buffer */
370 while (--left != 0) {
371 if ((*dest++ = *s++) == '\0')
372 break;
373 }
374 }
375
376 if (left == 0) {
377 /* Not enough room for the string; force NUL-termination */
378 if (siz != 0)
379 *dest = '\0';
380 while (*s++)
381 ; /* determine total src string length */
382 }
383
384 return s - src - 1;
385}
386
387
388size_t strlcat(char *dst, const char *str, size_t size)
389{
390 char *pos;
391 size_t dstlen, srclen, copy;
392
393 srclen = strlen(str);
P Praneeshbce09062021-07-13 18:57:16 +0530394 dstlen = strlen(dst);
395 pos = dst + dstlen;
396
397 if (dstlen >= size)
Peng Xu769731a2017-05-10 17:27:28 -0700398 return dstlen + srclen;
P Praneeshbce09062021-07-13 18:57:16 +0530399
400 if (dstlen + srclen >= size)
Peng Xu769731a2017-05-10 17:27:28 -0700401 copy = size - dstlen - 1;
402 else
403 copy = srclen;
P Praneeshbce09062021-07-13 18:57:16 +0530404
Peng Xu769731a2017-05-10 17:27:28 -0700405 memcpy(pos, str, copy);
406 pos[copy] = '\0';
407 return dstlen + srclen;
408}
409
410#endif /* ANDROID */
Ankita Bajaj1bde7942018-01-09 19:15:01 +0530411
412
413void hex_dump(struct sigma_dut *dut, u8 *data, size_t len)
414{
415 char buf[1024];
416 size_t index;
417 u8 *ptr;
418 int pos;
419
420 memset(buf, 0, sizeof(buf));
421 ptr = data;
422 pos = 0;
423 for (index = 0; index < len; index++) {
424 pos += snprintf(&(buf[pos]), sizeof(buf) - pos,
425 "%02x ", *ptr++);
426 if (pos > 1020)
427 break;
428 }
429 sigma_dut_print(dut, DUT_MSG_INFO, "HEXDUMP len=[%d]", (int) len);
430 sigma_dut_print(dut, DUT_MSG_INFO, "buf:%s", buf);
431}
Peng Xu291d97d2018-01-31 16:34:03 -0800432
433
434#ifdef NL80211_SUPPORT
435
436void * nl80211_cmd(struct sigma_dut *dut, struct nl80211_ctx *ctx,
437 struct nl_msg *msg, int flags, uint8_t cmd)
438{
Sai Pavan Akhil Remella6469f0c2021-12-20 15:49:53 +0530439 if (!ctx)
440 return NULL;
Peng Xu291d97d2018-01-31 16:34:03 -0800441 return genlmsg_put(msg, 0, 0, ctx->netlink_familyid,
442 0, flags, cmd, 0);
443}
444
445
446static struct nl_msg *
447nl80211_ifindex_msg(struct sigma_dut *dut, struct nl80211_ctx *ctx, int ifindex,
448 int flags, uint8_t cmd)
449{
450 struct nl_msg *msg;
451
452 msg = nlmsg_alloc();
453 if (!msg) {
454 sigma_dut_print(dut, DUT_MSG_ERROR,
455 "Failed to allocate NL message");
456 return NULL;
457 }
458
459 if (!nl80211_cmd(dut, ctx, msg, flags, cmd) ||
460 nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifindex)) {
461 nlmsg_free(msg);
462 return NULL;
463 }
464
465 return msg;
466}
467
468
469struct nl_msg * nl80211_drv_msg(struct sigma_dut *dut, struct nl80211_ctx *ctx,
470 int ifindex, int flags, uint8_t cmd)
471{
472 return nl80211_ifindex_msg(dut, ctx, ifindex, flags, cmd);
473}
474
475
Kiran Kumar Lokeref61a7432021-06-24 00:19:19 -0700476static int no_seq_check(struct nl_msg *msg, void *arg)
477{
478 return NL_OK;
479}
480
481
Peng Xu291d97d2018-01-31 16:34:03 -0800482static int ack_handler(struct nl_msg *msg, void *arg)
483{
484 int *err = arg;
485 *err = 0;
486 return NL_STOP;
487}
488
489
490static int finish_handler(struct nl_msg *msg, void *arg)
491{
492 int *ret = arg;
493 *ret = 0;
494 return NL_SKIP;
495}
496
497
498static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
499 void *arg)
500{
501 int *ret = arg;
502 *ret = err->error;
503 return NL_SKIP;
504}
505
506
507int send_and_recv_msgs(struct sigma_dut *dut, struct nl80211_ctx *ctx,
508 struct nl_msg *nlmsg,
509 int (*valid_handler)(struct nl_msg *, void *),
510 void *valid_data)
511{
512 struct nl_cb *cb;
513 int err = -ENOMEM;
514
515 if (!nlmsg)
516 return -ENOMEM;
517
518 cb = nl_cb_alloc(NL_CB_DEFAULT);
519 if (!cb)
520 goto out;
521
522 err = nl_send_auto_complete(ctx->sock, nlmsg);
523 if (err < 0) {
524 sigma_dut_print(dut, DUT_MSG_ERROR,
525 "nl80211: failed to send err=%d", err);
526 goto out;
527 }
528
529 err = 1;
530
531 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
532 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
533 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
534
535 if (valid_handler)
536 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
537 valid_handler, valid_data);
538
539 while (err > 0) {
540 int res = nl_recvmsgs(ctx->sock, cb);
541
542 if (res < 0) {
543 sigma_dut_print(dut, DUT_MSG_ERROR,
544 "nl80211: %s->nl_recvmsgs failed: res=%d, err=%d",
545 __func__, res, err);
546 }
547 }
548 out:
549 nl_cb_put(cb);
550 if (!valid_handler && valid_data == (void *) -1) {
551 if (nlmsg) {
552 struct nlmsghdr *hdr = nlmsg_hdr(nlmsg);
553 void *data = nlmsg_data(hdr);
554 int len = hdr->nlmsg_len - NLMSG_HDRLEN;
555
556 memset(data, 0, len);
557 }
558 }
559
560 nlmsg_free(nlmsg);
561 return err;
562}
563
564
Kiran Kumar Lokeref61a7432021-06-24 00:19:19 -0700565struct family_data {
566 struct sigma_dut *dut;
567 const char *group;
568 int id;
569};
570
571static int family_handler(struct nl_msg *msg, void *arg)
572{
573 struct family_data *res = arg;
574 struct nlattr *tb[CTRL_ATTR_MAX + 1];
575 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
576 struct nlattr *mcgrp;
577 int i;
578 struct sigma_dut *dut = res->dut;
579
580 nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
581 genlmsg_attrlen(gnlh, 0), NULL);
582
583 if (!tb[CTRL_ATTR_MCAST_GROUPS]) {
584 sigma_dut_print(dut, DUT_MSG_ERROR,
585 "mcast groups is not present");
586 return NL_SKIP;
587 }
588
589 nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {
590 struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1];
591
592 nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mcgrp),
593 nla_len(mcgrp), NULL);
594 if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] ||
595 !tb2[CTRL_ATTR_MCAST_GRP_ID] ||
596 strncmp(nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]),
597 res->group,
598 nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME])) != 0)
599 continue;
600 res->id = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]);
601 break;
602 };
603
604 return NL_SKIP;
605}
606
607
608static int nl_get_multicast_id(struct sigma_dut *dut, struct nl80211_ctx *ctx,
609 const char *family, const char *group)
610{
611 struct nl_msg *msg;
612 int ret;
613 struct family_data res = { dut, group, -ENOENT };
614
615 res.dut = dut;
616
617 msg = nlmsg_alloc();
618 if (!msg)
619 return -ENOMEM;
620 if (!genlmsg_put(msg, 0, 0, genl_ctrl_resolve(ctx->sock, "nlctrl"),
621 0, 0, CTRL_CMD_GETFAMILY, 0) ||
622 nla_put_string(msg, CTRL_ATTR_FAMILY_NAME, family)) {
623 nlmsg_free(msg);
624 return -1;
625 }
626
627 ret = send_and_recv_msgs(dut, ctx, msg, family_handler, &res);
628 if (ret == 0)
629 ret = res.id;
630 return ret;
631}
632
633
Peng Xu291d97d2018-01-31 16:34:03 -0800634struct nl80211_ctx * nl80211_init(struct sigma_dut *dut)
635{
636 struct nl80211_ctx *ctx;
637
638 ctx = calloc(1, sizeof(struct nl80211_ctx));
639 if (!ctx) {
640 sigma_dut_print(dut, DUT_MSG_ERROR,
641 "Failed to alloc nl80211_ctx");
642 return NULL;
643 }
644
645 ctx->sock = nl_socket_alloc();
646 if (!ctx->sock) {
647 sigma_dut_print(dut, DUT_MSG_ERROR,
648 "Failed to create NL socket, err: %s",
649 strerror(errno));
650 goto cleanup;
651 }
652
653 if (nl_connect(ctx->sock, NETLINK_GENERIC)) {
654 sigma_dut_print(dut, DUT_MSG_ERROR,
655 "Could not connect socket, err: %s",
656 strerror(errno));
657 goto cleanup;
658 }
659
660 if (nl_socket_set_buffer_size(ctx->sock, SOCK_BUF_SIZE, 0) < 0) {
661 sigma_dut_print(dut, DUT_MSG_INFO,
662 "Could not set nl_socket RX buffer size for sock: %s",
663 strerror(errno));
664 }
665
666 ctx->netlink_familyid = genl_ctrl_resolve(ctx->sock, "nl80211");
667 if (ctx->netlink_familyid < 0) {
668 sigma_dut_print(dut, DUT_MSG_ERROR,
669 "Could not resolve nl80211 family id");
670 goto cleanup;
671 }
672
673 ctx->nlctrl_familyid = genl_ctrl_resolve(ctx->sock, "nlctrl");
674 if (ctx->nlctrl_familyid < 0) {
675 sigma_dut_print(dut, DUT_MSG_ERROR,
676 "net link family nlctrl is not present: %d err:%s",
677 ctx->nlctrl_familyid, strerror(errno));
678 goto cleanup;
679 }
680
Kiran Kumar Lokere94829ce2022-01-20 10:49:08 -0800681 return ctx;
682
683cleanup:
684 if (ctx->sock)
685 nl_socket_free(ctx->sock);
686
687 free(ctx);
688 return NULL;
689}
690
691
692int nl80211_open_event_sock(struct sigma_dut *dut)
693{
694 struct nl_cb *cb = NULL;
695 int ret;
696 struct nl80211_ctx *ctx = dut->nl_ctx;
697
698 if (!ctx) {
699 sigma_dut_print(dut, DUT_MSG_ERROR, "nl80211 context is NULL");
700 return -1;
701 }
702
703 nl80211_close_event_sock(dut);
Kiran Kumar Lokeref61a7432021-06-24 00:19:19 -0700704 ctx->event_sock = nl_socket_alloc();
705 if (!ctx->event_sock) {
706 sigma_dut_print(dut, DUT_MSG_ERROR,
707 "Failed to create NL event socket, err: %s",
708 strerror(errno));
Kiran Kumar Lokere94829ce2022-01-20 10:49:08 -0800709 return -1;
Kiran Kumar Lokeref61a7432021-06-24 00:19:19 -0700710 }
711
712 if (nl_connect(ctx->event_sock, NETLINK_GENERIC)) {
713 sigma_dut_print(dut, DUT_MSG_ERROR,
714 "Could not connect event socket, err: %s",
715 strerror(errno));
Kiran Kumar Lokere94829ce2022-01-20 10:49:08 -0800716 return -1;
Kiran Kumar Lokeref61a7432021-06-24 00:19:19 -0700717 }
718
719 if (nl_socket_set_buffer_size(ctx->event_sock, SOCK_BUF_SIZE, 0) < 0) {
720 sigma_dut_print(dut, DUT_MSG_INFO,
721 "Fail to set nl_socket RX buff size for event sock: %s",
722 strerror(errno));
723 }
724
725 cb = nl_socket_get_cb(ctx->event_sock);
726 if (!cb) {
727 sigma_dut_print(dut, DUT_MSG_INFO,
728 "Failed to get NL control block for event socket port");
Kiran Kumar Lokere94829ce2022-01-20 10:49:08 -0800729 return -1;
Kiran Kumar Lokeref61a7432021-06-24 00:19:19 -0700730 }
731
732 ret = nl_get_multicast_id(dut, ctx, "nl80211", "vendor");
733 if (ret >= 0)
734 ret = nl_socket_add_membership(ctx->event_sock, ret);
735 if (ret < 0) {
736 sigma_dut_print(dut, DUT_MSG_INFO,
737 "nl80211: Could not add multicast "
738 "membership for vendor events: %d (%s)",
739 ret, nl_geterror(ret));
740 /* Continue without vendor events */
741 }
742 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &ret);
743 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &ret);
744 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &ret);
745 nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
746 nl_cb_put(cb);
747
Kiran Kumar Lokere94829ce2022-01-20 10:49:08 -0800748 return 0;
Peng Xu291d97d2018-01-31 16:34:03 -0800749}
750
751
752void nl80211_deinit(struct sigma_dut *dut, struct nl80211_ctx *ctx)
753{
Kiran Kumar Lokeref61a7432021-06-24 00:19:19 -0700754 if (!ctx) {
755 sigma_dut_print(dut, DUT_MSG_ERROR, "%s: ctx is NULL",
Peng Xu291d97d2018-01-31 16:34:03 -0800756 __func__);
757 return;
758 }
Kiran Kumar Lokeref61a7432021-06-24 00:19:19 -0700759 if (ctx->sock)
760 nl_socket_free(ctx->sock);
761 if (ctx->event_sock)
762 nl_socket_free(ctx->event_sock);
Peng Xu291d97d2018-01-31 16:34:03 -0800763 free(ctx);
764}
765
Veerendranath Jakkam050b85a2020-07-04 04:00:32 +0530766
Kiran Kumar Lokere94829ce2022-01-20 10:49:08 -0800767void nl80211_close_event_sock(struct sigma_dut *dut)
768{
769 struct nl80211_ctx *ctx = dut->nl_ctx;
770
771 if (ctx && ctx->event_sock) {
772 nl_socket_free(ctx->event_sock);
773 ctx->event_sock = NULL;
774 }
775}
776
777
Veerendranath Jakkam050b85a2020-07-04 04:00:32 +0530778static struct nl_msg *
779wcn_create_wifi_test_config_msg(struct sigma_dut *dut, const char *intf)
780{
781 int ifindex;
782 struct nl_msg *msg;
783
784 ifindex = if_nametoindex(intf);
785 if (ifindex == 0) {
786 sigma_dut_print(dut, DUT_MSG_ERROR,
787 "%s: Index for interface %s failed",
788 __func__, intf);
789 return NULL;
790 }
791
792 if (!(msg = nl80211_drv_msg(dut, dut->nl_ctx, ifindex, 0,
793 NL80211_CMD_VENDOR)) ||
794 nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifindex) ||
795 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
796 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
797 QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION)) {
798 nlmsg_free(msg);
799 return NULL;
800 }
801
802 return msg;
803}
804
805
806static int wcn_send_wifi_test_config_msg(struct sigma_dut *dut,
807 struct nl_msg *msg,
808 struct nlattr *params, int attr_id)
809{
810 int ret;
811
812 nla_nest_end(msg, params);
813
814 ret = send_and_recv_msgs(dut, dut->nl_ctx, msg, NULL, NULL);
815 if (ret) {
816 sigma_dut_print(dut, DUT_MSG_ERROR,
817 "%s: err in send_and_recv_msgs, ret=%d for %d",
818 __func__, ret, attr_id);
819 }
820
821 return ret;
822}
823
824
825int wcn_wifi_test_config_set_flag(struct sigma_dut *dut, const char *intf,
826 int attr_id)
827{
828 struct nl_msg *msg;
829 struct nlattr *params;
830
831 if (!(msg = wcn_create_wifi_test_config_msg(dut, intf)) ||
832 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
833 nla_put_flag(msg, attr_id)) {
834 sigma_dut_print(dut, DUT_MSG_ERROR,
835 "%s: err in adding test config data for %d",
836 __func__, attr_id);
837 nlmsg_free(msg);
838 return -1;
839 }
840
841 return wcn_send_wifi_test_config_msg(dut, msg, params, attr_id);
842}
843
844
845int wcn_wifi_test_config_set_u8(struct sigma_dut *dut, const char *intf,
846 int attr_id, uint8_t val)
847{
848 struct nl_msg *msg;
849 struct nlattr *params;
850
851 if (!(msg = wcn_create_wifi_test_config_msg(dut, intf)) ||
852 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
853 nla_put_u8(msg, attr_id, val)) {
854 sigma_dut_print(dut, DUT_MSG_ERROR,
855 "%s: err in adding test config data for %d",
856 __func__, attr_id);
857 nlmsg_free(msg);
858 return -1;
859 }
860
861 return wcn_send_wifi_test_config_msg(dut, msg, params, attr_id);
862}
863
864
865int wcn_wifi_test_config_set_u16(struct sigma_dut *dut, const char *intf,
866 int attr_id, uint16_t val)
867{
868 struct nl_msg *msg;
869 struct nlattr *params;
870
871 if (!(msg = wcn_create_wifi_test_config_msg(dut, intf)) ||
872 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
873 nla_put_u16(msg, attr_id, val)) {
874 sigma_dut_print(dut, DUT_MSG_ERROR,
875 "%s: err in adding test config data for %d",
876 __func__, attr_id);
877 nlmsg_free(msg);
878 return -1;
879 }
880
881 return wcn_send_wifi_test_config_msg(dut, msg, params, attr_id);
882}
883
Peng Xu291d97d2018-01-31 16:34:03 -0800884#endif /* NL80211_SUPPORT */
Alexei Avshalom Lazar64279692018-12-23 16:49:49 +0200885
886
Alexei Avshalom Lazar0dae51c2018-12-18 16:00:18 +0200887static int get_wps_pin_checksum(int pin)
888{
889 int a = 0;
890
891 while (pin > 0) {
892 a += 3 * (pin % 10);
893 pin = pin / 10;
894 a += (pin % 10);
895 pin = pin / 10;
896 }
897
898 return (10 - (a % 10)) % 10;
899}
900
901
902int get_wps_pin_from_mac(struct sigma_dut *dut, const char *macaddr,
903 char *pin, size_t len)
904{
905 unsigned char mac[ETH_ALEN];
906 int tmp, checksum;
907
908 if (len < 9)
909 return -1;
910 if (parse_mac_address(dut, macaddr, mac))
911 return -1;
912
913 /*
914 * get 7 digit PIN from the last 24 bits of MAC
915 * range 1000000 - 9999999
916 */
917 tmp = (mac[5] & 0xFF) | ((mac[4] & 0xFF) << 8) |
918 ((mac[3] & 0xFF) << 16);
919 tmp = (tmp % 9000000) + 1000000;
920 checksum = get_wps_pin_checksum(tmp);
921 snprintf(pin, len, "%07d%01d", tmp, checksum);
922 return 0;
923}
924
925
Alexei Avshalom Lazar744ae8a2019-01-31 17:26:46 +0200926int get_wps_forced_version(struct sigma_dut *dut, const char *str)
927{
928 int major, minor, result = 0;
929 int count = sscanf(str, "%d.%d", &major, &minor);
930
931 if (count == 2) {
932 result = major * 16 + minor;
933 sigma_dut_print(dut, DUT_MSG_DEBUG,
934 "Force WPS version to 0x%02x (%s)",
935 result, str);
936 } else {
937 sigma_dut_print(dut, DUT_MSG_ERROR,
938 "Invalid WPS version %s", str);
939 }
940
941 return result;
942}
943
944
Alexei Avshalom Lazar64279692018-12-23 16:49:49 +0200945void str_remove_chars(char *str, char ch)
946{
947 char *pr = str, *pw = str;
948
949 while (*pr) {
950 *pw = *pr++;
951 if (*pw != ch)
952 pw++;
953 }
954 *pw = '\0';
955}
Alexei Avshalom Lazara37dc162019-02-04 14:06:48 +0200956
957
958static const char base64_table[65] =
959 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
960
961
962int base64_encode(const char *src, size_t len, char *out, size_t out_len)
963{
964 unsigned char *pos;
965 const unsigned char *end, *in;
966 size_t olen;
967
968 olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */
969 olen++; /* nul termination */
970 if (olen < len || olen > out_len)
971 return -1;
972
973 end = (unsigned char *)(src + len);
974 in = (unsigned char *)src;
975 pos = (unsigned char *)out;
976 while (end - in >= 3) {
977 *pos++ = base64_table[(in[0] >> 2) & 0x3f];
978 *pos++ = base64_table[(((in[0] & 0x03) << 4) |
979 (in[1] >> 4)) & 0x3f];
980 *pos++ = base64_table[(((in[1] & 0x0f) << 2) |
981 (in[2] >> 6)) & 0x3f];
982 *pos++ = base64_table[in[2] & 0x3f];
983 in += 3;
984 }
985
986 if (end - in) {
987 *pos++ = base64_table[(in[0] >> 2) & 0x3f];
988 if (end - in == 1) {
989 *pos++ = base64_table[((in[0] & 0x03) << 4) & 0x3f];
990 *pos++ = '=';
991 } else {
992 *pos++ = base64_table[(((in[0] & 0x03) << 4) |
993 (in[1] >> 4)) & 0x3f];
994 *pos++ = base64_table[((in[1] & 0x0f) << 2) & 0x3f];
995 }
996 *pos++ = '=';
997 }
998
999 *pos = '\0';
1000 return 0;
1001}
1002
1003
Jouni Malinen3d6d1622022-04-14 12:47:54 +03001004unsigned char * base64_decode(const char *src, size_t len, size_t *out_len)
1005{
1006 unsigned char dtable[256], *out, *pos, block[4], tmp;
1007 size_t i, count, olen;
1008 int pad = 0;
1009 size_t extra_pad;
1010
1011 memset(dtable, 0x80, 256);
1012 for (i = 0; i < sizeof(base64_table) - 1; i++)
1013 dtable[(unsigned char) base64_table[i]] = (unsigned char) i;
1014 dtable['='] = 0;
1015
1016 count = 0;
1017 for (i = 0; i < len; i++) {
1018 if (dtable[(unsigned char) src[i]] != 0x80)
1019 count++;
1020 }
1021
1022 if (count == 0)
1023 return NULL;
1024 extra_pad = (4 - count % 4) % 4;
1025
1026 olen = (count + extra_pad) / 4 * 3;
1027 pos = out = malloc(olen);
1028 if (!out)
1029 return NULL;
1030
1031 count = 0;
1032 for (i = 0; i < len + extra_pad; i++) {
1033 unsigned char val;
1034
1035 if (i >= len)
1036 val = '=';
1037 else
1038 val = src[i];
1039 tmp = dtable[val];
1040 if (tmp == 0x80)
1041 continue;
1042
1043 if (val == '=')
1044 pad++;
1045 block[count] = tmp;
1046 count++;
1047 if (count == 4) {
1048 *pos++ = (block[0] << 2) | (block[1] >> 4);
1049 *pos++ = (block[1] << 4) | (block[2] >> 2);
1050 *pos++ = (block[2] << 6) | block[3];
1051 count = 0;
1052 if (pad) {
1053 if (pad == 1)
1054 pos--;
1055 else if (pad == 2)
1056 pos -= 2;
1057 else {
1058 /* Invalid padding */
1059 free(out);
1060 return NULL;
1061 }
1062 break;
1063 }
1064 }
1065 }
1066
1067 *out_len = pos - out;
1068 return out;
1069}
1070
1071
Alexei Avshalom Lazara37dc162019-02-04 14:06:48 +02001072int random_get_bytes(char *buf, size_t len)
1073{
1074 FILE *f;
1075 size_t rc;
1076
1077 f = fopen("/dev/urandom", "rb");
1078 if (!f)
1079 return -1;
1080
1081 rc = fread(buf, 1, len, f);
1082 fclose(f);
1083
1084 return rc != len ? -1 : 0;
1085}
Jouni Malinen3c740ab2019-10-10 15:55:11 +03001086
1087
1088int get_enable_disable(const char *val)
1089{
1090 if (strcasecmp(val, "enable") == 0 ||
1091 strcasecmp(val, "enabled") == 0 ||
1092 strcasecmp(val, "on") == 0 ||
1093 strcasecmp(val, "yes") == 0)
1094 return 1;
1095 return atoi(val);
1096}
Vinita Maloo54b78cf2020-03-30 12:18:19 +05301097
1098
1099int wcn_driver_cmd(const char *ifname, char *buf)
1100{
1101 int s, res;
1102 size_t buf_len;
1103 struct wcn_drv_priv_cmd priv_cmd;
1104 struct ifreq ifr;
1105
1106 s = socket(PF_INET, SOCK_DGRAM, 0);
1107 if (s < 0) {
1108 perror("socket");
1109 return -1;
1110 }
1111
1112 memset(&ifr, 0, sizeof(ifr));
1113 memset(&priv_cmd, 0, sizeof(priv_cmd));
1114 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1115 buf_len = strlen(buf);
1116 priv_cmd.buf = buf;
1117 priv_cmd.used_len = buf_len;
1118 priv_cmd.total_len = buf_len;
1119 ifr.ifr_data = (void *) &priv_cmd;
1120 res = ioctl(s, SIOCDEVPRIVATE + 1, &ifr);
1121 close(s);
1122 return res;
1123}
Veerendranath Jakkam176181c2020-05-16 00:19:21 +05301124
1125
1126int set_ipv6_addr(struct sigma_dut *dut, const char *ip, const char *mask,
1127 const char *ifname)
1128{
1129 char buf[200];
1130
1131 snprintf(buf, sizeof(buf), "ip -6 addr del %s/%s dev %s", ip, mask,
1132 ifname);
1133 sigma_dut_print(dut, DUT_MSG_DEBUG, "Run: %s", buf);
1134 if (system(buf) != 0) {
1135 /*
1136 * This command may fail if the address being deleted does not
1137 * exist. Inaction here is intentional.
1138 */
1139 }
1140
1141 snprintf(buf, sizeof(buf), "ip -6 addr add %s/%s dev %s", ip, mask,
1142 ifname);
1143 sigma_dut_print(dut, DUT_MSG_DEBUG, "Run: %s", buf);
1144 if (system(buf) != 0)
1145 return -1;
1146
1147 return 0;
1148}
Veerendranath Jakkam9ceb3b12021-09-10 03:18:17 +05301149
1150
1151int snprintf_error(size_t size, int res)
1152{
1153 return res < 0 || (unsigned int) res >= size;
1154}
Shivani Baranwal31182012021-12-07 21:11:13 +05301155
1156
1157void kill_pid(struct sigma_dut *dut, const char *pid_file)
1158{
1159 int pid;
1160 FILE *f;
1161
1162 f = fopen(pid_file, "r");
1163 if (!f)
1164 return; /* process is not running */
1165
1166 if (fscanf(f, "%d", &pid) != 1 || pid <= 0) {
1167 sigma_dut_print(dut, DUT_MSG_ERROR,
1168 "No PID for process in %s", pid_file);
1169 fclose(f);
1170 unlink(pid_file);
1171 return;
1172 }
1173 fclose(f);
1174
1175 sigma_dut_print(dut, DUT_MSG_DEBUG, "Process PID found in %s: %d",
1176 pid_file, pid);
1177 if (kill(pid, SIGINT) < 0 && errno != ESRCH)
1178 sigma_dut_print(dut, DUT_MSG_DEBUG, "kill failed: %s",
1179 strerror(errno));
1180
1181 unlink(pid_file);
1182 sleep(1);
1183}