xref: /wlan-dirver/utils/sigma-dut/utils.c (revision ba630459ecbf526291f6896e6a3da7c07199aa6a) !
1 /*
2  * Sigma Control API DUT (station/AP)
3  * Copyright (c) 2014-2017, Qualcomm Atheros, Inc.
4  * Copyright (c) 2018, The Linux Foundation
5  * 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 
13 enum driver_type wifi_chip_type = DRIVER_NOT_SET;
14 enum openwrt_driver_type openwrt_chip_type = OPENWRT_DRIVER_NOT_SET;
15 
16 
17 int file_exists(const char *fname)
18 {
19 	struct stat s;
20 	return stat(fname, &s) == 0;
21 }
22 
23 
24 int 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;
38 	else if (!strncmp(chip_type, "LINUX-WCN", strlen("LINUX-WCN")))
39 		wifi_chip_type = DRIVER_LINUX_WCN;
40 	else
41 		return -1;
42 
43 	return 0;
44 }
45 
46 
47 enum 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 
74 enum openwrt_driver_type get_openwrt_driver_type(void)
75 {
76 	struct stat s;
77 
78 	if (openwrt_chip_type == OPENWRT_DRIVER_NOT_SET) {
79 		if (stat("/sys/module/umac", &s) == 0 ||
80 		    stat("/sys/module/atd", &s) == 0)
81 			openwrt_chip_type = OPENWRT_DRIVER_ATHEROS;
82 	}
83 
84 	return openwrt_chip_type;
85 }
86 
87 
88 enum 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, "HS2-R3") == 0)
101 		return PROGRAM_HS2_R3;
102 	if (strcasecmp(prog, "WFD") == 0)
103 		return PROGRAM_WFD;
104 	if (strcasecmp(prog, "DisplayR2") == 0)
105 		return PROGRAM_DISPLAYR2;
106 	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;
118 	if (strcasecmp(prog, "LOC") == 0)
119 		return PROGRAM_LOC;
120 	if (strcasecmp(prog, "MBO") == 0)
121 		return PROGRAM_MBO;
122 	if (strcasecmp(prog, "IoTLP") == 0)
123 		return PROGRAM_IOTLP;
124 	if (strcasecmp(prog, "DPP") == 0)
125 		return PROGRAM_DPP;
126 	if (strcasecmp(prog, "OCE") == 0)
127 		return PROGRAM_OCE;
128 	if (strcasecmp(prog, "WPA3") == 0)
129 		return PROGRAM_WPA3;
130 	if (strcasecmp(prog, "HE") == 0)
131 		return PROGRAM_HE;
132 
133 	return PROGRAM_UNKNOWN;
134 }
135 
136 
137 static 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 
149 static 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 
163 int 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 
184 int 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 
210 fail:
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 }
216 
217 
218 unsigned 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 
231 unsigned 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 }
241 
242 
243 void 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 
254 #ifndef ANDROID
255 
256 size_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 
281 size_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 */
302 
303 
304 void 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 }
323 
324 
325 #ifdef NL80211_SUPPORT
326 
327 void * 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 
335 static struct nl_msg *
336 nl80211_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 
358 struct 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 
365 static int ack_handler(struct nl_msg *msg, void *arg)
366 {
367 	int *err = arg;
368 	*err = 0;
369 	return NL_STOP;
370 }
371 
372 
373 static int finish_handler(struct nl_msg *msg, void *arg)
374 {
375 	int *ret = arg;
376 	*ret = 0;
377 	return NL_SKIP;
378 }
379 
380 
381 static 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 
390 int 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 
448 struct 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 
497 cleanup:
498 	if (ctx->sock)
499 		nl_socket_free(ctx->sock);
500 
501 	free(ctx);
502 	return NULL;
503 }
504 
505 
506 void 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 */
518