blob: b9443e2c7b52d2bce79ff2d6b5ee904c9f73ab6a [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 ||
98 strcasecmp(prog, "HS2-R2") == 0)
99 return PROGRAM_HS2_R2;
100 if (strcasecmp(prog, "WFD") == 0)
101 return PROGRAM_WFD;
Amarnath Hullur Subramanyam659a34c2017-03-17 00:04:41 -0700102 if (strcasecmp(prog, "DisplayR2") == 0)
103 return PROGRAM_DISPLAYR2;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200104 if (strcasecmp(prog, "PMF") == 0)
105 return PROGRAM_PMF;
106 if (strcasecmp(prog, "WPS") == 0)
107 return PROGRAM_WPS;
108 if (strcasecmp(prog, "11n") == 0)
109 return PROGRAM_HT;
110 if (strcasecmp(prog, "VHT") == 0)
111 return PROGRAM_VHT;
112 if (strcasecmp(prog, "60GHZ") == 0)
113 return PROGRAM_60GHZ;
114 if (strcasecmp(prog, "NAN") == 0)
115 return PROGRAM_NAN;
priyadharshini gowthaman12dd4142016-06-22 22:47:14 -0700116 if (strcasecmp(prog, "LOC") == 0)
117 return PROGRAM_LOC;
priyadharshini gowthamanb4e05fc2016-10-13 15:02:35 -0700118 if (strcasecmp(prog, "MBO") == 0)
119 return PROGRAM_MBO;
Adil Saeed Musthafa33ea2872017-04-10 23:13:24 -0700120 if (strcasecmp(prog, "IoTLP") == 0)
121 return PROGRAM_IOTLP;
Jouni Malinen5c3813a2017-08-26 13:30:39 +0300122 if (strcasecmp(prog, "DPP") == 0)
123 return PROGRAM_DPP;
Ankita Bajaja2cb5672017-10-25 16:08:28 +0530124 if (strcasecmp(prog, "OCE") == 0)
125 return PROGRAM_OCE;
priyadharshini gowthaman0e209fc2018-01-26 15:15:37 -0800126 if (strcasecmp(prog, "WPA3") == 0)
127 return PROGRAM_WPA3;
Amarnath Hullur Subramanyam8f9c8682018-01-30 19:01:51 -0800128 if (strcasecmp(prog, "HE") == 0)
129 return PROGRAM_HE;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200130
131 return PROGRAM_UNKNOWN;
132}
priyadharshini gowthaman72462ef2016-06-22 22:47:14 -0700133
134
135static int parse_hex(char c)
136{
137 if (c >= '0' && c <= '9')
138 return c - '0';
139 if (c >= 'a' && c <= 'f')
140 return c - 'a' + 10;
141 if (c >= 'A' && c <= 'F')
142 return c - 'A' + 10;
143 return -1;
144}
145
146
147static int hex_byte(const char *str)
148{
149 int res1, res2;
150
151 res1 = parse_hex(str[0]);
152 if (res1 < 0)
153 return -1;
154 res2 = parse_hex(str[1]);
155 if (res2 < 0)
156 return -1;
157 return (res1 << 4) | res2;
158}
159
160
Jouni Malinen08cf2312017-09-04 13:39:47 +0300161int parse_hexstr(const char *hex, unsigned char *buf, size_t buflen)
162{
163 size_t i;
164 const char *pos = hex;
165
166 for (i = 0; i < buflen; i++) {
167 int val;
168
169 if (*pos == '\0')
170 break;
171 val = hex_byte(pos);
172 if (val < 0)
173 return -1;
174 buf[i] = val;
175 pos += 2;
176 }
177
178 return i;
179}
180
181
priyadharshini gowthaman72462ef2016-06-22 22:47:14 -0700182int parse_mac_address(struct sigma_dut *dut, const char *arg,
183 unsigned char *addr)
184{
185 int i;
186 const char *pos = arg;
187
188 if (strlen(arg) != 17)
189 goto fail;
190
191 for (i = 0; i < ETH_ALEN; i++) {
192 int val;
193
194 val = hex_byte(pos);
195 if (val < 0)
196 goto fail;
197 addr[i] = val;
198 if (i + 1 < ETH_ALEN) {
199 pos += 2;
200 if (*pos != ':')
201 goto fail;
202 pos++;
203 }
204 }
205
206 return 0;
207
208fail:
209 sigma_dut_print(dut, DUT_MSG_ERROR,
210 "Invalid MAC address %s (expected format xx:xx:xx:xx:xx:xx)",
211 arg);
212 return -1;
213}
Rakesh Sunki7192dc42017-03-30 14:47:55 -0700214
215
216unsigned int channel_to_freq(unsigned int channel)
217{
218 if (channel >= 1 && channel <= 13)
219 return 2407 + 5 * channel;
220 if (channel == 14)
221 return 2484;
222 if (channel >= 36 && channel <= 165)
223 return 5000 + 5 * channel;
224
225 return 0;
226}
227
228
229unsigned int freq_to_channel(unsigned int freq)
230{
231 if (freq >= 2412 && freq <= 2472)
232 return (freq - 2407) / 5;
233 if (freq == 2484)
234 return 14;
235 if (freq >= 5180 && freq <= 5825)
236 return (freq - 5000) / 5;
237 return 0;
238}
Peng Xu769731a2017-05-10 17:27:28 -0700239
240
Rakesh Sunki8f8e74b2017-05-16 15:42:12 -0700241void convert_mac_addr_to_ipv6_lladdr(u8 *mac_addr, char *ipv6_buf,
242 size_t buf_len)
243{
244 u8 temp = mac_addr[0] ^ 0x02;
245
246 snprintf(ipv6_buf, buf_len, "fe80::%02x%02x:%02xff:fe%02x:%02x%02x",
247 temp, mac_addr[1], mac_addr[2],
248 mac_addr[3], mac_addr[4], mac_addr[5]);
249}
250
251
Peng Xu769731a2017-05-10 17:27:28 -0700252#ifndef ANDROID
253
254size_t strlcpy(char *dest, const char *src, size_t siz)
255{
256 const char *s = src;
257 size_t left = siz;
258
259 if (left) {
260 /* Copy string up to the maximum size of the dest buffer */
261 while (--left != 0) {
262 if ((*dest++ = *s++) == '\0')
263 break;
264 }
265 }
266
267 if (left == 0) {
268 /* Not enough room for the string; force NUL-termination */
269 if (siz != 0)
270 *dest = '\0';
271 while (*s++)
272 ; /* determine total src string length */
273 }
274
275 return s - src - 1;
276}
277
278
279size_t strlcat(char *dst, const char *str, size_t size)
280{
281 char *pos;
282 size_t dstlen, srclen, copy;
283
284 srclen = strlen(str);
285 for (pos = dst; pos - dst < size && *dst; pos++)
286 ;
287 dstlen = pos - dst;
288 if (*dst)
289 return dstlen + srclen;
290 if (dstlen + srclen + 1 > size)
291 copy = size - dstlen - 1;
292 else
293 copy = srclen;
294 memcpy(pos, str, copy);
295 pos[copy] = '\0';
296 return dstlen + srclen;
297}
298
299#endif /* ANDROID */
Ankita Bajaj1bde7942018-01-09 19:15:01 +0530300
301
302void hex_dump(struct sigma_dut *dut, u8 *data, size_t len)
303{
304 char buf[1024];
305 size_t index;
306 u8 *ptr;
307 int pos;
308
309 memset(buf, 0, sizeof(buf));
310 ptr = data;
311 pos = 0;
312 for (index = 0; index < len; index++) {
313 pos += snprintf(&(buf[pos]), sizeof(buf) - pos,
314 "%02x ", *ptr++);
315 if (pos > 1020)
316 break;
317 }
318 sigma_dut_print(dut, DUT_MSG_INFO, "HEXDUMP len=[%d]", (int) len);
319 sigma_dut_print(dut, DUT_MSG_INFO, "buf:%s", buf);
320}
Peng Xu291d97d2018-01-31 16:34:03 -0800321
322
323#ifdef NL80211_SUPPORT
324
325void * nl80211_cmd(struct sigma_dut *dut, struct nl80211_ctx *ctx,
326 struct nl_msg *msg, int flags, uint8_t cmd)
327{
328 return genlmsg_put(msg, 0, 0, ctx->netlink_familyid,
329 0, flags, cmd, 0);
330}
331
332
333static struct nl_msg *
334nl80211_ifindex_msg(struct sigma_dut *dut, struct nl80211_ctx *ctx, int ifindex,
335 int flags, uint8_t cmd)
336{
337 struct nl_msg *msg;
338
339 msg = nlmsg_alloc();
340 if (!msg) {
341 sigma_dut_print(dut, DUT_MSG_ERROR,
342 "Failed to allocate NL message");
343 return NULL;
344 }
345
346 if (!nl80211_cmd(dut, ctx, msg, flags, cmd) ||
347 nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifindex)) {
348 nlmsg_free(msg);
349 return NULL;
350 }
351
352 return msg;
353}
354
355
356struct nl_msg * nl80211_drv_msg(struct sigma_dut *dut, struct nl80211_ctx *ctx,
357 int ifindex, int flags, uint8_t cmd)
358{
359 return nl80211_ifindex_msg(dut, ctx, ifindex, flags, cmd);
360}
361
362
363static int ack_handler(struct nl_msg *msg, void *arg)
364{
365 int *err = arg;
366 *err = 0;
367 return NL_STOP;
368}
369
370
371static int finish_handler(struct nl_msg *msg, void *arg)
372{
373 int *ret = arg;
374 *ret = 0;
375 return NL_SKIP;
376}
377
378
379static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
380 void *arg)
381{
382 int *ret = arg;
383 *ret = err->error;
384 return NL_SKIP;
385}
386
387
388int send_and_recv_msgs(struct sigma_dut *dut, struct nl80211_ctx *ctx,
389 struct nl_msg *nlmsg,
390 int (*valid_handler)(struct nl_msg *, void *),
391 void *valid_data)
392{
393 struct nl_cb *cb;
394 int err = -ENOMEM;
395
396 if (!nlmsg)
397 return -ENOMEM;
398
399 cb = nl_cb_alloc(NL_CB_DEFAULT);
400 if (!cb)
401 goto out;
402
403 err = nl_send_auto_complete(ctx->sock, nlmsg);
404 if (err < 0) {
405 sigma_dut_print(dut, DUT_MSG_ERROR,
406 "nl80211: failed to send err=%d", err);
407 goto out;
408 }
409
410 err = 1;
411
412 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
413 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
414 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
415
416 if (valid_handler)
417 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
418 valid_handler, valid_data);
419
420 while (err > 0) {
421 int res = nl_recvmsgs(ctx->sock, cb);
422
423 if (res < 0) {
424 sigma_dut_print(dut, DUT_MSG_ERROR,
425 "nl80211: %s->nl_recvmsgs failed: res=%d, err=%d",
426 __func__, res, err);
427 }
428 }
429 out:
430 nl_cb_put(cb);
431 if (!valid_handler && valid_data == (void *) -1) {
432 if (nlmsg) {
433 struct nlmsghdr *hdr = nlmsg_hdr(nlmsg);
434 void *data = nlmsg_data(hdr);
435 int len = hdr->nlmsg_len - NLMSG_HDRLEN;
436
437 memset(data, 0, len);
438 }
439 }
440
441 nlmsg_free(nlmsg);
442 return err;
443}
444
445
446struct nl80211_ctx * nl80211_init(struct sigma_dut *dut)
447{
448 struct nl80211_ctx *ctx;
449
450 ctx = calloc(1, sizeof(struct nl80211_ctx));
451 if (!ctx) {
452 sigma_dut_print(dut, DUT_MSG_ERROR,
453 "Failed to alloc nl80211_ctx");
454 return NULL;
455 }
456
457 ctx->sock = nl_socket_alloc();
458 if (!ctx->sock) {
459 sigma_dut_print(dut, DUT_MSG_ERROR,
460 "Failed to create NL socket, err: %s",
461 strerror(errno));
462 goto cleanup;
463 }
464
465 if (nl_connect(ctx->sock, NETLINK_GENERIC)) {
466 sigma_dut_print(dut, DUT_MSG_ERROR,
467 "Could not connect socket, err: %s",
468 strerror(errno));
469 goto cleanup;
470 }
471
472 if (nl_socket_set_buffer_size(ctx->sock, SOCK_BUF_SIZE, 0) < 0) {
473 sigma_dut_print(dut, DUT_MSG_INFO,
474 "Could not set nl_socket RX buffer size for sock: %s",
475 strerror(errno));
476 }
477
478 ctx->netlink_familyid = genl_ctrl_resolve(ctx->sock, "nl80211");
479 if (ctx->netlink_familyid < 0) {
480 sigma_dut_print(dut, DUT_MSG_ERROR,
481 "Could not resolve nl80211 family id");
482 goto cleanup;
483 }
484
485 ctx->nlctrl_familyid = genl_ctrl_resolve(ctx->sock, "nlctrl");
486 if (ctx->nlctrl_familyid < 0) {
487 sigma_dut_print(dut, DUT_MSG_ERROR,
488 "net link family nlctrl is not present: %d err:%s",
489 ctx->nlctrl_familyid, strerror(errno));
490 goto cleanup;
491 }
492
493 return ctx;
494
495cleanup:
496 if (ctx->sock)
497 nl_socket_free(ctx->sock);
498
499 free(ctx);
500 return NULL;
501}
502
503
504void nl80211_deinit(struct sigma_dut *dut, struct nl80211_ctx *ctx)
505{
506 if (!ctx || !ctx->sock) {
507 sigma_dut_print(dut, DUT_MSG_ERROR, "%s: ctx/sock is NULL",
508 __func__);
509 return;
510 }
511 nl_socket_free(ctx->sock);
512 free(ctx);
513}
514
515#endif /* NL80211_SUPPORT */