1189251Ssam/*
2189251Ssam * wpa_supplicant/hostapd / common helper functions, etc.
3346981Scy * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
4189251Ssam *
5252726Srpaulo * This software may be distributed under the terms of the BSD license.
6252726Srpaulo * See README for more details.
7189251Ssam */
8189251Ssam
9189251Ssam#include "includes.h"
10189251Ssam
11289549Srpaulo#include "common/ieee802_11_defs.h"
12189251Ssam#include "common.h"
13189251Ssam
14189251Ssam
15189251Ssamstatic int hex2num(char c)
16189251Ssam{
17189251Ssam	if (c >= '0' && c <= '9')
18189251Ssam		return c - '0';
19189251Ssam	if (c >= 'a' && c <= 'f')
20189251Ssam		return c - 'a' + 10;
21189251Ssam	if (c >= 'A' && c <= 'F')
22189251Ssam		return c - 'A' + 10;
23189251Ssam	return -1;
24189251Ssam}
25189251Ssam
26189251Ssam
27252726Srpauloint hex2byte(const char *hex)
28189251Ssam{
29189251Ssam	int a, b;
30189251Ssam	a = hex2num(*hex++);
31189251Ssam	if (a < 0)
32189251Ssam		return -1;
33189251Ssam	b = hex2num(*hex++);
34189251Ssam	if (b < 0)
35189251Ssam		return -1;
36189251Ssam	return (a << 4) | b;
37189251Ssam}
38189251Ssam
39189251Ssam
40281806Srpaulostatic const char * hwaddr_parse(const char *txt, u8 *addr)
41281806Srpaulo{
42281806Srpaulo	size_t i;
43281806Srpaulo
44281806Srpaulo	for (i = 0; i < ETH_ALEN; i++) {
45281806Srpaulo		int a;
46281806Srpaulo
47281806Srpaulo		a = hex2byte(txt);
48281806Srpaulo		if (a < 0)
49281806Srpaulo			return NULL;
50281806Srpaulo		txt += 2;
51281806Srpaulo		addr[i] = a;
52281806Srpaulo		if (i < ETH_ALEN - 1 && *txt++ != ':')
53281806Srpaulo			return NULL;
54281806Srpaulo	}
55281806Srpaulo	return txt;
56281806Srpaulo}
57281806Srpaulo
58281806Srpaulo
59189251Ssam/**
60214734Srpaulo * hwaddr_aton - Convert ASCII string to MAC address (colon-delimited format)
61189251Ssam * @txt: MAC address as a string (e.g., "00:11:22:33:44:55")
62189251Ssam * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
63189251Ssam * Returns: 0 on success, -1 on failure (e.g., string not a MAC address)
64189251Ssam */
65189251Ssamint hwaddr_aton(const char *txt, u8 *addr)
66189251Ssam{
67281806Srpaulo	return hwaddr_parse(txt, addr) ? 0 : -1;
68281806Srpaulo}
69189251Ssam
70189251Ssam
71281806Srpaulo/**
72281806Srpaulo * hwaddr_masked_aton - Convert ASCII string with optional mask to MAC address (colon-delimited format)
73281806Srpaulo * @txt: MAC address with optional mask as a string (e.g., "00:11:22:33:44:55/ff:ff:ff:ff:00:00")
74281806Srpaulo * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
75281806Srpaulo * @mask: Buffer for the MAC address mask (ETH_ALEN = 6 bytes)
76281806Srpaulo * @maskable: Flag to indicate whether a mask is allowed
77281806Srpaulo * Returns: 0 on success, -1 on failure (e.g., string not a MAC address)
78281806Srpaulo */
79281806Srpauloint hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable)
80281806Srpaulo{
81281806Srpaulo	const char *r;
82281806Srpaulo
83281806Srpaulo	/* parse address part */
84281806Srpaulo	r = hwaddr_parse(txt, addr);
85281806Srpaulo	if (!r)
86281806Srpaulo		return -1;
87281806Srpaulo
88281806Srpaulo	/* check for optional mask */
89337817Scy	if (*r == '\0' || isspace((unsigned char) *r)) {
90281806Srpaulo		/* no mask specified, assume default */
91281806Srpaulo		os_memset(mask, 0xff, ETH_ALEN);
92281806Srpaulo	} else if (maskable && *r == '/') {
93281806Srpaulo		/* mask specified and allowed */
94281806Srpaulo		r = hwaddr_parse(r + 1, mask);
95281806Srpaulo		/* parser error? */
96281806Srpaulo		if (!r)
97189251Ssam			return -1;
98281806Srpaulo	} else {
99281806Srpaulo		/* mask specified but not allowed or trailing garbage */
100281806Srpaulo		return -1;
101189251Ssam	}
102189251Ssam
103189251Ssam	return 0;
104189251Ssam}
105189251Ssam
106281806Srpaulo
107252726Srpaulo/**
108252726Srpaulo * hwaddr_compact_aton - Convert ASCII string to MAC address (no colon delimitors format)
109252726Srpaulo * @txt: MAC address as a string (e.g., "001122334455")
110252726Srpaulo * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
111252726Srpaulo * Returns: 0 on success, -1 on failure (e.g., string not a MAC address)
112252726Srpaulo */
113252726Srpauloint hwaddr_compact_aton(const char *txt, u8 *addr)
114252726Srpaulo{
115252726Srpaulo	int i;
116189251Ssam
117252726Srpaulo	for (i = 0; i < 6; i++) {
118252726Srpaulo		int a, b;
119252726Srpaulo
120252726Srpaulo		a = hex2num(*txt++);
121252726Srpaulo		if (a < 0)
122252726Srpaulo			return -1;
123252726Srpaulo		b = hex2num(*txt++);
124252726Srpaulo		if (b < 0)
125252726Srpaulo			return -1;
126252726Srpaulo		*addr++ = (a << 4) | b;
127252726Srpaulo	}
128252726Srpaulo
129252726Srpaulo	return 0;
130252726Srpaulo}
131252726Srpaulo
132189251Ssam/**
133214734Srpaulo * hwaddr_aton2 - Convert ASCII string to MAC address (in any known format)
134214734Srpaulo * @txt: MAC address as a string (e.g., 00:11:22:33:44:55 or 0011.2233.4455)
135214734Srpaulo * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
136214734Srpaulo * Returns: Characters used (> 0) on success, -1 on failure
137214734Srpaulo */
138214734Srpauloint hwaddr_aton2(const char *txt, u8 *addr)
139214734Srpaulo{
140214734Srpaulo	int i;
141214734Srpaulo	const char *pos = txt;
142214734Srpaulo
143214734Srpaulo	for (i = 0; i < 6; i++) {
144214734Srpaulo		int a, b;
145214734Srpaulo
146214734Srpaulo		while (*pos == ':' || *pos == '.' || *pos == '-')
147214734Srpaulo			pos++;
148214734Srpaulo
149214734Srpaulo		a = hex2num(*pos++);
150214734Srpaulo		if (a < 0)
151214734Srpaulo			return -1;
152214734Srpaulo		b = hex2num(*pos++);
153214734Srpaulo		if (b < 0)
154214734Srpaulo			return -1;
155214734Srpaulo		*addr++ = (a << 4) | b;
156214734Srpaulo	}
157214734Srpaulo
158214734Srpaulo	return pos - txt;
159214734Srpaulo}
160214734Srpaulo
161214734Srpaulo
162214734Srpaulo/**
163189251Ssam * hexstr2bin - Convert ASCII hex string into binary data
164189251Ssam * @hex: ASCII hex string (e.g., "01ab")
165189251Ssam * @buf: Buffer for the binary data
166189251Ssam * @len: Length of the text to convert in bytes (of buf); hex will be double
167189251Ssam * this size
168189251Ssam * Returns: 0 on success, -1 on failure (invalid hex string)
169189251Ssam */
170189251Ssamint hexstr2bin(const char *hex, u8 *buf, size_t len)
171189251Ssam{
172189251Ssam	size_t i;
173189251Ssam	int a;
174189251Ssam	const char *ipos = hex;
175189251Ssam	u8 *opos = buf;
176189251Ssam
177189251Ssam	for (i = 0; i < len; i++) {
178189251Ssam		a = hex2byte(ipos);
179189251Ssam		if (a < 0)
180189251Ssam			return -1;
181189251Ssam		*opos++ = a;
182189251Ssam		ipos += 2;
183189251Ssam	}
184189251Ssam	return 0;
185189251Ssam}
186189251Ssam
187189251Ssam
188281806Srpauloint hwaddr_mask_txt(char *buf, size_t len, const u8 *addr, const u8 *mask)
189281806Srpaulo{
190281806Srpaulo	size_t i;
191281806Srpaulo	int print_mask = 0;
192281806Srpaulo	int res;
193281806Srpaulo
194281806Srpaulo	for (i = 0; i < ETH_ALEN; i++) {
195281806Srpaulo		if (mask[i] != 0xff) {
196281806Srpaulo			print_mask = 1;
197281806Srpaulo			break;
198281806Srpaulo		}
199281806Srpaulo	}
200281806Srpaulo
201281806Srpaulo	if (print_mask)
202281806Srpaulo		res = os_snprintf(buf, len, MACSTR "/" MACSTR,
203281806Srpaulo				  MAC2STR(addr), MAC2STR(mask));
204281806Srpaulo	else
205281806Srpaulo		res = os_snprintf(buf, len, MACSTR, MAC2STR(addr));
206281806Srpaulo	if (os_snprintf_error(len, res))
207281806Srpaulo		return -1;
208281806Srpaulo	return res;
209281806Srpaulo}
210281806Srpaulo
211281806Srpaulo
212189251Ssam/**
213189251Ssam * inc_byte_array - Increment arbitrary length byte array by one
214189251Ssam * @counter: Pointer to byte array
215189251Ssam * @len: Length of the counter in bytes
216189251Ssam *
217189251Ssam * This function increments the last byte of the counter by one and continues
218189251Ssam * rolling over to more significant bytes if the byte was incremented from
219189251Ssam * 0xff to 0x00.
220189251Ssam */
221189251Ssamvoid inc_byte_array(u8 *counter, size_t len)
222189251Ssam{
223189251Ssam	int pos = len - 1;
224189251Ssam	while (pos >= 0) {
225189251Ssam		counter[pos]++;
226189251Ssam		if (counter[pos] != 0)
227189251Ssam			break;
228189251Ssam		pos--;
229189251Ssam	}
230189251Ssam}
231189251Ssam
232189251Ssam
233351611Scyvoid buf_shift_right(u8 *buf, size_t len, size_t bits)
234351611Scy{
235351611Scy	size_t i;
236351611Scy
237351611Scy	for (i = len - 1; i > 0; i--)
238351611Scy		buf[i] = (buf[i - 1] << (8 - bits)) | (buf[i] >> bits);
239351611Scy	buf[0] >>= bits;
240351611Scy}
241351611Scy
242351611Scy
243189251Ssamvoid wpa_get_ntp_timestamp(u8 *buf)
244189251Ssam{
245189251Ssam	struct os_time now;
246189251Ssam	u32 sec, usec;
247189251Ssam	be32 tmp;
248189251Ssam
249189251Ssam	/* 64-bit NTP timestamp (time from 1900-01-01 00:00:00) */
250189251Ssam	os_get_time(&now);
251189251Ssam	sec = now.sec + 2208988800U; /* Epoch to 1900 */
252189251Ssam	/* Estimate 2^32/10^6 = 4295 - 1/32 - 1/512 */
253189251Ssam	usec = now.usec;
254189251Ssam	usec = 4295 * usec - (usec >> 5) - (usec >> 9);
255189251Ssam	tmp = host_to_be32(sec);
256189251Ssam	os_memcpy(buf, (u8 *) &tmp, 4);
257189251Ssam	tmp = host_to_be32(usec);
258189251Ssam	os_memcpy(buf + 4, (u8 *) &tmp, 4);
259189251Ssam}
260189251Ssam
261281806Srpaulo/**
262281806Srpaulo * wpa_scnprintf - Simpler-to-use snprintf function
263281806Srpaulo * @buf: Output buffer
264281806Srpaulo * @size: Buffer size
265281806Srpaulo * @fmt: format
266281806Srpaulo *
267281806Srpaulo * Simpler snprintf version that doesn't require further error checks - the
268281806Srpaulo * return value only indicates how many bytes were actually written, excluding
269281806Srpaulo * the NULL byte (i.e., 0 on error, size-1 if buffer is not big enough).
270281806Srpaulo */
271281806Srpauloint wpa_scnprintf(char *buf, size_t size, const char *fmt, ...)
272281806Srpaulo{
273281806Srpaulo	va_list ap;
274281806Srpaulo	int ret;
275189251Ssam
276281806Srpaulo	if (!size)
277281806Srpaulo		return 0;
278281806Srpaulo
279281806Srpaulo	va_start(ap, fmt);
280281806Srpaulo	ret = vsnprintf(buf, size, fmt, ap);
281281806Srpaulo	va_end(ap);
282281806Srpaulo
283281806Srpaulo	if (ret < 0)
284281806Srpaulo		return 0;
285281806Srpaulo	if ((size_t) ret >= size)
286281806Srpaulo		return size - 1;
287281806Srpaulo
288281806Srpaulo	return ret;
289281806Srpaulo}
290281806Srpaulo
291289549Srpaulo
292289549Srpauloint wpa_snprintf_hex_sep(char *buf, size_t buf_size, const u8 *data, size_t len,
293289549Srpaulo			 char sep)
294289549Srpaulo{
295289549Srpaulo	size_t i;
296289549Srpaulo	char *pos = buf, *end = buf + buf_size;
297289549Srpaulo	int ret;
298289549Srpaulo
299289549Srpaulo	if (buf_size == 0)
300289549Srpaulo		return 0;
301289549Srpaulo
302289549Srpaulo	for (i = 0; i < len; i++) {
303289549Srpaulo		ret = os_snprintf(pos, end - pos, "%02x%c",
304289549Srpaulo				  data[i], sep);
305289549Srpaulo		if (os_snprintf_error(end - pos, ret)) {
306289549Srpaulo			end[-1] = '\0';
307289549Srpaulo			return pos - buf;
308289549Srpaulo		}
309289549Srpaulo		pos += ret;
310289549Srpaulo	}
311289549Srpaulo	pos[-1] = '\0';
312289549Srpaulo	return pos - buf;
313289549Srpaulo}
314289549Srpaulo
315289549Srpaulo
316189251Ssamstatic inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data,
317189251Ssam				    size_t len, int uppercase)
318189251Ssam{
319189251Ssam	size_t i;
320189251Ssam	char *pos = buf, *end = buf + buf_size;
321189251Ssam	int ret;
322189251Ssam	if (buf_size == 0)
323189251Ssam		return 0;
324189251Ssam	for (i = 0; i < len; i++) {
325189251Ssam		ret = os_snprintf(pos, end - pos, uppercase ? "%02X" : "%02x",
326189251Ssam				  data[i]);
327281806Srpaulo		if (os_snprintf_error(end - pos, ret)) {
328189251Ssam			end[-1] = '\0';
329189251Ssam			return pos - buf;
330189251Ssam		}
331189251Ssam		pos += ret;
332189251Ssam	}
333189251Ssam	end[-1] = '\0';
334189251Ssam	return pos - buf;
335189251Ssam}
336189251Ssam
337189251Ssam/**
338189251Ssam * wpa_snprintf_hex - Print data as a hex string into a buffer
339189251Ssam * @buf: Memory area to use as the output buffer
340189251Ssam * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1)
341189251Ssam * @data: Data to be printed
342189251Ssam * @len: Length of data in bytes
343189251Ssam * Returns: Number of bytes written
344189251Ssam */
345189251Ssamint wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len)
346189251Ssam{
347189251Ssam	return _wpa_snprintf_hex(buf, buf_size, data, len, 0);
348189251Ssam}
349189251Ssam
350189251Ssam
351189251Ssam/**
352189251Ssam * wpa_snprintf_hex_uppercase - Print data as a upper case hex string into buf
353189251Ssam * @buf: Memory area to use as the output buffer
354189251Ssam * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1)
355189251Ssam * @data: Data to be printed
356189251Ssam * @len: Length of data in bytes
357189251Ssam * Returns: Number of bytes written
358189251Ssam */
359189251Ssamint wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data,
360189251Ssam			       size_t len)
361189251Ssam{
362189251Ssam	return _wpa_snprintf_hex(buf, buf_size, data, len, 1);
363189251Ssam}
364189251Ssam
365189251Ssam
366189251Ssam#ifdef CONFIG_ANSI_C_EXTRA
367189251Ssam
368189251Ssam#ifdef _WIN32_WCE
369189251Ssamvoid perror(const char *s)
370189251Ssam{
371189251Ssam	wpa_printf(MSG_ERROR, "%s: GetLastError: %d",
372189251Ssam		   s, (int) GetLastError());
373189251Ssam}
374189251Ssam#endif /* _WIN32_WCE */
375189251Ssam
376189251Ssam
377189251Ssamint optind = 1;
378189251Ssamint optopt;
379189251Ssamchar *optarg;
380189251Ssam
381189251Ssamint getopt(int argc, char *const argv[], const char *optstring)
382189251Ssam{
383189251Ssam	static int optchr = 1;
384189251Ssam	char *cp;
385189251Ssam
386189251Ssam	if (optchr == 1) {
387189251Ssam		if (optind >= argc) {
388189251Ssam			/* all arguments processed */
389189251Ssam			return EOF;
390189251Ssam		}
391189251Ssam
392189251Ssam		if (argv[optind][0] != '-' || argv[optind][1] == '\0') {
393189251Ssam			/* no option characters */
394189251Ssam			return EOF;
395189251Ssam		}
396189251Ssam	}
397189251Ssam
398189251Ssam	if (os_strcmp(argv[optind], "--") == 0) {
399189251Ssam		/* no more options */
400189251Ssam		optind++;
401189251Ssam		return EOF;
402189251Ssam	}
403189251Ssam
404189251Ssam	optopt = argv[optind][optchr];
405189251Ssam	cp = os_strchr(optstring, optopt);
406189251Ssam	if (cp == NULL || optopt == ':') {
407189251Ssam		if (argv[optind][++optchr] == '\0') {
408189251Ssam			optchr = 1;
409189251Ssam			optind++;
410189251Ssam		}
411189251Ssam		return '?';
412189251Ssam	}
413189251Ssam
414189251Ssam	if (cp[1] == ':') {
415189251Ssam		/* Argument required */
416189251Ssam		optchr = 1;
417189251Ssam		if (argv[optind][optchr + 1]) {
418189251Ssam			/* No space between option and argument */
419189251Ssam			optarg = &argv[optind++][optchr + 1];
420189251Ssam		} else if (++optind >= argc) {
421189251Ssam			/* option requires an argument */
422189251Ssam			return '?';
423189251Ssam		} else {
424189251Ssam			/* Argument in the next argv */
425189251Ssam			optarg = argv[optind++];
426189251Ssam		}
427189251Ssam	} else {
428189251Ssam		/* No argument */
429189251Ssam		if (argv[optind][++optchr] == '\0') {
430189251Ssam			optchr = 1;
431189251Ssam			optind++;
432189251Ssam		}
433189251Ssam		optarg = NULL;
434189251Ssam	}
435189251Ssam	return *cp;
436189251Ssam}
437189251Ssam#endif /* CONFIG_ANSI_C_EXTRA */
438189251Ssam
439189251Ssam
440189251Ssam#ifdef CONFIG_NATIVE_WINDOWS
441189251Ssam/**
442189251Ssam * wpa_unicode2ascii_inplace - Convert unicode string into ASCII
443189251Ssam * @str: Pointer to string to convert
444189251Ssam *
445189251Ssam * This function converts a unicode string to ASCII using the same
446189251Ssam * buffer for output. If UNICODE is not set, the buffer is not
447189251Ssam * modified.
448189251Ssam */
449189251Ssamvoid wpa_unicode2ascii_inplace(TCHAR *str)
450189251Ssam{
451189251Ssam#ifdef UNICODE
452189251Ssam	char *dst = (char *) str;
453189251Ssam	while (*str)
454189251Ssam		*dst++ = (char) *str++;
455189251Ssam	*dst = '\0';
456189251Ssam#endif /* UNICODE */
457189251Ssam}
458189251Ssam
459189251Ssam
460189251SsamTCHAR * wpa_strdup_tchar(const char *str)
461189251Ssam{
462189251Ssam#ifdef UNICODE
463189251Ssam	TCHAR *buf;
464189251Ssam	buf = os_malloc((strlen(str) + 1) * sizeof(TCHAR));
465189251Ssam	if (buf == NULL)
466189251Ssam		return NULL;
467189251Ssam	wsprintf(buf, L"%S", str);
468189251Ssam	return buf;
469189251Ssam#else /* UNICODE */
470189251Ssam	return os_strdup(str);
471189251Ssam#endif /* UNICODE */
472189251Ssam}
473189251Ssam#endif /* CONFIG_NATIVE_WINDOWS */
474189251Ssam
475189251Ssam
476252726Srpaulovoid printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len)
477252726Srpaulo{
478252726Srpaulo	char *end = txt + maxlen;
479252726Srpaulo	size_t i;
480252726Srpaulo
481252726Srpaulo	for (i = 0; i < len; i++) {
482281806Srpaulo		if (txt + 4 >= end)
483252726Srpaulo			break;
484252726Srpaulo
485252726Srpaulo		switch (data[i]) {
486252726Srpaulo		case '\"':
487252726Srpaulo			*txt++ = '\\';
488252726Srpaulo			*txt++ = '\"';
489252726Srpaulo			break;
490252726Srpaulo		case '\\':
491252726Srpaulo			*txt++ = '\\';
492252726Srpaulo			*txt++ = '\\';
493252726Srpaulo			break;
494281806Srpaulo		case '\033':
495252726Srpaulo			*txt++ = '\\';
496252726Srpaulo			*txt++ = 'e';
497252726Srpaulo			break;
498252726Srpaulo		case '\n':
499252726Srpaulo			*txt++ = '\\';
500252726Srpaulo			*txt++ = 'n';
501252726Srpaulo			break;
502252726Srpaulo		case '\r':
503252726Srpaulo			*txt++ = '\\';
504252726Srpaulo			*txt++ = 'r';
505252726Srpaulo			break;
506252726Srpaulo		case '\t':
507252726Srpaulo			*txt++ = '\\';
508252726Srpaulo			*txt++ = 't';
509252726Srpaulo			break;
510252726Srpaulo		default:
511337817Scy			if (data[i] >= 32 && data[i] <= 126) {
512252726Srpaulo				*txt++ = data[i];
513252726Srpaulo			} else {
514252726Srpaulo				txt += os_snprintf(txt, end - txt, "\\x%02x",
515252726Srpaulo						   data[i]);
516252726Srpaulo			}
517252726Srpaulo			break;
518252726Srpaulo		}
519252726Srpaulo	}
520252726Srpaulo
521252726Srpaulo	*txt = '\0';
522252726Srpaulo}
523252726Srpaulo
524252726Srpaulo
525252726Srpaulosize_t printf_decode(u8 *buf, size_t maxlen, const char *str)
526252726Srpaulo{
527252726Srpaulo	const char *pos = str;
528252726Srpaulo	size_t len = 0;
529252726Srpaulo	int val;
530252726Srpaulo
531252726Srpaulo	while (*pos) {
532281806Srpaulo		if (len + 1 >= maxlen)
533252726Srpaulo			break;
534252726Srpaulo		switch (*pos) {
535252726Srpaulo		case '\\':
536252726Srpaulo			pos++;
537252726Srpaulo			switch (*pos) {
538252726Srpaulo			case '\\':
539252726Srpaulo				buf[len++] = '\\';
540252726Srpaulo				pos++;
541252726Srpaulo				break;
542252726Srpaulo			case '"':
543252726Srpaulo				buf[len++] = '"';
544252726Srpaulo				pos++;
545252726Srpaulo				break;
546252726Srpaulo			case 'n':
547252726Srpaulo				buf[len++] = '\n';
548252726Srpaulo				pos++;
549252726Srpaulo				break;
550252726Srpaulo			case 'r':
551252726Srpaulo				buf[len++] = '\r';
552252726Srpaulo				pos++;
553252726Srpaulo				break;
554252726Srpaulo			case 't':
555252726Srpaulo				buf[len++] = '\t';
556252726Srpaulo				pos++;
557252726Srpaulo				break;
558252726Srpaulo			case 'e':
559281806Srpaulo				buf[len++] = '\033';
560252726Srpaulo				pos++;
561252726Srpaulo				break;
562252726Srpaulo			case 'x':
563252726Srpaulo				pos++;
564252726Srpaulo				val = hex2byte(pos);
565252726Srpaulo				if (val < 0) {
566252726Srpaulo					val = hex2num(*pos);
567252726Srpaulo					if (val < 0)
568252726Srpaulo						break;
569252726Srpaulo					buf[len++] = val;
570252726Srpaulo					pos++;
571252726Srpaulo				} else {
572252726Srpaulo					buf[len++] = val;
573252726Srpaulo					pos += 2;
574252726Srpaulo				}
575252726Srpaulo				break;
576252726Srpaulo			case '0':
577252726Srpaulo			case '1':
578252726Srpaulo			case '2':
579252726Srpaulo			case '3':
580252726Srpaulo			case '4':
581252726Srpaulo			case '5':
582252726Srpaulo			case '6':
583252726Srpaulo			case '7':
584252726Srpaulo				val = *pos++ - '0';
585252726Srpaulo				if (*pos >= '0' && *pos <= '7')
586252726Srpaulo					val = val * 8 + (*pos++ - '0');
587252726Srpaulo				if (*pos >= '0' && *pos <= '7')
588252726Srpaulo					val = val * 8 + (*pos++ - '0');
589252726Srpaulo				buf[len++] = val;
590252726Srpaulo				break;
591252726Srpaulo			default:
592252726Srpaulo				break;
593252726Srpaulo			}
594252726Srpaulo			break;
595252726Srpaulo		default:
596252726Srpaulo			buf[len++] = *pos++;
597252726Srpaulo			break;
598252726Srpaulo		}
599252726Srpaulo	}
600281806Srpaulo	if (maxlen > len)
601281806Srpaulo		buf[len] = '\0';
602252726Srpaulo
603252726Srpaulo	return len;
604252726Srpaulo}
605252726Srpaulo
606252726Srpaulo
607189251Ssam/**
608189251Ssam * wpa_ssid_txt - Convert SSID to a printable string
609189251Ssam * @ssid: SSID (32-octet string)
610189251Ssam * @ssid_len: Length of ssid in octets
611189251Ssam * Returns: Pointer to a printable string
612189251Ssam *
613189251Ssam * This function can be used to convert SSIDs into printable form. In most
614189251Ssam * cases, SSIDs do not use unprintable characters, but IEEE 802.11 standard
615189251Ssam * does not limit the used character set, so anything could be used in an SSID.
616189251Ssam *
617189251Ssam * This function uses a static buffer, so only one call can be used at the
618189251Ssam * time, i.e., this is not re-entrant and the returned buffer must be used
619189251Ssam * before calling this again.
620189251Ssam */
621189251Ssamconst char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len)
622189251Ssam{
623289549Srpaulo	static char ssid_txt[SSID_MAX_LEN * 4 + 1];
624189251Ssam
625252726Srpaulo	if (ssid == NULL) {
626252726Srpaulo		ssid_txt[0] = '\0';
627252726Srpaulo		return ssid_txt;
628189251Ssam	}
629252726Srpaulo
630252726Srpaulo	printf_encode(ssid_txt, sizeof(ssid_txt), ssid, ssid_len);
631189251Ssam	return ssid_txt;
632189251Ssam}
633209158Srpaulo
634209158Srpaulo
635209158Srpaulovoid * __hide_aliasing_typecast(void *foo)
636209158Srpaulo{
637209158Srpaulo	return foo;
638209158Srpaulo}
639252726Srpaulo
640252726Srpaulo
641252726Srpaulochar * wpa_config_parse_string(const char *value, size_t *len)
642252726Srpaulo{
643252726Srpaulo	if (*value == '"') {
644252726Srpaulo		const char *pos;
645252726Srpaulo		char *str;
646252726Srpaulo		value++;
647252726Srpaulo		pos = os_strrchr(value, '"');
648252726Srpaulo		if (pos == NULL || pos[1] != '\0')
649252726Srpaulo			return NULL;
650252726Srpaulo		*len = pos - value;
651281806Srpaulo		str = dup_binstr(value, *len);
652252726Srpaulo		if (str == NULL)
653252726Srpaulo			return NULL;
654252726Srpaulo		return str;
655252726Srpaulo	} else if (*value == 'P' && value[1] == '"') {
656252726Srpaulo		const char *pos;
657252726Srpaulo		char *tstr, *str;
658252726Srpaulo		size_t tlen;
659252726Srpaulo		value += 2;
660252726Srpaulo		pos = os_strrchr(value, '"');
661252726Srpaulo		if (pos == NULL || pos[1] != '\0')
662252726Srpaulo			return NULL;
663252726Srpaulo		tlen = pos - value;
664281806Srpaulo		tstr = dup_binstr(value, tlen);
665252726Srpaulo		if (tstr == NULL)
666252726Srpaulo			return NULL;
667252726Srpaulo
668252726Srpaulo		str = os_malloc(tlen + 1);
669252726Srpaulo		if (str == NULL) {
670252726Srpaulo			os_free(tstr);
671252726Srpaulo			return NULL;
672252726Srpaulo		}
673252726Srpaulo
674252726Srpaulo		*len = printf_decode((u8 *) str, tlen + 1, tstr);
675252726Srpaulo		os_free(tstr);
676252726Srpaulo
677252726Srpaulo		return str;
678252726Srpaulo	} else {
679252726Srpaulo		u8 *str;
680252726Srpaulo		size_t tlen, hlen = os_strlen(value);
681252726Srpaulo		if (hlen & 1)
682252726Srpaulo			return NULL;
683252726Srpaulo		tlen = hlen / 2;
684252726Srpaulo		str = os_malloc(tlen + 1);
685252726Srpaulo		if (str == NULL)
686252726Srpaulo			return NULL;
687252726Srpaulo		if (hexstr2bin(value, str, tlen)) {
688252726Srpaulo			os_free(str);
689252726Srpaulo			return NULL;
690252726Srpaulo		}
691252726Srpaulo		str[tlen] = '\0';
692252726Srpaulo		*len = tlen;
693252726Srpaulo		return (char *) str;
694252726Srpaulo	}
695252726Srpaulo}
696252726Srpaulo
697252726Srpaulo
698252726Srpauloint is_hex(const u8 *data, size_t len)
699252726Srpaulo{
700252726Srpaulo	size_t i;
701252726Srpaulo
702252726Srpaulo	for (i = 0; i < len; i++) {
703252726Srpaulo		if (data[i] < 32 || data[i] >= 127)
704252726Srpaulo			return 1;
705252726Srpaulo	}
706252726Srpaulo	return 0;
707252726Srpaulo}
708252726Srpaulo
709252726Srpaulo
710337817Scyint has_ctrl_char(const u8 *data, size_t len)
711337817Scy{
712337817Scy	size_t i;
713337817Scy
714337817Scy	for (i = 0; i < len; i++) {
715337817Scy		if (data[i] < 32 || data[i] == 127)
716337817Scy			return 1;
717337817Scy	}
718337817Scy	return 0;
719337817Scy}
720337817Scy
721337817Scy
722337817Scyint has_newline(const char *str)
723337817Scy{
724337817Scy	while (*str) {
725337817Scy		if (*str == '\n' || *str == '\r')
726337817Scy			return 1;
727337817Scy		str++;
728337817Scy	}
729337817Scy	return 0;
730337817Scy}
731337817Scy
732337817Scy
733252726Srpaulosize_t merge_byte_arrays(u8 *res, size_t res_len,
734252726Srpaulo			 const u8 *src1, size_t src1_len,
735252726Srpaulo			 const u8 *src2, size_t src2_len)
736252726Srpaulo{
737252726Srpaulo	size_t len = 0;
738252726Srpaulo
739252726Srpaulo	os_memset(res, 0, res_len);
740252726Srpaulo
741252726Srpaulo	if (src1) {
742252726Srpaulo		if (src1_len >= res_len) {
743252726Srpaulo			os_memcpy(res, src1, res_len);
744252726Srpaulo			return res_len;
745252726Srpaulo		}
746252726Srpaulo
747252726Srpaulo		os_memcpy(res, src1, src1_len);
748252726Srpaulo		len += src1_len;
749252726Srpaulo	}
750252726Srpaulo
751252726Srpaulo	if (src2) {
752252726Srpaulo		if (len + src2_len >= res_len) {
753252726Srpaulo			os_memcpy(res + len, src2, res_len - len);
754252726Srpaulo			return res_len;
755252726Srpaulo		}
756252726Srpaulo
757252726Srpaulo		os_memcpy(res + len, src2, src2_len);
758252726Srpaulo		len += src2_len;
759252726Srpaulo	}
760252726Srpaulo
761252726Srpaulo	return len;
762252726Srpaulo}
763281806Srpaulo
764281806Srpaulo
765281806Srpaulochar * dup_binstr(const void *src, size_t len)
766281806Srpaulo{
767281806Srpaulo	char *res;
768281806Srpaulo
769281806Srpaulo	if (src == NULL)
770281806Srpaulo		return NULL;
771281806Srpaulo	res = os_malloc(len + 1);
772281806Srpaulo	if (res == NULL)
773281806Srpaulo		return NULL;
774281806Srpaulo	os_memcpy(res, src, len);
775281806Srpaulo	res[len] = '\0';
776281806Srpaulo
777281806Srpaulo	return res;
778281806Srpaulo}
779281806Srpaulo
780281806Srpaulo
781281806Srpauloint freq_range_list_parse(struct wpa_freq_range_list *res, const char *value)
782281806Srpaulo{
783281806Srpaulo	struct wpa_freq_range *freq = NULL, *n;
784281806Srpaulo	unsigned int count = 0;
785281806Srpaulo	const char *pos, *pos2, *pos3;
786281806Srpaulo
787281806Srpaulo	/*
788281806Srpaulo	 * Comma separated list of frequency ranges.
789281806Srpaulo	 * For example: 2412-2432,2462,5000-6000
790281806Srpaulo	 */
791281806Srpaulo	pos = value;
792281806Srpaulo	while (pos && pos[0]) {
793281806Srpaulo		n = os_realloc_array(freq, count + 1,
794281806Srpaulo				     sizeof(struct wpa_freq_range));
795281806Srpaulo		if (n == NULL) {
796281806Srpaulo			os_free(freq);
797281806Srpaulo			return -1;
798281806Srpaulo		}
799281806Srpaulo		freq = n;
800281806Srpaulo		freq[count].min = atoi(pos);
801281806Srpaulo		pos2 = os_strchr(pos, '-');
802281806Srpaulo		pos3 = os_strchr(pos, ',');
803281806Srpaulo		if (pos2 && (!pos3 || pos2 < pos3)) {
804281806Srpaulo			pos2++;
805281806Srpaulo			freq[count].max = atoi(pos2);
806281806Srpaulo		} else
807281806Srpaulo			freq[count].max = freq[count].min;
808281806Srpaulo		pos = pos3;
809281806Srpaulo		if (pos)
810281806Srpaulo			pos++;
811281806Srpaulo		count++;
812281806Srpaulo	}
813281806Srpaulo
814281806Srpaulo	os_free(res->range);
815281806Srpaulo	res->range = freq;
816281806Srpaulo	res->num = count;
817281806Srpaulo
818281806Srpaulo	return 0;
819281806Srpaulo}
820281806Srpaulo
821281806Srpaulo
822281806Srpauloint freq_range_list_includes(const struct wpa_freq_range_list *list,
823281806Srpaulo			     unsigned int freq)
824281806Srpaulo{
825281806Srpaulo	unsigned int i;
826281806Srpaulo
827281806Srpaulo	if (list == NULL)
828281806Srpaulo		return 0;
829281806Srpaulo
830281806Srpaulo	for (i = 0; i < list->num; i++) {
831281806Srpaulo		if (freq >= list->range[i].min && freq <= list->range[i].max)
832281806Srpaulo			return 1;
833281806Srpaulo	}
834281806Srpaulo
835281806Srpaulo	return 0;
836281806Srpaulo}
837281806Srpaulo
838281806Srpaulo
839281806Srpaulochar * freq_range_list_str(const struct wpa_freq_range_list *list)
840281806Srpaulo{
841281806Srpaulo	char *buf, *pos, *end;
842281806Srpaulo	size_t maxlen;
843281806Srpaulo	unsigned int i;
844281806Srpaulo	int res;
845281806Srpaulo
846281806Srpaulo	if (list->num == 0)
847281806Srpaulo		return NULL;
848281806Srpaulo
849281806Srpaulo	maxlen = list->num * 30;
850281806Srpaulo	buf = os_malloc(maxlen);
851281806Srpaulo	if (buf == NULL)
852281806Srpaulo		return NULL;
853281806Srpaulo	pos = buf;
854281806Srpaulo	end = buf + maxlen;
855281806Srpaulo
856281806Srpaulo	for (i = 0; i < list->num; i++) {
857281806Srpaulo		struct wpa_freq_range *range = &list->range[i];
858281806Srpaulo
859281806Srpaulo		if (range->min == range->max)
860281806Srpaulo			res = os_snprintf(pos, end - pos, "%s%u",
861281806Srpaulo					  i == 0 ? "" : ",", range->min);
862281806Srpaulo		else
863281806Srpaulo			res = os_snprintf(pos, end - pos, "%s%u-%u",
864281806Srpaulo					  i == 0 ? "" : ",",
865281806Srpaulo					  range->min, range->max);
866281806Srpaulo		if (os_snprintf_error(end - pos, res)) {
867281806Srpaulo			os_free(buf);
868281806Srpaulo			return NULL;
869281806Srpaulo		}
870281806Srpaulo		pos += res;
871281806Srpaulo	}
872281806Srpaulo
873281806Srpaulo	return buf;
874281806Srpaulo}
875281806Srpaulo
876281806Srpaulo
877281806Srpauloint int_array_len(const int *a)
878281806Srpaulo{
879281806Srpaulo	int i;
880281806Srpaulo	for (i = 0; a && a[i]; i++)
881281806Srpaulo		;
882281806Srpaulo	return i;
883281806Srpaulo}
884281806Srpaulo
885281806Srpaulo
886281806Srpaulovoid int_array_concat(int **res, const int *a)
887281806Srpaulo{
888281806Srpaulo	int reslen, alen, i;
889281806Srpaulo	int *n;
890281806Srpaulo
891281806Srpaulo	reslen = int_array_len(*res);
892281806Srpaulo	alen = int_array_len(a);
893281806Srpaulo
894281806Srpaulo	n = os_realloc_array(*res, reslen + alen + 1, sizeof(int));
895281806Srpaulo	if (n == NULL) {
896281806Srpaulo		os_free(*res);
897281806Srpaulo		*res = NULL;
898281806Srpaulo		return;
899281806Srpaulo	}
900281806Srpaulo	for (i = 0; i <= alen; i++)
901281806Srpaulo		n[reslen + i] = a[i];
902281806Srpaulo	*res = n;
903281806Srpaulo}
904281806Srpaulo
905281806Srpaulo
906281806Srpaulostatic int freq_cmp(const void *a, const void *b)
907281806Srpaulo{
908281806Srpaulo	int _a = *(int *) a;
909281806Srpaulo	int _b = *(int *) b;
910281806Srpaulo
911281806Srpaulo	if (_a == 0)
912281806Srpaulo		return 1;
913281806Srpaulo	if (_b == 0)
914281806Srpaulo		return -1;
915281806Srpaulo	return _a - _b;
916281806Srpaulo}
917281806Srpaulo
918281806Srpaulo
919281806Srpaulovoid int_array_sort_unique(int *a)
920281806Srpaulo{
921281806Srpaulo	int alen;
922281806Srpaulo	int i, j;
923281806Srpaulo
924281806Srpaulo	if (a == NULL)
925281806Srpaulo		return;
926281806Srpaulo
927281806Srpaulo	alen = int_array_len(a);
928281806Srpaulo	qsort(a, alen, sizeof(int), freq_cmp);
929281806Srpaulo
930281806Srpaulo	i = 0;
931281806Srpaulo	j = 1;
932281806Srpaulo	while (a[i] && a[j]) {
933281806Srpaulo		if (a[i] == a[j]) {
934281806Srpaulo			j++;
935281806Srpaulo			continue;
936281806Srpaulo		}
937281806Srpaulo		a[++i] = a[j++];
938281806Srpaulo	}
939281806Srpaulo	if (a[i])
940281806Srpaulo		i++;
941281806Srpaulo	a[i] = 0;
942281806Srpaulo}
943281806Srpaulo
944281806Srpaulo
945281806Srpaulovoid int_array_add_unique(int **res, int a)
946281806Srpaulo{
947281806Srpaulo	int reslen;
948281806Srpaulo	int *n;
949281806Srpaulo
950281806Srpaulo	for (reslen = 0; *res && (*res)[reslen]; reslen++) {
951281806Srpaulo		if ((*res)[reslen] == a)
952281806Srpaulo			return; /* already in the list */
953281806Srpaulo	}
954281806Srpaulo
955281806Srpaulo	n = os_realloc_array(*res, reslen + 2, sizeof(int));
956281806Srpaulo	if (n == NULL) {
957281806Srpaulo		os_free(*res);
958281806Srpaulo		*res = NULL;
959281806Srpaulo		return;
960281806Srpaulo	}
961281806Srpaulo
962281806Srpaulo	n[reslen] = a;
963281806Srpaulo	n[reslen + 1] = 0;
964281806Srpaulo
965281806Srpaulo	*res = n;
966281806Srpaulo}
967281806Srpaulo
968281806Srpaulo
969281806Srpaulovoid str_clear_free(char *str)
970281806Srpaulo{
971281806Srpaulo	if (str) {
972281806Srpaulo		size_t len = os_strlen(str);
973351611Scy		forced_memzero(str, len);
974281806Srpaulo		os_free(str);
975281806Srpaulo	}
976281806Srpaulo}
977281806Srpaulo
978281806Srpaulo
979281806Srpaulovoid bin_clear_free(void *bin, size_t len)
980281806Srpaulo{
981281806Srpaulo	if (bin) {
982351611Scy		forced_memzero(bin, len);
983281806Srpaulo		os_free(bin);
984281806Srpaulo	}
985281806Srpaulo}
986281806Srpaulo
987281806Srpaulo
988281806Srpauloint random_mac_addr(u8 *addr)
989281806Srpaulo{
990281806Srpaulo	if (os_get_random(addr, ETH_ALEN) < 0)
991281806Srpaulo		return -1;
992281806Srpaulo	addr[0] &= 0xfe; /* unicast */
993281806Srpaulo	addr[0] |= 0x02; /* locally administered */
994281806Srpaulo	return 0;
995281806Srpaulo}
996281806Srpaulo
997281806Srpaulo
998281806Srpauloint random_mac_addr_keep_oui(u8 *addr)
999281806Srpaulo{
1000281806Srpaulo	if (os_get_random(addr + 3, 3) < 0)
1001281806Srpaulo		return -1;
1002281806Srpaulo	addr[0] &= 0xfe; /* unicast */
1003281806Srpaulo	addr[0] |= 0x02; /* locally administered */
1004281806Srpaulo	return 0;
1005281806Srpaulo}
1006281806Srpaulo
1007281806Srpaulo
1008281806Srpaulo/**
1009289549Srpaulo * cstr_token - Get next token from const char string
1010289549Srpaulo * @str: a constant string to tokenize
1011289549Srpaulo * @delim: a string of delimiters
1012289549Srpaulo * @last: a pointer to a character following the returned token
1013289549Srpaulo *      It has to be set to NULL for the first call and passed for any
1014337817Scy *      further call.
1015289549Srpaulo * Returns: a pointer to token position in str or NULL
1016289549Srpaulo *
1017289549Srpaulo * This function is similar to str_token, but it can be used with both
1018289549Srpaulo * char and const char strings. Differences:
1019289549Srpaulo * - The str buffer remains unmodified
1020289549Srpaulo * - The returned token is not a NULL terminated string, but a token
1021289549Srpaulo *   position in str buffer. If a return value is not NULL a size
1022289549Srpaulo *   of the returned token could be calculated as (last - token).
1023289549Srpaulo */
1024289549Srpauloconst char * cstr_token(const char *str, const char *delim, const char **last)
1025289549Srpaulo{
1026289549Srpaulo	const char *end, *token = str;
1027289549Srpaulo
1028289549Srpaulo	if (!str || !delim || !last)
1029289549Srpaulo		return NULL;
1030289549Srpaulo
1031289549Srpaulo	if (*last)
1032289549Srpaulo		token = *last;
1033289549Srpaulo
1034289549Srpaulo	while (*token && os_strchr(delim, *token))
1035289549Srpaulo		token++;
1036289549Srpaulo
1037289549Srpaulo	if (!*token)
1038289549Srpaulo		return NULL;
1039289549Srpaulo
1040289549Srpaulo	end = token + 1;
1041289549Srpaulo
1042289549Srpaulo	while (*end && !os_strchr(delim, *end))
1043289549Srpaulo		end++;
1044289549Srpaulo
1045289549Srpaulo	*last = end;
1046289549Srpaulo	return token;
1047289549Srpaulo}
1048289549Srpaulo
1049289549Srpaulo
1050289549Srpaulo/**
1051281806Srpaulo * str_token - Get next token from a string
1052281806Srpaulo * @buf: String to tokenize. Note that the string might be modified.
1053281806Srpaulo * @delim: String of delimiters
1054281806Srpaulo * @context: Pointer to save our context. Should be initialized with
1055281806Srpaulo *	NULL on the first call, and passed for any further call.
1056281806Srpaulo * Returns: The next token, NULL if there are no more valid tokens.
1057281806Srpaulo */
1058281806Srpaulochar * str_token(char *str, const char *delim, char **context)
1059281806Srpaulo{
1060289549Srpaulo	char *token = (char *) cstr_token(str, delim, (const char **) context);
1061281806Srpaulo
1062289549Srpaulo	if (token && **context)
1063289549Srpaulo		*(*context)++ = '\0';
1064281806Srpaulo
1065289549Srpaulo	return token;
1066281806Srpaulo}
1067281806Srpaulo
1068281806Srpaulo
1069281806Srpaulosize_t utf8_unescape(const char *inp, size_t in_size,
1070281806Srpaulo		     char *outp, size_t out_size)
1071281806Srpaulo{
1072281806Srpaulo	size_t res_size = 0;
1073281806Srpaulo
1074281806Srpaulo	if (!inp || !outp)
1075281806Srpaulo		return 0;
1076281806Srpaulo
1077281806Srpaulo	if (!in_size)
1078281806Srpaulo		in_size = os_strlen(inp);
1079281806Srpaulo
1080281806Srpaulo	/* Advance past leading single quote */
1081281806Srpaulo	if (*inp == '\'' && in_size) {
1082281806Srpaulo		inp++;
1083281806Srpaulo		in_size--;
1084281806Srpaulo	}
1085281806Srpaulo
1086346981Scy	while (in_size) {
1087346981Scy		in_size--;
1088281806Srpaulo		if (res_size >= out_size)
1089281806Srpaulo			return 0;
1090281806Srpaulo
1091281806Srpaulo		switch (*inp) {
1092281806Srpaulo		case '\'':
1093281806Srpaulo			/* Terminate on bare single quote */
1094281806Srpaulo			*outp = '\0';
1095281806Srpaulo			return res_size;
1096281806Srpaulo
1097281806Srpaulo		case '\\':
1098346981Scy			if (!in_size)
1099281806Srpaulo				return 0;
1100346981Scy			in_size--;
1101281806Srpaulo			inp++;
1102281806Srpaulo			/* fall through */
1103281806Srpaulo
1104281806Srpaulo		default:
1105281806Srpaulo			*outp++ = *inp++;
1106281806Srpaulo			res_size++;
1107281806Srpaulo		}
1108281806Srpaulo	}
1109281806Srpaulo
1110281806Srpaulo	/* NUL terminate if space allows */
1111281806Srpaulo	if (res_size < out_size)
1112281806Srpaulo		*outp = '\0';
1113281806Srpaulo
1114281806Srpaulo	return res_size;
1115281806Srpaulo}
1116281806Srpaulo
1117281806Srpaulo
1118281806Srpaulosize_t utf8_escape(const char *inp, size_t in_size,
1119281806Srpaulo		   char *outp, size_t out_size)
1120281806Srpaulo{
1121281806Srpaulo	size_t res_size = 0;
1122281806Srpaulo
1123281806Srpaulo	if (!inp || !outp)
1124281806Srpaulo		return 0;
1125281806Srpaulo
1126281806Srpaulo	/* inp may or may not be NUL terminated, but must be if 0 size
1127281806Srpaulo	 * is specified */
1128281806Srpaulo	if (!in_size)
1129281806Srpaulo		in_size = os_strlen(inp);
1130281806Srpaulo
1131346981Scy	while (in_size) {
1132346981Scy		in_size--;
1133281806Srpaulo		if (res_size++ >= out_size)
1134281806Srpaulo			return 0;
1135281806Srpaulo
1136281806Srpaulo		switch (*inp) {
1137281806Srpaulo		case '\\':
1138281806Srpaulo		case '\'':
1139281806Srpaulo			if (res_size++ >= out_size)
1140281806Srpaulo				return 0;
1141281806Srpaulo			*outp++ = '\\';
1142281806Srpaulo			/* fall through */
1143281806Srpaulo
1144281806Srpaulo		default:
1145281806Srpaulo			*outp++ = *inp++;
1146281806Srpaulo			break;
1147281806Srpaulo		}
1148281806Srpaulo	}
1149281806Srpaulo
1150281806Srpaulo	/* NUL terminate if space allows */
1151281806Srpaulo	if (res_size < out_size)
1152281806Srpaulo		*outp = '\0';
1153281806Srpaulo
1154281806Srpaulo	return res_size;
1155281806Srpaulo}
1156289549Srpaulo
1157289549Srpaulo
1158289549Srpauloint is_ctrl_char(char c)
1159289549Srpaulo{
1160289549Srpaulo	return c > 0 && c < 32;
1161289549Srpaulo}
1162337817Scy
1163337817Scy
1164337817Scy/**
1165337817Scy * ssid_parse - Parse a string that contains SSID in hex or text format
1166337817Scy * @buf: Input NULL terminated string that contains the SSID
1167337817Scy * @ssid: Output SSID
1168337817Scy * Returns: 0 on success, -1 otherwise
1169337817Scy *
1170337817Scy * The SSID has to be enclosed in double quotes for the text format or space
1171337817Scy * or NULL terminated string of hex digits for the hex format. buf can include
1172337817Scy * additional arguments after the SSID.
1173337817Scy */
1174337817Scyint ssid_parse(const char *buf, struct wpa_ssid_value *ssid)
1175337817Scy{
1176337817Scy	char *tmp, *res, *end;
1177337817Scy	size_t len;
1178337817Scy
1179337817Scy	ssid->ssid_len = 0;
1180337817Scy
1181337817Scy	tmp = os_strdup(buf);
1182337817Scy	if (!tmp)
1183337817Scy		return -1;
1184337817Scy
1185337817Scy	if (*tmp != '"') {
1186337817Scy		end = os_strchr(tmp, ' ');
1187337817Scy		if (end)
1188337817Scy			*end = '\0';
1189337817Scy	} else {
1190337817Scy		end = os_strchr(tmp + 1, '"');
1191337817Scy		if (!end) {
1192337817Scy			os_free(tmp);
1193337817Scy			return -1;
1194337817Scy		}
1195337817Scy
1196337817Scy		end[1] = '\0';
1197337817Scy	}
1198337817Scy
1199337817Scy	res = wpa_config_parse_string(tmp, &len);
1200337817Scy	if (res && len <= SSID_MAX_LEN) {
1201337817Scy		ssid->ssid_len = len;
1202337817Scy		os_memcpy(ssid->ssid, res, len);
1203337817Scy	}
1204337817Scy
1205337817Scy	os_free(tmp);
1206337817Scy	os_free(res);
1207337817Scy
1208337817Scy	return ssid->ssid_len ? 0 : -1;
1209337817Scy}
1210337817Scy
1211337817Scy
1212337817Scyint str_starts(const char *str, const char *start)
1213337817Scy{
1214337817Scy	return os_strncmp(str, start, os_strlen(start)) == 0;
1215337817Scy}
1216346981Scy
1217346981Scy
1218346981Scy/**
1219346981Scy * rssi_to_rcpi - Convert RSSI to RCPI
1220346981Scy * @rssi: RSSI to convert
1221346981Scy * Returns: RCPI corresponding to the given RSSI value, or 255 if not available.
1222346981Scy *
1223346981Scy * It's possible to estimate RCPI based on RSSI in dBm. This calculation will
1224346981Scy * not reflect the correct value for high rates, but it's good enough for Action
1225346981Scy * frames which are transmitted with up to 24 Mbps rates.
1226346981Scy */
1227346981Scyu8 rssi_to_rcpi(int rssi)
1228346981Scy{
1229346981Scy	if (!rssi)
1230346981Scy		return 255; /* not available */
1231346981Scy	if (rssi < -110)
1232346981Scy		return 0;
1233346981Scy	if (rssi > 0)
1234346981Scy		return 220;
1235346981Scy	return (rssi + 110) * 2;
1236346981Scy}
1237346981Scy
1238346981Scy
1239346981Scychar * get_param(const char *cmd, const char *param)
1240346981Scy{
1241346981Scy	const char *pos, *end;
1242346981Scy	char *val;
1243346981Scy	size_t len;
1244346981Scy
1245346981Scy	pos = os_strstr(cmd, param);
1246346981Scy	if (!pos)
1247346981Scy		return NULL;
1248346981Scy
1249346981Scy	pos += os_strlen(param);
1250346981Scy	end = os_strchr(pos, ' ');
1251346981Scy	if (end)
1252346981Scy		len = end - pos;
1253346981Scy	else
1254346981Scy		len = os_strlen(pos);
1255346981Scy	val = os_malloc(len + 1);
1256346981Scy	if (!val)
1257346981Scy		return NULL;
1258346981Scy	os_memcpy(val, pos, len);
1259346981Scy	val[len] = '\0';
1260346981Scy	return val;
1261346981Scy}
1262351611Scy
1263351611Scy
1264351611Scy/* Try to prevent most compilers from optimizing out clearing of memory that
1265351611Scy * becomes unaccessible after this function is called. This is mostly the case
1266351611Scy * for clearing local stack variables at the end of a function. This is not
1267351611Scy * exactly perfect, i.e., someone could come up with a compiler that figures out
1268351611Scy * the pointer is pointing to memset and then end up optimizing the call out, so
1269351611Scy * try go a bit further by storing the first octet (now zero) to make this even
1270351611Scy * a bit more difficult to optimize out. Once memset_s() is available, that
1271351611Scy * could be used here instead. */
1272351611Scystatic void * (* const volatile memset_func)(void *, int, size_t) = memset;
1273351611Scystatic u8 forced_memzero_val;
1274351611Scy
1275351611Scyvoid forced_memzero(void *ptr, size_t len)
1276351611Scy{
1277351611Scy	memset_func(ptr, 0, len);
1278351611Scy	if (len)
1279351611Scy		forced_memzero_val = ((u8 *) ptr)[0];
1280351611Scy}
1281