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