xref: /wlan-dirver/utils/sigma-dut/utils.c (revision 016ae6c8cafcbfd03dc69ed0eb43e252fb93e347)
1 /*
2  * Sigma Control API DUT (station/AP)
3  * Copyright (c) 2014-2017, Qualcomm Atheros, Inc.
4  * Copyright (c) 2018, The Linux Foundation
5  * Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi>
6  * All Rights Reserved.
7  * Licensed under the Clear BSD license. See README for more details.
8  */
9 
10 #include "sigma_dut.h"
11 #include <sys/stat.h>
12 #include "wpa_helpers.h"
13 
14 enum driver_type wifi_chip_type = DRIVER_NOT_SET;
15 enum openwrt_driver_type openwrt_chip_type = OPENWRT_DRIVER_NOT_SET;
16 
17 
18 int file_exists(const char *fname)
19 {
20 	struct stat s;
21 	return stat(fname, &s) == 0;
22 }
23 
24 
25 int set_wifi_chip(const char *chip_type)
26 {
27 	if (!strncmp(chip_type, "WCN", strlen("WCN")))
28 		wifi_chip_type = DRIVER_WCN;
29 	else if (!strncmp(chip_type, "ATHEROS", strlen("ATHEROS")))
30 		wifi_chip_type = DRIVER_ATHEROS;
31 	else if (!strncmp(chip_type, "AR6003", strlen("AR6003")))
32 		wifi_chip_type = DRIVER_AR6003;
33 	else if (strcmp(chip_type, "MAC80211") == 0)
34 		wifi_chip_type = DRIVER_MAC80211;
35 	else if (strcmp(chip_type, "QNXNTO") == 0)
36 		wifi_chip_type = DRIVER_QNXNTO;
37 	else if (strcmp(chip_type, "OPENWRT") == 0)
38 		wifi_chip_type = DRIVER_OPENWRT;
39 	else if (!strncmp(chip_type, "LINUX-WCN", strlen("LINUX-WCN")))
40 		wifi_chip_type = DRIVER_LINUX_WCN;
41 	else
42 		return -1;
43 
44 	return 0;
45 }
46 
47 
48 enum driver_type get_driver_type(struct sigma_dut *dut)
49 {
50 	struct stat s;
51 	if (wifi_chip_type == DRIVER_NOT_SET) {
52 		/* Check for 60G driver */
53 		ssize_t len;
54 		char link[256];
55 		char buf[256];
56 		const char *ifname = get_station_ifname(dut);
57 
58 		snprintf(buf, sizeof(buf), "/sys/class/net/%s/device/driver",
59 			 ifname);
60 		len = readlink(buf, link, sizeof(link) - 1);
61 		if (len >= 0) {
62 			link[len] = '\0';
63 			if (strstr(link, DRIVER_NAME_60G))
64 				return DRIVER_WIL6210;
65 		}
66 
67 		if (stat("/sys/module/mac80211", &s) == 0)
68 			return DRIVER_MAC80211;
69 		return DRIVER_ATHEROS;
70 	}
71 	return wifi_chip_type;
72 }
73 
74 
75 enum openwrt_driver_type get_openwrt_driver_type(void)
76 {
77 	struct stat s;
78 
79 	if (openwrt_chip_type == OPENWRT_DRIVER_NOT_SET) {
80 		if (stat("/sys/module/umac", &s) == 0 ||
81 		    stat("/sys/module/atd", &s) == 0)
82 			openwrt_chip_type = OPENWRT_DRIVER_ATHEROS;
83 	}
84 
85 	return openwrt_chip_type;
86 }
87 
88 
89 enum sigma_program sigma_program_to_enum(const char *prog)
90 {
91 	if (prog == NULL)
92 		return PROGRAM_UNKNOWN;
93 
94 	if (strcasecmp(prog, "TDLS") == 0)
95 		return PROGRAM_TDLS;
96 	if (strcasecmp(prog, "HS2") == 0)
97 		return PROGRAM_HS2;
98 	if (strcasecmp(prog, "HS2_R2") == 0 ||
99 	    strcasecmp(prog, "HS2-R2") == 0)
100 		return PROGRAM_HS2_R2;
101 	if (strcasecmp(prog, "HS2-R3") == 0)
102 		return PROGRAM_HS2_R3;
103 	if (strcasecmp(prog, "WFD") == 0)
104 		return PROGRAM_WFD;
105 	if (strcasecmp(prog, "DisplayR2") == 0)
106 		return PROGRAM_DISPLAYR2;
107 	if (strcasecmp(prog, "PMF") == 0)
108 		return PROGRAM_PMF;
109 	if (strcasecmp(prog, "WPS") == 0)
110 		return PROGRAM_WPS;
111 	if (strcasecmp(prog, "11n") == 0)
112 		return PROGRAM_HT;
113 	if (strcasecmp(prog, "VHT") == 0)
114 		return PROGRAM_VHT;
115 	if (strcasecmp(prog, "60GHZ") == 0)
116 		return PROGRAM_60GHZ;
117 	if (strcasecmp(prog, "NAN") == 0)
118 		return PROGRAM_NAN;
119 	if (strcasecmp(prog, "LOC") == 0)
120 		return PROGRAM_LOC;
121 	if (strcasecmp(prog, "MBO") == 0)
122 		return PROGRAM_MBO;
123 	if (strcasecmp(prog, "IoTLP") == 0)
124 		return PROGRAM_IOTLP;
125 	if (strcasecmp(prog, "DPP") == 0)
126 		return PROGRAM_DPP;
127 	if (strcasecmp(prog, "OCE") == 0)
128 		return PROGRAM_OCE;
129 	if (strcasecmp(prog, "WPA3") == 0)
130 		return PROGRAM_WPA3;
131 	if (strcasecmp(prog, "HE") == 0)
132 		return PROGRAM_HE;
133 
134 	return PROGRAM_UNKNOWN;
135 }
136 
137 
138 static int parse_hex(char c)
139 {
140 	if (c >= '0' && c <= '9')
141 		return c - '0';
142 	if (c >= 'a' && c <= 'f')
143 		return c - 'a' + 10;
144 	if (c >= 'A' && c <= 'F')
145 		return c - 'A' + 10;
146 	return -1;
147 }
148 
149 
150 int hex_byte(const char *str)
151 {
152 	int res1, res2;
153 
154 	res1 = parse_hex(str[0]);
155 	if (res1 < 0)
156 		return -1;
157 	res2 = parse_hex(str[1]);
158 	if (res2 < 0)
159 		return -1;
160 	return (res1 << 4) | res2;
161 }
162 
163 
164 int parse_hexstr(const char *hex, unsigned char *buf, size_t buflen)
165 {
166 	size_t i;
167 	const char *pos = hex;
168 
169 	for (i = 0; i < buflen; i++) {
170 		int val;
171 
172 		if (*pos == '\0')
173 			break;
174 		val = hex_byte(pos);
175 		if (val < 0)
176 			return -1;
177 		buf[i] = val;
178 		pos += 2;
179 	}
180 
181 	return i;
182 }
183 
184 
185 int parse_mac_address(struct sigma_dut *dut, const char *arg,
186 		      unsigned char *addr)
187 {
188 	int i;
189 	const char *pos = arg;
190 
191 	if (strlen(arg) != 17)
192 		goto fail;
193 
194 	for (i = 0; i < ETH_ALEN; i++) {
195 		int val;
196 
197 		val = hex_byte(pos);
198 		if (val < 0)
199 			goto fail;
200 		addr[i] = val;
201 		if (i + 1 < ETH_ALEN) {
202 			pos += 2;
203 			if (*pos != ':')
204 				goto fail;
205 			pos++;
206 		}
207 	}
208 
209 	return 0;
210 
211 fail:
212 	sigma_dut_print(dut, DUT_MSG_ERROR,
213 			"Invalid MAC address %s (expected format xx:xx:xx:xx:xx:xx)",
214 			arg);
215 	return -1;
216 }
217 
218 
219 int is_60g_sigma_dut(struct sigma_dut *dut)
220 {
221 	return dut->program == PROGRAM_60GHZ ||
222 		(dut->program == PROGRAM_WPS &&
223 		 (get_driver_type(dut) == DRIVER_WIL6210));
224 }
225 
226 
227 unsigned int channel_to_freq(struct sigma_dut *dut, unsigned int channel)
228 {
229 	if (is_60g_sigma_dut(dut)) {
230 		if (channel >= 1 && channel <= 4)
231 			return 58320 + 2160 * channel;
232 
233 		return 0;
234 	}
235 
236 	if (channel >= 1 && channel <= 13)
237 		return 2407 + 5 * channel;
238 	if (channel == 14)
239 		return 2484;
240 	if (channel >= 36 && channel <= 165)
241 		return 5000 + 5 * channel;
242 
243 	return 0;
244 }
245 
246 
247 unsigned int freq_to_channel(unsigned int freq)
248 {
249 	if (freq >= 2412 && freq <= 2472)
250 		return (freq - 2407) / 5;
251 	if (freq == 2484)
252 		return 14;
253 	if (freq >= 5180 && freq <= 5825)
254 		return (freq - 5000) / 5;
255 	if (freq >= 58320 && freq <= 64800)
256 		return (freq - 58320) / 2160;
257 	return 0;
258 }
259 
260 
261 int is_ipv6_addr(const char *str)
262 {
263 	struct sockaddr_in6 addr;
264 
265 	return inet_pton(AF_INET6, str, &(addr.sin6_addr));
266 }
267 
268 
269 void convert_mac_addr_to_ipv6_lladdr(u8 *mac_addr, char *ipv6_buf,
270 				     size_t buf_len)
271 {
272 	u8 temp = mac_addr[0] ^ 0x02;
273 
274 	snprintf(ipv6_buf, buf_len, "fe80::%02x%02x:%02xff:fe%02x:%02x%02x",
275 		 temp, mac_addr[1], mac_addr[2],
276 		 mac_addr[3], mac_addr[4], mac_addr[5]);
277 }
278 
279 
280 size_t convert_mac_addr_to_ipv6_linklocal(const u8 *mac_addr, u8 *ipv6)
281 {
282 	int i;
283 
284 	ipv6[0] = 0xfe;
285 	ipv6[1] = 0x80;
286 	for (i = 2; i < 8; i++)
287 		ipv6[i] = 0;
288 	ipv6[8] = mac_addr[0] ^ 0x02;
289 	ipv6[9] = mac_addr[1];
290 	ipv6[10] = mac_addr[2];
291 	ipv6[11] = 0xff;
292 	ipv6[12] = 0xfe;
293 	ipv6[13] = mac_addr[3];
294 	ipv6[14] = mac_addr[4];
295 	ipv6[15] = mac_addr[5];
296 
297 	return 16;
298 }
299 
300 
301 #ifndef ANDROID
302 
303 size_t strlcpy(char *dest, const char *src, size_t siz)
304 {
305 	const char *s = src;
306 	size_t left = siz;
307 
308 	if (left) {
309 		/* Copy string up to the maximum size of the dest buffer */
310 		while (--left != 0) {
311 			if ((*dest++ = *s++) == '\0')
312 				break;
313 		}
314 	}
315 
316 	if (left == 0) {
317 		/* Not enough room for the string; force NUL-termination */
318 		if (siz != 0)
319 			*dest = '\0';
320 		while (*s++)
321 			; /* determine total src string length */
322 	}
323 
324 	return s - src - 1;
325 }
326 
327 
328 size_t strlcat(char *dst, const char *str, size_t size)
329 {
330 	char *pos;
331 	size_t dstlen, srclen, copy;
332 
333 	srclen = strlen(str);
334 	for (pos = dst; pos - dst < size && *dst; pos++)
335 		;
336 	dstlen = pos - dst;
337 	if (*dst)
338 		return dstlen + srclen;
339 	if (dstlen + srclen + 1 > size)
340 		copy = size - dstlen - 1;
341 	else
342 		copy = srclen;
343 	memcpy(pos, str, copy);
344 	pos[copy] = '\0';
345 	return dstlen + srclen;
346 }
347 
348 #endif /* ANDROID */
349 
350 
351 void hex_dump(struct sigma_dut *dut, u8 *data, size_t len)
352 {
353 	char buf[1024];
354 	size_t index;
355 	u8 *ptr;
356 	int pos;
357 
358 	memset(buf, 0, sizeof(buf));
359 	ptr = data;
360 	pos = 0;
361 	for (index = 0; index < len; index++) {
362 		pos += snprintf(&(buf[pos]), sizeof(buf) - pos,
363 				"%02x ", *ptr++);
364 		if (pos > 1020)
365 			break;
366 	}
367 	sigma_dut_print(dut, DUT_MSG_INFO, "HEXDUMP len=[%d]", (int) len);
368 	sigma_dut_print(dut, DUT_MSG_INFO, "buf:%s", buf);
369 }
370 
371 
372 #ifdef NL80211_SUPPORT
373 
374 void * nl80211_cmd(struct sigma_dut *dut, struct nl80211_ctx *ctx,
375 		   struct nl_msg *msg, int flags, uint8_t cmd)
376 {
377 	return genlmsg_put(msg, 0, 0, ctx->netlink_familyid,
378 			   0, flags, cmd, 0);
379 }
380 
381 
382 static struct nl_msg *
383 nl80211_ifindex_msg(struct sigma_dut *dut, struct nl80211_ctx *ctx, int ifindex,
384 		    int flags, uint8_t cmd)
385 {
386 	struct nl_msg *msg;
387 
388 	msg = nlmsg_alloc();
389 	if (!msg) {
390 		sigma_dut_print(dut, DUT_MSG_ERROR,
391 				"Failed to allocate NL message");
392 		return NULL;
393 	}
394 
395 	if (!nl80211_cmd(dut, ctx, msg, flags, cmd) ||
396 	    nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifindex)) {
397 		nlmsg_free(msg);
398 		return NULL;
399 	}
400 
401 	return msg;
402 }
403 
404 
405 struct nl_msg * nl80211_drv_msg(struct sigma_dut *dut, struct nl80211_ctx *ctx,
406 				int ifindex, int flags, uint8_t cmd)
407 {
408 	return nl80211_ifindex_msg(dut, ctx, ifindex, flags, cmd);
409 }
410 
411 
412 static int ack_handler(struct nl_msg *msg, void *arg)
413 {
414 	int *err = arg;
415 	*err = 0;
416 	return NL_STOP;
417 }
418 
419 
420 static int finish_handler(struct nl_msg *msg, void *arg)
421 {
422 	int *ret = arg;
423 	*ret = 0;
424 	return NL_SKIP;
425 }
426 
427 
428 static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
429 			 void *arg)
430 {
431 	int *ret = arg;
432 	*ret = err->error;
433 	return NL_SKIP;
434 }
435 
436 
437 int send_and_recv_msgs(struct sigma_dut *dut, struct nl80211_ctx *ctx,
438 		       struct nl_msg *nlmsg,
439 		       int (*valid_handler)(struct nl_msg *, void *),
440 		       void *valid_data)
441 {
442 	struct nl_cb *cb;
443 	int err = -ENOMEM;
444 
445 	if (!nlmsg)
446 		return -ENOMEM;
447 
448 	cb = nl_cb_alloc(NL_CB_DEFAULT);
449 	if (!cb)
450 		goto out;
451 
452 	err = nl_send_auto_complete(ctx->sock, nlmsg);
453 	if (err < 0) {
454 		sigma_dut_print(dut, DUT_MSG_ERROR,
455 				"nl80211: failed to send err=%d", err);
456 		goto out;
457 	}
458 
459 	err = 1;
460 
461 	nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
462 	nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
463 	nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
464 
465 	if (valid_handler)
466 		nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
467 			  valid_handler, valid_data);
468 
469 	while (err > 0) {
470 		int res = nl_recvmsgs(ctx->sock, cb);
471 
472 		if (res < 0) {
473 			sigma_dut_print(dut, DUT_MSG_ERROR,
474 					"nl80211: %s->nl_recvmsgs failed: res=%d, err=%d",
475 					__func__, res, err);
476 		}
477 	}
478  out:
479 	nl_cb_put(cb);
480 	if (!valid_handler && valid_data == (void *) -1) {
481 		if (nlmsg) {
482 			struct nlmsghdr *hdr = nlmsg_hdr(nlmsg);
483 			void *data = nlmsg_data(hdr);
484 			int len = hdr->nlmsg_len - NLMSG_HDRLEN;
485 
486 			memset(data, 0, len);
487 		}
488 	}
489 
490 	nlmsg_free(nlmsg);
491 	return err;
492 }
493 
494 
495 struct nl80211_ctx * nl80211_init(struct sigma_dut *dut)
496 {
497 	struct nl80211_ctx *ctx;
498 
499 	ctx = calloc(1, sizeof(struct nl80211_ctx));
500 	if (!ctx) {
501 		sigma_dut_print(dut, DUT_MSG_ERROR,
502 				"Failed to alloc nl80211_ctx");
503 		return NULL;
504 	}
505 
506 	ctx->sock = nl_socket_alloc();
507 	if (!ctx->sock) {
508 		sigma_dut_print(dut, DUT_MSG_ERROR,
509 				"Failed to create NL socket, err: %s",
510 				strerror(errno));
511 		goto cleanup;
512 	}
513 
514 	if (nl_connect(ctx->sock, NETLINK_GENERIC)) {
515 		sigma_dut_print(dut, DUT_MSG_ERROR,
516 				"Could not connect socket, err: %s",
517 				strerror(errno));
518 		goto cleanup;
519 	}
520 
521 	if (nl_socket_set_buffer_size(ctx->sock, SOCK_BUF_SIZE, 0) < 0) {
522 		sigma_dut_print(dut, DUT_MSG_INFO,
523 				"Could not set nl_socket RX buffer size for sock: %s",
524 				strerror(errno));
525 	}
526 
527 	ctx->netlink_familyid = genl_ctrl_resolve(ctx->sock, "nl80211");
528 	if (ctx->netlink_familyid < 0) {
529 		sigma_dut_print(dut, DUT_MSG_ERROR,
530 				"Could not resolve nl80211 family id");
531 		goto cleanup;
532 	}
533 
534 	ctx->nlctrl_familyid = genl_ctrl_resolve(ctx->sock, "nlctrl");
535 	if (ctx->nlctrl_familyid < 0) {
536 		sigma_dut_print(dut, DUT_MSG_ERROR,
537 				"net link family nlctrl is not present: %d err:%s",
538 				ctx->nlctrl_familyid, strerror(errno));
539 		goto cleanup;
540 	}
541 
542 	return ctx;
543 
544 cleanup:
545 	if (ctx->sock)
546 		nl_socket_free(ctx->sock);
547 
548 	free(ctx);
549 	return NULL;
550 }
551 
552 
553 void nl80211_deinit(struct sigma_dut *dut, struct nl80211_ctx *ctx)
554 {
555 	if (!ctx || !ctx->sock) {
556 		sigma_dut_print(dut, DUT_MSG_ERROR, "%s: ctx/sock is NULL",
557 				__func__);
558 		return;
559 	}
560 	nl_socket_free(ctx->sock);
561 	free(ctx);
562 }
563 
564 #endif /* NL80211_SUPPORT */
565 
566 
567 static int get_wps_pin_checksum(int pin)
568 {
569 	int a = 0;
570 
571 	while (pin > 0) {
572 		a += 3 * (pin % 10);
573 		pin = pin / 10;
574 		a += (pin % 10);
575 		pin = pin / 10;
576 	}
577 
578 	return (10 - (a % 10)) % 10;
579 }
580 
581 
582 int get_wps_pin_from_mac(struct sigma_dut *dut, const char *macaddr,
583 			 char *pin, size_t len)
584 {
585 	unsigned char mac[ETH_ALEN];
586 	int tmp, checksum;
587 
588 	if (len < 9)
589 		return -1;
590 	if (parse_mac_address(dut, macaddr, mac))
591 		return -1;
592 
593 	/*
594 	 * get 7 digit PIN from the last 24 bits of MAC
595 	 * range 1000000 - 9999999
596 	 */
597 	tmp = (mac[5] & 0xFF) | ((mac[4] & 0xFF) << 8) |
598 	      ((mac[3] & 0xFF) << 16);
599 	tmp = (tmp % 9000000) + 1000000;
600 	checksum = get_wps_pin_checksum(tmp);
601 	snprintf(pin, len, "%07d%01d", tmp, checksum);
602 	return 0;
603 }
604 
605 
606 int get_wps_forced_version(struct sigma_dut *dut, const char *str)
607 {
608 	int major, minor, result = 0;
609 	int count = sscanf(str, "%d.%d", &major, &minor);
610 
611 	if (count == 2) {
612 		result = major * 16 + minor;
613 		sigma_dut_print(dut, DUT_MSG_DEBUG,
614 				"Force WPS version to 0x%02x (%s)",
615 				result, str);
616 	} else {
617 		sigma_dut_print(dut, DUT_MSG_ERROR,
618 				"Invalid WPS version %s", str);
619 	}
620 
621 	return result;
622 }
623 
624 
625 void str_remove_chars(char *str, char ch)
626 {
627 	char *pr = str, *pw = str;
628 
629 	while (*pr) {
630 		*pw = *pr++;
631 		if (*pw != ch)
632 			pw++;
633 	}
634 	*pw = '\0';
635 }
636 
637 
638 static const char base64_table[65] =
639 	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
640 
641 
642 int base64_encode(const char *src, size_t len, char *out, size_t out_len)
643 {
644 	unsigned char *pos;
645 	const unsigned char *end, *in;
646 	size_t olen;
647 
648 	olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */
649 	olen++; /* nul termination */
650 	if (olen < len || olen > out_len)
651 		return -1;
652 
653 	end = (unsigned char *)(src + len);
654 	in = (unsigned char *)src;
655 	pos = (unsigned char *)out;
656 	while (end - in >= 3) {
657 		*pos++ = base64_table[(in[0] >> 2) & 0x3f];
658 		*pos++ = base64_table[(((in[0] & 0x03) << 4) |
659 				       (in[1] >> 4)) & 0x3f];
660 		*pos++ = base64_table[(((in[1] & 0x0f) << 2) |
661 				       (in[2] >> 6)) & 0x3f];
662 		*pos++ = base64_table[in[2] & 0x3f];
663 		in += 3;
664 	}
665 
666 	if (end - in) {
667 		*pos++ = base64_table[(in[0] >> 2) & 0x3f];
668 		if (end - in == 1) {
669 			*pos++ = base64_table[((in[0] & 0x03) << 4) & 0x3f];
670 			*pos++ = '=';
671 		} else {
672 			*pos++ = base64_table[(((in[0] & 0x03) << 4) |
673 					       (in[1] >> 4)) & 0x3f];
674 			*pos++ = base64_table[((in[1] & 0x0f) << 2) & 0x3f];
675 		}
676 		*pos++ = '=';
677 	}
678 
679 	*pos = '\0';
680 	return 0;
681 }
682 
683 
684 int random_get_bytes(char *buf, size_t len)
685 {
686 	FILE *f;
687 	size_t rc;
688 
689 	f = fopen("/dev/urandom", "rb");
690 	if (!f)
691 		return -1;
692 
693 	rc = fread(buf, 1, len, f);
694 	fclose(f);
695 
696 	return rc != len ? -1 : 0;
697 }
698 
699 
700 int get_enable_disable(const char *val)
701 {
702 	if (strcasecmp(val, "enable") == 0 ||
703 	    strcasecmp(val, "enabled") == 0 ||
704 	    strcasecmp(val, "on") == 0 ||
705 	    strcasecmp(val, "yes") == 0)
706 		return 1;
707 	return atoi(val);
708 }
709