blob: 7949ccb41e552f02642a7df6f16a88823d149309 [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
Rakesh Sunki8f8e74b2017-05-16 15:42:12 -0700243void convert_mac_addr_to_ipv6_lladdr(u8 *mac_addr, char *ipv6_buf,
244 size_t buf_len)
245{
246 u8 temp = mac_addr[0] ^ 0x02;
247
248 snprintf(ipv6_buf, buf_len, "fe80::%02x%02x:%02xff:fe%02x:%02x%02x",
249 temp, mac_addr[1], mac_addr[2],
250 mac_addr[3], mac_addr[4], mac_addr[5]);
251}
252
253
Peng Xu769731a2017-05-10 17:27:28 -0700254#ifndef ANDROID
255
256size_t strlcpy(char *dest, const char *src, size_t siz)
257{
258 const char *s = src;
259 size_t left = siz;
260
261 if (left) {
262 /* Copy string up to the maximum size of the dest buffer */
263 while (--left != 0) {
264 if ((*dest++ = *s++) == '\0')
265 break;
266 }
267 }
268
269 if (left == 0) {
270 /* Not enough room for the string; force NUL-termination */
271 if (siz != 0)
272 *dest = '\0';
273 while (*s++)
274 ; /* determine total src string length */
275 }
276
277 return s - src - 1;
278}
279
280
281size_t strlcat(char *dst, const char *str, size_t size)
282{
283 char *pos;
284 size_t dstlen, srclen, copy;
285
286 srclen = strlen(str);
287 for (pos = dst; pos - dst < size && *dst; pos++)
288 ;
289 dstlen = pos - dst;
290 if (*dst)
291 return dstlen + srclen;
292 if (dstlen + srclen + 1 > size)
293 copy = size - dstlen - 1;
294 else
295 copy = srclen;
296 memcpy(pos, str, copy);
297 pos[copy] = '\0';
298 return dstlen + srclen;
299}
300
301#endif /* ANDROID */
Ankita Bajaj1bde7942018-01-09 19:15:01 +0530302
303
304void hex_dump(struct sigma_dut *dut, u8 *data, size_t len)
305{
306 char buf[1024];
307 size_t index;
308 u8 *ptr;
309 int pos;
310
311 memset(buf, 0, sizeof(buf));
312 ptr = data;
313 pos = 0;
314 for (index = 0; index < len; index++) {
315 pos += snprintf(&(buf[pos]), sizeof(buf) - pos,
316 "%02x ", *ptr++);
317 if (pos > 1020)
318 break;
319 }
320 sigma_dut_print(dut, DUT_MSG_INFO, "HEXDUMP len=[%d]", (int) len);
321 sigma_dut_print(dut, DUT_MSG_INFO, "buf:%s", buf);
322}
Peng Xu291d97d2018-01-31 16:34:03 -0800323
324
325#ifdef NL80211_SUPPORT
326
327void * nl80211_cmd(struct sigma_dut *dut, struct nl80211_ctx *ctx,
328 struct nl_msg *msg, int flags, uint8_t cmd)
329{
330 return genlmsg_put(msg, 0, 0, ctx->netlink_familyid,
331 0, flags, cmd, 0);
332}
333
334
335static struct nl_msg *
336nl80211_ifindex_msg(struct sigma_dut *dut, struct nl80211_ctx *ctx, int ifindex,
337 int flags, uint8_t cmd)
338{
339 struct nl_msg *msg;
340
341 msg = nlmsg_alloc();
342 if (!msg) {
343 sigma_dut_print(dut, DUT_MSG_ERROR,
344 "Failed to allocate NL message");
345 return NULL;
346 }
347
348 if (!nl80211_cmd(dut, ctx, msg, flags, cmd) ||
349 nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifindex)) {
350 nlmsg_free(msg);
351 return NULL;
352 }
353
354 return msg;
355}
356
357
358struct nl_msg * nl80211_drv_msg(struct sigma_dut *dut, struct nl80211_ctx *ctx,
359 int ifindex, int flags, uint8_t cmd)
360{
361 return nl80211_ifindex_msg(dut, ctx, ifindex, flags, cmd);
362}
363
364
365static int ack_handler(struct nl_msg *msg, void *arg)
366{
367 int *err = arg;
368 *err = 0;
369 return NL_STOP;
370}
371
372
373static int finish_handler(struct nl_msg *msg, void *arg)
374{
375 int *ret = arg;
376 *ret = 0;
377 return NL_SKIP;
378}
379
380
381static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
382 void *arg)
383{
384 int *ret = arg;
385 *ret = err->error;
386 return NL_SKIP;
387}
388
389
390int send_and_recv_msgs(struct sigma_dut *dut, struct nl80211_ctx *ctx,
391 struct nl_msg *nlmsg,
392 int (*valid_handler)(struct nl_msg *, void *),
393 void *valid_data)
394{
395 struct nl_cb *cb;
396 int err = -ENOMEM;
397
398 if (!nlmsg)
399 return -ENOMEM;
400
401 cb = nl_cb_alloc(NL_CB_DEFAULT);
402 if (!cb)
403 goto out;
404
405 err = nl_send_auto_complete(ctx->sock, nlmsg);
406 if (err < 0) {
407 sigma_dut_print(dut, DUT_MSG_ERROR,
408 "nl80211: failed to send err=%d", err);
409 goto out;
410 }
411
412 err = 1;
413
414 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
415 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
416 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
417
418 if (valid_handler)
419 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
420 valid_handler, valid_data);
421
422 while (err > 0) {
423 int res = nl_recvmsgs(ctx->sock, cb);
424
425 if (res < 0) {
426 sigma_dut_print(dut, DUT_MSG_ERROR,
427 "nl80211: %s->nl_recvmsgs failed: res=%d, err=%d",
428 __func__, res, err);
429 }
430 }
431 out:
432 nl_cb_put(cb);
433 if (!valid_handler && valid_data == (void *) -1) {
434 if (nlmsg) {
435 struct nlmsghdr *hdr = nlmsg_hdr(nlmsg);
436 void *data = nlmsg_data(hdr);
437 int len = hdr->nlmsg_len - NLMSG_HDRLEN;
438
439 memset(data, 0, len);
440 }
441 }
442
443 nlmsg_free(nlmsg);
444 return err;
445}
446
447
448struct nl80211_ctx * nl80211_init(struct sigma_dut *dut)
449{
450 struct nl80211_ctx *ctx;
451
452 ctx = calloc(1, sizeof(struct nl80211_ctx));
453 if (!ctx) {
454 sigma_dut_print(dut, DUT_MSG_ERROR,
455 "Failed to alloc nl80211_ctx");
456 return NULL;
457 }
458
459 ctx->sock = nl_socket_alloc();
460 if (!ctx->sock) {
461 sigma_dut_print(dut, DUT_MSG_ERROR,
462 "Failed to create NL socket, err: %s",
463 strerror(errno));
464 goto cleanup;
465 }
466
467 if (nl_connect(ctx->sock, NETLINK_GENERIC)) {
468 sigma_dut_print(dut, DUT_MSG_ERROR,
469 "Could not connect socket, err: %s",
470 strerror(errno));
471 goto cleanup;
472 }
473
474 if (nl_socket_set_buffer_size(ctx->sock, SOCK_BUF_SIZE, 0) < 0) {
475 sigma_dut_print(dut, DUT_MSG_INFO,
476 "Could not set nl_socket RX buffer size for sock: %s",
477 strerror(errno));
478 }
479
480 ctx->netlink_familyid = genl_ctrl_resolve(ctx->sock, "nl80211");
481 if (ctx->netlink_familyid < 0) {
482 sigma_dut_print(dut, DUT_MSG_ERROR,
483 "Could not resolve nl80211 family id");
484 goto cleanup;
485 }
486
487 ctx->nlctrl_familyid = genl_ctrl_resolve(ctx->sock, "nlctrl");
488 if (ctx->nlctrl_familyid < 0) {
489 sigma_dut_print(dut, DUT_MSG_ERROR,
490 "net link family nlctrl is not present: %d err:%s",
491 ctx->nlctrl_familyid, strerror(errno));
492 goto cleanup;
493 }
494
495 return ctx;
496
497cleanup:
498 if (ctx->sock)
499 nl_socket_free(ctx->sock);
500
501 free(ctx);
502 return NULL;
503}
504
505
506void nl80211_deinit(struct sigma_dut *dut, struct nl80211_ctx *ctx)
507{
508 if (!ctx || !ctx->sock) {
509 sigma_dut_print(dut, DUT_MSG_ERROR, "%s: ctx/sock is NULL",
510 __func__);
511 return;
512 }
513 nl_socket_free(ctx->sock);
514 free(ctx);
515}
516
517#endif /* NL80211_SUPPORT */