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