common.c revision 337817
1189251Ssam/*
2189251Ssam * wpa_supplicant/hostapd / common helper functions, etc.
3189251Ssam * Copyright (c) 2002-2007, 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
233189251Ssamvoid wpa_get_ntp_timestamp(u8 *buf)
234189251Ssam{
235189251Ssam	struct os_time now;
236189251Ssam	u32 sec, usec;
237189251Ssam	be32 tmp;
238189251Ssam
239189251Ssam	/* 64-bit NTP timestamp (time from 1900-01-01 00:00:00) */
240189251Ssam	os_get_time(&now);
241189251Ssam	sec = now.sec + 2208988800U; /* Epoch to 1900 */
242189251Ssam	/* Estimate 2^32/10^6 = 4295 - 1/32 - 1/512 */
243189251Ssam	usec = now.usec;
244189251Ssam	usec = 4295 * usec - (usec >> 5) - (usec >> 9);
245189251Ssam	tmp = host_to_be32(sec);
246189251Ssam	os_memcpy(buf, (u8 *) &tmp, 4);
247189251Ssam	tmp = host_to_be32(usec);
248189251Ssam	os_memcpy(buf + 4, (u8 *) &tmp, 4);
249189251Ssam}
250189251Ssam
251281806Srpaulo/**
252281806Srpaulo * wpa_scnprintf - Simpler-to-use snprintf function
253281806Srpaulo * @buf: Output buffer
254281806Srpaulo * @size: Buffer size
255281806Srpaulo * @fmt: format
256281806Srpaulo *
257281806Srpaulo * Simpler snprintf version that doesn't require further error checks - the
258281806Srpaulo * return value only indicates how many bytes were actually written, excluding
259281806Srpaulo * the NULL byte (i.e., 0 on error, size-1 if buffer is not big enough).
260281806Srpaulo */
261281806Srpauloint wpa_scnprintf(char *buf, size_t size, const char *fmt, ...)
262281806Srpaulo{
263281806Srpaulo	va_list ap;
264281806Srpaulo	int ret;
265189251Ssam
266281806Srpaulo	if (!size)
267281806Srpaulo		return 0;
268281806Srpaulo
269281806Srpaulo	va_start(ap, fmt);
270281806Srpaulo	ret = vsnprintf(buf, size, fmt, ap);
271281806Srpaulo	va_end(ap);
272281806Srpaulo
273281806Srpaulo	if (ret < 0)
274281806Srpaulo		return 0;
275281806Srpaulo	if ((size_t) ret >= size)
276281806Srpaulo		return size - 1;
277281806Srpaulo
278281806Srpaulo	return ret;
279281806Srpaulo}
280281806Srpaulo
281289549Srpaulo
282289549Srpauloint wpa_snprintf_hex_sep(char *buf, size_t buf_size, const u8 *data, size_t len,
283289549Srpaulo			 char sep)
284289549Srpaulo{
285289549Srpaulo	size_t i;
286289549Srpaulo	char *pos = buf, *end = buf + buf_size;
287289549Srpaulo	int ret;
288289549Srpaulo
289289549Srpaulo	if (buf_size == 0)
290289549Srpaulo		return 0;
291289549Srpaulo
292289549Srpaulo	for (i = 0; i < len; i++) {
293289549Srpaulo		ret = os_snprintf(pos, end - pos, "%02x%c",
294289549Srpaulo				  data[i], sep);
295289549Srpaulo		if (os_snprintf_error(end - pos, ret)) {
296289549Srpaulo			end[-1] = '\0';
297289549Srpaulo			return pos - buf;
298289549Srpaulo		}
299289549Srpaulo		pos += ret;
300289549Srpaulo	}
301289549Srpaulo	pos[-1] = '\0';
302289549Srpaulo	return pos - buf;
303289549Srpaulo}
304289549Srpaulo
305289549Srpaulo
306189251Ssamstatic inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data,
307189251Ssam				    size_t len, int uppercase)
308189251Ssam{
309189251Ssam	size_t i;
310189251Ssam	char *pos = buf, *end = buf + buf_size;
311189251Ssam	int ret;
312189251Ssam	if (buf_size == 0)
313189251Ssam		return 0;
314189251Ssam	for (i = 0; i < len; i++) {
315189251Ssam		ret = os_snprintf(pos, end - pos, uppercase ? "%02X" : "%02x",
316189251Ssam				  data[i]);
317281806Srpaulo		if (os_snprintf_error(end - pos, ret)) {
318189251Ssam			end[-1] = '\0';
319189251Ssam			return pos - buf;
320189251Ssam		}
321189251Ssam		pos += ret;
322189251Ssam	}
323189251Ssam	end[-1] = '\0';
324189251Ssam	return pos - buf;
325189251Ssam}
326189251Ssam
327189251Ssam/**
328189251Ssam * wpa_snprintf_hex - Print data as a hex string into a buffer
329189251Ssam * @buf: Memory area to use as the output buffer
330189251Ssam * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1)
331189251Ssam * @data: Data to be printed
332189251Ssam * @len: Length of data in bytes
333189251Ssam * Returns: Number of bytes written
334189251Ssam */
335189251Ssamint wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len)
336189251Ssam{
337189251Ssam	return _wpa_snprintf_hex(buf, buf_size, data, len, 0);
338189251Ssam}
339189251Ssam
340189251Ssam
341189251Ssam/**
342189251Ssam * wpa_snprintf_hex_uppercase - Print data as a upper case hex string into buf
343189251Ssam * @buf: Memory area to use as the output buffer
344189251Ssam * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1)
345189251Ssam * @data: Data to be printed
346189251Ssam * @len: Length of data in bytes
347189251Ssam * Returns: Number of bytes written
348189251Ssam */
349189251Ssamint wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data,
350189251Ssam			       size_t len)
351189251Ssam{
352189251Ssam	return _wpa_snprintf_hex(buf, buf_size, data, len, 1);
353189251Ssam}
354189251Ssam
355189251Ssam
356189251Ssam#ifdef CONFIG_ANSI_C_EXTRA
357189251Ssam
358189251Ssam#ifdef _WIN32_WCE
359189251Ssamvoid perror(const char *s)
360189251Ssam{
361189251Ssam	wpa_printf(MSG_ERROR, "%s: GetLastError: %d",
362189251Ssam		   s, (int) GetLastError());
363189251Ssam}
364189251Ssam#endif /* _WIN32_WCE */
365189251Ssam
366189251Ssam
367189251Ssamint optind = 1;
368189251Ssamint optopt;
369189251Ssamchar *optarg;
370189251Ssam
371189251Ssamint getopt(int argc, char *const argv[], const char *optstring)
372189251Ssam{
373189251Ssam	static int optchr = 1;
374189251Ssam	char *cp;
375189251Ssam
376189251Ssam	if (optchr == 1) {
377189251Ssam		if (optind >= argc) {
378189251Ssam			/* all arguments processed */
379189251Ssam			return EOF;
380189251Ssam		}
381189251Ssam
382189251Ssam		if (argv[optind][0] != '-' || argv[optind][1] == '\0') {
383189251Ssam			/* no option characters */
384189251Ssam			return EOF;
385189251Ssam		}
386189251Ssam	}
387189251Ssam
388189251Ssam	if (os_strcmp(argv[optind], "--") == 0) {
389189251Ssam		/* no more options */
390189251Ssam		optind++;
391189251Ssam		return EOF;
392189251Ssam	}
393189251Ssam
394189251Ssam	optopt = argv[optind][optchr];
395189251Ssam	cp = os_strchr(optstring, optopt);
396189251Ssam	if (cp == NULL || optopt == ':') {
397189251Ssam		if (argv[optind][++optchr] == '\0') {
398189251Ssam			optchr = 1;
399189251Ssam			optind++;
400189251Ssam		}
401189251Ssam		return '?';
402189251Ssam	}
403189251Ssam
404189251Ssam	if (cp[1] == ':') {
405189251Ssam		/* Argument required */
406189251Ssam		optchr = 1;
407189251Ssam		if (argv[optind][optchr + 1]) {
408189251Ssam			/* No space between option and argument */
409189251Ssam			optarg = &argv[optind++][optchr + 1];
410189251Ssam		} else if (++optind >= argc) {
411189251Ssam			/* option requires an argument */
412189251Ssam			return '?';
413189251Ssam		} else {
414189251Ssam			/* Argument in the next argv */
415189251Ssam			optarg = argv[optind++];
416189251Ssam		}
417189251Ssam	} else {
418189251Ssam		/* No argument */
419189251Ssam		if (argv[optind][++optchr] == '\0') {
420189251Ssam			optchr = 1;
421189251Ssam			optind++;
422189251Ssam		}
423189251Ssam		optarg = NULL;
424189251Ssam	}
425189251Ssam	return *cp;
426189251Ssam}
427189251Ssam#endif /* CONFIG_ANSI_C_EXTRA */
428189251Ssam
429189251Ssam
430189251Ssam#ifdef CONFIG_NATIVE_WINDOWS
431189251Ssam/**
432189251Ssam * wpa_unicode2ascii_inplace - Convert unicode string into ASCII
433189251Ssam * @str: Pointer to string to convert
434189251Ssam *
435189251Ssam * This function converts a unicode string to ASCII using the same
436189251Ssam * buffer for output. If UNICODE is not set, the buffer is not
437189251Ssam * modified.
438189251Ssam */
439189251Ssamvoid wpa_unicode2ascii_inplace(TCHAR *str)
440189251Ssam{
441189251Ssam#ifdef UNICODE
442189251Ssam	char *dst = (char *) str;
443189251Ssam	while (*str)
444189251Ssam		*dst++ = (char) *str++;
445189251Ssam	*dst = '\0';
446189251Ssam#endif /* UNICODE */
447189251Ssam}
448189251Ssam
449189251Ssam
450189251SsamTCHAR * wpa_strdup_tchar(const char *str)
451189251Ssam{
452189251Ssam#ifdef UNICODE
453189251Ssam	TCHAR *buf;
454189251Ssam	buf = os_malloc((strlen(str) + 1) * sizeof(TCHAR));
455189251Ssam	if (buf == NULL)
456189251Ssam		return NULL;
457189251Ssam	wsprintf(buf, L"%S", str);
458189251Ssam	return buf;
459189251Ssam#else /* UNICODE */
460189251Ssam	return os_strdup(str);
461189251Ssam#endif /* UNICODE */
462189251Ssam}
463189251Ssam#endif /* CONFIG_NATIVE_WINDOWS */
464189251Ssam
465189251Ssam
466252726Srpaulovoid printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len)
467252726Srpaulo{
468252726Srpaulo	char *end = txt + maxlen;
469252726Srpaulo	size_t i;
470252726Srpaulo
471252726Srpaulo	for (i = 0; i < len; i++) {
472281806Srpaulo		if (txt + 4 >= end)
473252726Srpaulo			break;
474252726Srpaulo
475252726Srpaulo		switch (data[i]) {
476252726Srpaulo		case '\"':
477252726Srpaulo			*txt++ = '\\';
478252726Srpaulo			*txt++ = '\"';
479252726Srpaulo			break;
480252726Srpaulo		case '\\':
481252726Srpaulo			*txt++ = '\\';
482252726Srpaulo			*txt++ = '\\';
483252726Srpaulo			break;
484281806Srpaulo		case '\033':
485252726Srpaulo			*txt++ = '\\';
486252726Srpaulo			*txt++ = 'e';
487252726Srpaulo			break;
488252726Srpaulo		case '\n':
489252726Srpaulo			*txt++ = '\\';
490252726Srpaulo			*txt++ = 'n';
491252726Srpaulo			break;
492252726Srpaulo		case '\r':
493252726Srpaulo			*txt++ = '\\';
494252726Srpaulo			*txt++ = 'r';
495252726Srpaulo			break;
496252726Srpaulo		case '\t':
497252726Srpaulo			*txt++ = '\\';
498252726Srpaulo			*txt++ = 't';
499252726Srpaulo			break;
500252726Srpaulo		default:
501337817Scy			if (data[i] >= 32 && data[i] <= 126) {
502252726Srpaulo				*txt++ = data[i];
503252726Srpaulo			} else {
504252726Srpaulo				txt += os_snprintf(txt, end - txt, "\\x%02x",
505252726Srpaulo						   data[i]);
506252726Srpaulo			}
507252726Srpaulo			break;
508252726Srpaulo		}
509252726Srpaulo	}
510252726Srpaulo
511252726Srpaulo	*txt = '\0';
512252726Srpaulo}
513252726Srpaulo
514252726Srpaulo
515252726Srpaulosize_t printf_decode(u8 *buf, size_t maxlen, const char *str)
516252726Srpaulo{
517252726Srpaulo	const char *pos = str;
518252726Srpaulo	size_t len = 0;
519252726Srpaulo	int val;
520252726Srpaulo
521252726Srpaulo	while (*pos) {
522281806Srpaulo		if (len + 1 >= maxlen)
523252726Srpaulo			break;
524252726Srpaulo		switch (*pos) {
525252726Srpaulo		case '\\':
526252726Srpaulo			pos++;
527252726Srpaulo			switch (*pos) {
528252726Srpaulo			case '\\':
529252726Srpaulo				buf[len++] = '\\';
530252726Srpaulo				pos++;
531252726Srpaulo				break;
532252726Srpaulo			case '"':
533252726Srpaulo				buf[len++] = '"';
534252726Srpaulo				pos++;
535252726Srpaulo				break;
536252726Srpaulo			case 'n':
537252726Srpaulo				buf[len++] = '\n';
538252726Srpaulo				pos++;
539252726Srpaulo				break;
540252726Srpaulo			case 'r':
541252726Srpaulo				buf[len++] = '\r';
542252726Srpaulo				pos++;
543252726Srpaulo				break;
544252726Srpaulo			case 't':
545252726Srpaulo				buf[len++] = '\t';
546252726Srpaulo				pos++;
547252726Srpaulo				break;
548252726Srpaulo			case 'e':
549281806Srpaulo				buf[len++] = '\033';
550252726Srpaulo				pos++;
551252726Srpaulo				break;
552252726Srpaulo			case 'x':
553252726Srpaulo				pos++;
554252726Srpaulo				val = hex2byte(pos);
555252726Srpaulo				if (val < 0) {
556252726Srpaulo					val = hex2num(*pos);
557252726Srpaulo					if (val < 0)
558252726Srpaulo						break;
559252726Srpaulo					buf[len++] = val;
560252726Srpaulo					pos++;
561252726Srpaulo				} else {
562252726Srpaulo					buf[len++] = val;
563252726Srpaulo					pos += 2;
564252726Srpaulo				}
565252726Srpaulo				break;
566252726Srpaulo			case '0':
567252726Srpaulo			case '1':
568252726Srpaulo			case '2':
569252726Srpaulo			case '3':
570252726Srpaulo			case '4':
571252726Srpaulo			case '5':
572252726Srpaulo			case '6':
573252726Srpaulo			case '7':
574252726Srpaulo				val = *pos++ - '0';
575252726Srpaulo				if (*pos >= '0' && *pos <= '7')
576252726Srpaulo					val = val * 8 + (*pos++ - '0');
577252726Srpaulo				if (*pos >= '0' && *pos <= '7')
578252726Srpaulo					val = val * 8 + (*pos++ - '0');
579252726Srpaulo				buf[len++] = val;
580252726Srpaulo				break;
581252726Srpaulo			default:
582252726Srpaulo				break;
583252726Srpaulo			}
584252726Srpaulo			break;
585252726Srpaulo		default:
586252726Srpaulo			buf[len++] = *pos++;
587252726Srpaulo			break;
588252726Srpaulo		}
589252726Srpaulo	}
590281806Srpaulo	if (maxlen > len)
591281806Srpaulo		buf[len] = '\0';
592252726Srpaulo
593252726Srpaulo	return len;
594252726Srpaulo}
595252726Srpaulo
596252726Srpaulo
597189251Ssam/**
598189251Ssam * wpa_ssid_txt - Convert SSID to a printable string
599189251Ssam * @ssid: SSID (32-octet string)
600189251Ssam * @ssid_len: Length of ssid in octets
601189251Ssam * Returns: Pointer to a printable string
602189251Ssam *
603189251Ssam * This function can be used to convert SSIDs into printable form. In most
604189251Ssam * cases, SSIDs do not use unprintable characters, but IEEE 802.11 standard
605189251Ssam * does not limit the used character set, so anything could be used in an SSID.
606189251Ssam *
607189251Ssam * This function uses a static buffer, so only one call can be used at the
608189251Ssam * time, i.e., this is not re-entrant and the returned buffer must be used
609189251Ssam * before calling this again.
610189251Ssam */
611189251Ssamconst char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len)
612189251Ssam{
613289549Srpaulo	static char ssid_txt[SSID_MAX_LEN * 4 + 1];
614189251Ssam
615252726Srpaulo	if (ssid == NULL) {
616252726Srpaulo		ssid_txt[0] = '\0';
617252726Srpaulo		return ssid_txt;
618189251Ssam	}
619252726Srpaulo
620252726Srpaulo	printf_encode(ssid_txt, sizeof(ssid_txt), ssid, ssid_len);
621189251Ssam	return ssid_txt;
622189251Ssam}
623209158Srpaulo
624209158Srpaulo
625209158Srpaulovoid * __hide_aliasing_typecast(void *foo)
626209158Srpaulo{
627209158Srpaulo	return foo;
628209158Srpaulo}
629252726Srpaulo
630252726Srpaulo
631252726Srpaulochar * wpa_config_parse_string(const char *value, size_t *len)
632252726Srpaulo{
633252726Srpaulo	if (*value == '"') {
634252726Srpaulo		const char *pos;
635252726Srpaulo		char *str;
636252726Srpaulo		value++;
637252726Srpaulo		pos = os_strrchr(value, '"');
638252726Srpaulo		if (pos == NULL || pos[1] != '\0')
639252726Srpaulo			return NULL;
640252726Srpaulo		*len = pos - value;
641281806Srpaulo		str = dup_binstr(value, *len);
642252726Srpaulo		if (str == NULL)
643252726Srpaulo			return NULL;
644252726Srpaulo		return str;
645252726Srpaulo	} else if (*value == 'P' && value[1] == '"') {
646252726Srpaulo		const char *pos;
647252726Srpaulo		char *tstr, *str;
648252726Srpaulo		size_t tlen;
649252726Srpaulo		value += 2;
650252726Srpaulo		pos = os_strrchr(value, '"');
651252726Srpaulo		if (pos == NULL || pos[1] != '\0')
652252726Srpaulo			return NULL;
653252726Srpaulo		tlen = pos - value;
654281806Srpaulo		tstr = dup_binstr(value, tlen);
655252726Srpaulo		if (tstr == NULL)
656252726Srpaulo			return NULL;
657252726Srpaulo
658252726Srpaulo		str = os_malloc(tlen + 1);
659252726Srpaulo		if (str == NULL) {
660252726Srpaulo			os_free(tstr);
661252726Srpaulo			return NULL;
662252726Srpaulo		}
663252726Srpaulo
664252726Srpaulo		*len = printf_decode((u8 *) str, tlen + 1, tstr);
665252726Srpaulo		os_free(tstr);
666252726Srpaulo
667252726Srpaulo		return str;
668252726Srpaulo	} else {
669252726Srpaulo		u8 *str;
670252726Srpaulo		size_t tlen, hlen = os_strlen(value);
671252726Srpaulo		if (hlen & 1)
672252726Srpaulo			return NULL;
673252726Srpaulo		tlen = hlen / 2;
674252726Srpaulo		str = os_malloc(tlen + 1);
675252726Srpaulo		if (str == NULL)
676252726Srpaulo			return NULL;
677252726Srpaulo		if (hexstr2bin(value, str, tlen)) {
678252726Srpaulo			os_free(str);
679252726Srpaulo			return NULL;
680252726Srpaulo		}
681252726Srpaulo		str[tlen] = '\0';
682252726Srpaulo		*len = tlen;
683252726Srpaulo		return (char *) str;
684252726Srpaulo	}
685252726Srpaulo}
686252726Srpaulo
687252726Srpaulo
688252726Srpauloint is_hex(const u8 *data, size_t len)
689252726Srpaulo{
690252726Srpaulo	size_t i;
691252726Srpaulo
692252726Srpaulo	for (i = 0; i < len; i++) {
693252726Srpaulo		if (data[i] < 32 || data[i] >= 127)
694252726Srpaulo			return 1;
695252726Srpaulo	}
696252726Srpaulo	return 0;
697252726Srpaulo}
698252726Srpaulo
699252726Srpaulo
700337817Scyint has_ctrl_char(const u8 *data, size_t len)
701337817Scy{
702337817Scy	size_t i;
703337817Scy
704337817Scy	for (i = 0; i < len; i++) {
705337817Scy		if (data[i] < 32 || data[i] == 127)
706337817Scy			return 1;
707337817Scy	}
708337817Scy	return 0;
709337817Scy}
710337817Scy
711337817Scy
712337817Scyint has_newline(const char *str)
713337817Scy{
714337817Scy	while (*str) {
715337817Scy		if (*str == '\n' || *str == '\r')
716337817Scy			return 1;
717337817Scy		str++;
718337817Scy	}
719337817Scy	return 0;
720337817Scy}
721337817Scy
722337817Scy
723252726Srpaulosize_t merge_byte_arrays(u8 *res, size_t res_len,
724252726Srpaulo			 const u8 *src1, size_t src1_len,
725252726Srpaulo			 const u8 *src2, size_t src2_len)
726252726Srpaulo{
727252726Srpaulo	size_t len = 0;
728252726Srpaulo
729252726Srpaulo	os_memset(res, 0, res_len);
730252726Srpaulo
731252726Srpaulo	if (src1) {
732252726Srpaulo		if (src1_len >= res_len) {
733252726Srpaulo			os_memcpy(res, src1, res_len);
734252726Srpaulo			return res_len;
735252726Srpaulo		}
736252726Srpaulo
737252726Srpaulo		os_memcpy(res, src1, src1_len);
738252726Srpaulo		len += src1_len;
739252726Srpaulo	}
740252726Srpaulo
741252726Srpaulo	if (src2) {
742252726Srpaulo		if (len + src2_len >= res_len) {
743252726Srpaulo			os_memcpy(res + len, src2, res_len - len);
744252726Srpaulo			return res_len;
745252726Srpaulo		}
746252726Srpaulo
747252726Srpaulo		os_memcpy(res + len, src2, src2_len);
748252726Srpaulo		len += src2_len;
749252726Srpaulo	}
750252726Srpaulo
751252726Srpaulo	return len;
752252726Srpaulo}
753281806Srpaulo
754281806Srpaulo
755281806Srpaulochar * dup_binstr(const void *src, size_t len)
756281806Srpaulo{
757281806Srpaulo	char *res;
758281806Srpaulo
759281806Srpaulo	if (src == NULL)
760281806Srpaulo		return NULL;
761281806Srpaulo	res = os_malloc(len + 1);
762281806Srpaulo	if (res == NULL)
763281806Srpaulo		return NULL;
764281806Srpaulo	os_memcpy(res, src, len);
765281806Srpaulo	res[len] = '\0';
766281806Srpaulo
767281806Srpaulo	return res;
768281806Srpaulo}
769281806Srpaulo
770281806Srpaulo
771281806Srpauloint freq_range_list_parse(struct wpa_freq_range_list *res, const char *value)
772281806Srpaulo{
773281806Srpaulo	struct wpa_freq_range *freq = NULL, *n;
774281806Srpaulo	unsigned int count = 0;
775281806Srpaulo	const char *pos, *pos2, *pos3;
776281806Srpaulo
777281806Srpaulo	/*
778281806Srpaulo	 * Comma separated list of frequency ranges.
779281806Srpaulo	 * For example: 2412-2432,2462,5000-6000
780281806Srpaulo	 */
781281806Srpaulo	pos = value;
782281806Srpaulo	while (pos && pos[0]) {
783281806Srpaulo		n = os_realloc_array(freq, count + 1,
784281806Srpaulo				     sizeof(struct wpa_freq_range));
785281806Srpaulo		if (n == NULL) {
786281806Srpaulo			os_free(freq);
787281806Srpaulo			return -1;
788281806Srpaulo		}
789281806Srpaulo		freq = n;
790281806Srpaulo		freq[count].min = atoi(pos);
791281806Srpaulo		pos2 = os_strchr(pos, '-');
792281806Srpaulo		pos3 = os_strchr(pos, ',');
793281806Srpaulo		if (pos2 && (!pos3 || pos2 < pos3)) {
794281806Srpaulo			pos2++;
795281806Srpaulo			freq[count].max = atoi(pos2);
796281806Srpaulo		} else
797281806Srpaulo			freq[count].max = freq[count].min;
798281806Srpaulo		pos = pos3;
799281806Srpaulo		if (pos)
800281806Srpaulo			pos++;
801281806Srpaulo		count++;
802281806Srpaulo	}
803281806Srpaulo
804281806Srpaulo	os_free(res->range);
805281806Srpaulo	res->range = freq;
806281806Srpaulo	res->num = count;
807281806Srpaulo
808281806Srpaulo	return 0;
809281806Srpaulo}
810281806Srpaulo
811281806Srpaulo
812281806Srpauloint freq_range_list_includes(const struct wpa_freq_range_list *list,
813281806Srpaulo			     unsigned int freq)
814281806Srpaulo{
815281806Srpaulo	unsigned int i;
816281806Srpaulo
817281806Srpaulo	if (list == NULL)
818281806Srpaulo		return 0;
819281806Srpaulo
820281806Srpaulo	for (i = 0; i < list->num; i++) {
821281806Srpaulo		if (freq >= list->range[i].min && freq <= list->range[i].max)
822281806Srpaulo			return 1;
823281806Srpaulo	}
824281806Srpaulo
825281806Srpaulo	return 0;
826281806Srpaulo}
827281806Srpaulo
828281806Srpaulo
829281806Srpaulochar * freq_range_list_str(const struct wpa_freq_range_list *list)
830281806Srpaulo{
831281806Srpaulo	char *buf, *pos, *end;
832281806Srpaulo	size_t maxlen;
833281806Srpaulo	unsigned int i;
834281806Srpaulo	int res;
835281806Srpaulo
836281806Srpaulo	if (list->num == 0)
837281806Srpaulo		return NULL;
838281806Srpaulo
839281806Srpaulo	maxlen = list->num * 30;
840281806Srpaulo	buf = os_malloc(maxlen);
841281806Srpaulo	if (buf == NULL)
842281806Srpaulo		return NULL;
843281806Srpaulo	pos = buf;
844281806Srpaulo	end = buf + maxlen;
845281806Srpaulo
846281806Srpaulo	for (i = 0; i < list->num; i++) {
847281806Srpaulo		struct wpa_freq_range *range = &list->range[i];
848281806Srpaulo
849281806Srpaulo		if (range->min == range->max)
850281806Srpaulo			res = os_snprintf(pos, end - pos, "%s%u",
851281806Srpaulo					  i == 0 ? "" : ",", range->min);
852281806Srpaulo		else
853281806Srpaulo			res = os_snprintf(pos, end - pos, "%s%u-%u",
854281806Srpaulo					  i == 0 ? "" : ",",
855281806Srpaulo					  range->min, range->max);
856281806Srpaulo		if (os_snprintf_error(end - pos, res)) {
857281806Srpaulo			os_free(buf);
858281806Srpaulo			return NULL;
859281806Srpaulo		}
860281806Srpaulo		pos += res;
861281806Srpaulo	}
862281806Srpaulo
863281806Srpaulo	return buf;
864281806Srpaulo}
865281806Srpaulo
866281806Srpaulo
867281806Srpauloint int_array_len(const int *a)
868281806Srpaulo{
869281806Srpaulo	int i;
870281806Srpaulo	for (i = 0; a && a[i]; i++)
871281806Srpaulo		;
872281806Srpaulo	return i;
873281806Srpaulo}
874281806Srpaulo
875281806Srpaulo
876281806Srpaulovoid int_array_concat(int **res, const int *a)
877281806Srpaulo{
878281806Srpaulo	int reslen, alen, i;
879281806Srpaulo	int *n;
880281806Srpaulo
881281806Srpaulo	reslen = int_array_len(*res);
882281806Srpaulo	alen = int_array_len(a);
883281806Srpaulo
884281806Srpaulo	n = os_realloc_array(*res, reslen + alen + 1, sizeof(int));
885281806Srpaulo	if (n == NULL) {
886281806Srpaulo		os_free(*res);
887281806Srpaulo		*res = NULL;
888281806Srpaulo		return;
889281806Srpaulo	}
890281806Srpaulo	for (i = 0; i <= alen; i++)
891281806Srpaulo		n[reslen + i] = a[i];
892281806Srpaulo	*res = n;
893281806Srpaulo}
894281806Srpaulo
895281806Srpaulo
896281806Srpaulostatic int freq_cmp(const void *a, const void *b)
897281806Srpaulo{
898281806Srpaulo	int _a = *(int *) a;
899281806Srpaulo	int _b = *(int *) b;
900281806Srpaulo
901281806Srpaulo	if (_a == 0)
902281806Srpaulo		return 1;
903281806Srpaulo	if (_b == 0)
904281806Srpaulo		return -1;
905281806Srpaulo	return _a - _b;
906281806Srpaulo}
907281806Srpaulo
908281806Srpaulo
909281806Srpaulovoid int_array_sort_unique(int *a)
910281806Srpaulo{
911281806Srpaulo	int alen;
912281806Srpaulo	int i, j;
913281806Srpaulo
914281806Srpaulo	if (a == NULL)
915281806Srpaulo		return;
916281806Srpaulo
917281806Srpaulo	alen = int_array_len(a);
918281806Srpaulo	qsort(a, alen, sizeof(int), freq_cmp);
919281806Srpaulo
920281806Srpaulo	i = 0;
921281806Srpaulo	j = 1;
922281806Srpaulo	while (a[i] && a[j]) {
923281806Srpaulo		if (a[i] == a[j]) {
924281806Srpaulo			j++;
925281806Srpaulo			continue;
926281806Srpaulo		}
927281806Srpaulo		a[++i] = a[j++];
928281806Srpaulo	}
929281806Srpaulo	if (a[i])
930281806Srpaulo		i++;
931281806Srpaulo	a[i] = 0;
932281806Srpaulo}
933281806Srpaulo
934281806Srpaulo
935281806Srpaulovoid int_array_add_unique(int **res, int a)
936281806Srpaulo{
937281806Srpaulo	int reslen;
938281806Srpaulo	int *n;
939281806Srpaulo
940281806Srpaulo	for (reslen = 0; *res && (*res)[reslen]; reslen++) {
941281806Srpaulo		if ((*res)[reslen] == a)
942281806Srpaulo			return; /* already in the list */
943281806Srpaulo	}
944281806Srpaulo
945281806Srpaulo	n = os_realloc_array(*res, reslen + 2, sizeof(int));
946281806Srpaulo	if (n == NULL) {
947281806Srpaulo		os_free(*res);
948281806Srpaulo		*res = NULL;
949281806Srpaulo		return;
950281806Srpaulo	}
951281806Srpaulo
952281806Srpaulo	n[reslen] = a;
953281806Srpaulo	n[reslen + 1] = 0;
954281806Srpaulo
955281806Srpaulo	*res = n;
956281806Srpaulo}
957281806Srpaulo
958281806Srpaulo
959281806Srpaulovoid str_clear_free(char *str)
960281806Srpaulo{
961281806Srpaulo	if (str) {
962281806Srpaulo		size_t len = os_strlen(str);
963281806Srpaulo		os_memset(str, 0, len);
964281806Srpaulo		os_free(str);
965281806Srpaulo	}
966281806Srpaulo}
967281806Srpaulo
968281806Srpaulo
969281806Srpaulovoid bin_clear_free(void *bin, size_t len)
970281806Srpaulo{
971281806Srpaulo	if (bin) {
972281806Srpaulo		os_memset(bin, 0, len);
973281806Srpaulo		os_free(bin);
974281806Srpaulo	}
975281806Srpaulo}
976281806Srpaulo
977281806Srpaulo
978281806Srpauloint random_mac_addr(u8 *addr)
979281806Srpaulo{
980281806Srpaulo	if (os_get_random(addr, ETH_ALEN) < 0)
981281806Srpaulo		return -1;
982281806Srpaulo	addr[0] &= 0xfe; /* unicast */
983281806Srpaulo	addr[0] |= 0x02; /* locally administered */
984281806Srpaulo	return 0;
985281806Srpaulo}
986281806Srpaulo
987281806Srpaulo
988281806Srpauloint random_mac_addr_keep_oui(u8 *addr)
989281806Srpaulo{
990281806Srpaulo	if (os_get_random(addr + 3, 3) < 0)
991281806Srpaulo		return -1;
992281806Srpaulo	addr[0] &= 0xfe; /* unicast */
993281806Srpaulo	addr[0] |= 0x02; /* locally administered */
994281806Srpaulo	return 0;
995281806Srpaulo}
996281806Srpaulo
997281806Srpaulo
998281806Srpaulo/**
999289549Srpaulo * cstr_token - Get next token from const char string
1000289549Srpaulo * @str: a constant string to tokenize
1001289549Srpaulo * @delim: a string of delimiters
1002289549Srpaulo * @last: a pointer to a character following the returned token
1003289549Srpaulo *      It has to be set to NULL for the first call and passed for any
1004337817Scy *      further call.
1005289549Srpaulo * Returns: a pointer to token position in str or NULL
1006289549Srpaulo *
1007289549Srpaulo * This function is similar to str_token, but it can be used with both
1008289549Srpaulo * char and const char strings. Differences:
1009289549Srpaulo * - The str buffer remains unmodified
1010289549Srpaulo * - The returned token is not a NULL terminated string, but a token
1011289549Srpaulo *   position in str buffer. If a return value is not NULL a size
1012289549Srpaulo *   of the returned token could be calculated as (last - token).
1013289549Srpaulo */
1014289549Srpauloconst char * cstr_token(const char *str, const char *delim, const char **last)
1015289549Srpaulo{
1016289549Srpaulo	const char *end, *token = str;
1017289549Srpaulo
1018289549Srpaulo	if (!str || !delim || !last)
1019289549Srpaulo		return NULL;
1020289549Srpaulo
1021289549Srpaulo	if (*last)
1022289549Srpaulo		token = *last;
1023289549Srpaulo
1024289549Srpaulo	while (*token && os_strchr(delim, *token))
1025289549Srpaulo		token++;
1026289549Srpaulo
1027289549Srpaulo	if (!*token)
1028289549Srpaulo		return NULL;
1029289549Srpaulo
1030289549Srpaulo	end = token + 1;
1031289549Srpaulo
1032289549Srpaulo	while (*end && !os_strchr(delim, *end))
1033289549Srpaulo		end++;
1034289549Srpaulo
1035289549Srpaulo	*last = end;
1036289549Srpaulo	return token;
1037289549Srpaulo}
1038289549Srpaulo
1039289549Srpaulo
1040289549Srpaulo/**
1041281806Srpaulo * str_token - Get next token from a string
1042281806Srpaulo * @buf: String to tokenize. Note that the string might be modified.
1043281806Srpaulo * @delim: String of delimiters
1044281806Srpaulo * @context: Pointer to save our context. Should be initialized with
1045281806Srpaulo *	NULL on the first call, and passed for any further call.
1046281806Srpaulo * Returns: The next token, NULL if there are no more valid tokens.
1047281806Srpaulo */
1048281806Srpaulochar * str_token(char *str, const char *delim, char **context)
1049281806Srpaulo{
1050289549Srpaulo	char *token = (char *) cstr_token(str, delim, (const char **) context);
1051281806Srpaulo
1052289549Srpaulo	if (token && **context)
1053289549Srpaulo		*(*context)++ = '\0';
1054281806Srpaulo
1055289549Srpaulo	return token;
1056281806Srpaulo}
1057281806Srpaulo
1058281806Srpaulo
1059281806Srpaulosize_t utf8_unescape(const char *inp, size_t in_size,
1060281806Srpaulo		     char *outp, size_t out_size)
1061281806Srpaulo{
1062281806Srpaulo	size_t res_size = 0;
1063281806Srpaulo
1064281806Srpaulo	if (!inp || !outp)
1065281806Srpaulo		return 0;
1066281806Srpaulo
1067281806Srpaulo	if (!in_size)
1068281806Srpaulo		in_size = os_strlen(inp);
1069281806Srpaulo
1070281806Srpaulo	/* Advance past leading single quote */
1071281806Srpaulo	if (*inp == '\'' && in_size) {
1072281806Srpaulo		inp++;
1073281806Srpaulo		in_size--;
1074281806Srpaulo	}
1075281806Srpaulo
1076281806Srpaulo	while (in_size--) {
1077281806Srpaulo		if (res_size >= out_size)
1078281806Srpaulo			return 0;
1079281806Srpaulo
1080281806Srpaulo		switch (*inp) {
1081281806Srpaulo		case '\'':
1082281806Srpaulo			/* Terminate on bare single quote */
1083281806Srpaulo			*outp = '\0';
1084281806Srpaulo			return res_size;
1085281806Srpaulo
1086281806Srpaulo		case '\\':
1087281806Srpaulo			if (!in_size--)
1088281806Srpaulo				return 0;
1089281806Srpaulo			inp++;
1090281806Srpaulo			/* fall through */
1091281806Srpaulo
1092281806Srpaulo		default:
1093281806Srpaulo			*outp++ = *inp++;
1094281806Srpaulo			res_size++;
1095281806Srpaulo		}
1096281806Srpaulo	}
1097281806Srpaulo
1098281806Srpaulo	/* NUL terminate if space allows */
1099281806Srpaulo	if (res_size < out_size)
1100281806Srpaulo		*outp = '\0';
1101281806Srpaulo
1102281806Srpaulo	return res_size;
1103281806Srpaulo}
1104281806Srpaulo
1105281806Srpaulo
1106281806Srpaulosize_t utf8_escape(const char *inp, size_t in_size,
1107281806Srpaulo		   char *outp, size_t out_size)
1108281806Srpaulo{
1109281806Srpaulo	size_t res_size = 0;
1110281806Srpaulo
1111281806Srpaulo	if (!inp || !outp)
1112281806Srpaulo		return 0;
1113281806Srpaulo
1114281806Srpaulo	/* inp may or may not be NUL terminated, but must be if 0 size
1115281806Srpaulo	 * is specified */
1116281806Srpaulo	if (!in_size)
1117281806Srpaulo		in_size = os_strlen(inp);
1118281806Srpaulo
1119281806Srpaulo	while (in_size--) {
1120281806Srpaulo		if (res_size++ >= out_size)
1121281806Srpaulo			return 0;
1122281806Srpaulo
1123281806Srpaulo		switch (*inp) {
1124281806Srpaulo		case '\\':
1125281806Srpaulo		case '\'':
1126281806Srpaulo			if (res_size++ >= out_size)
1127281806Srpaulo				return 0;
1128281806Srpaulo			*outp++ = '\\';
1129281806Srpaulo			/* fall through */
1130281806Srpaulo
1131281806Srpaulo		default:
1132281806Srpaulo			*outp++ = *inp++;
1133281806Srpaulo			break;
1134281806Srpaulo		}
1135281806Srpaulo	}
1136281806Srpaulo
1137281806Srpaulo	/* NUL terminate if space allows */
1138281806Srpaulo	if (res_size < out_size)
1139281806Srpaulo		*outp = '\0';
1140281806Srpaulo
1141281806Srpaulo	return res_size;
1142281806Srpaulo}
1143289549Srpaulo
1144289549Srpaulo
1145289549Srpauloint is_ctrl_char(char c)
1146289549Srpaulo{
1147289549Srpaulo	return c > 0 && c < 32;
1148289549Srpaulo}
1149337817Scy
1150337817Scy
1151337817Scy/**
1152337817Scy * ssid_parse - Parse a string that contains SSID in hex or text format
1153337817Scy * @buf: Input NULL terminated string that contains the SSID
1154337817Scy * @ssid: Output SSID
1155337817Scy * Returns: 0 on success, -1 otherwise
1156337817Scy *
1157337817Scy * The SSID has to be enclosed in double quotes for the text format or space
1158337817Scy * or NULL terminated string of hex digits for the hex format. buf can include
1159337817Scy * additional arguments after the SSID.
1160337817Scy */
1161337817Scyint ssid_parse(const char *buf, struct wpa_ssid_value *ssid)
1162337817Scy{
1163337817Scy	char *tmp, *res, *end;
1164337817Scy	size_t len;
1165337817Scy
1166337817Scy	ssid->ssid_len = 0;
1167337817Scy
1168337817Scy	tmp = os_strdup(buf);
1169337817Scy	if (!tmp)
1170337817Scy		return -1;
1171337817Scy
1172337817Scy	if (*tmp != '"') {
1173337817Scy		end = os_strchr(tmp, ' ');
1174337817Scy		if (end)
1175337817Scy			*end = '\0';
1176337817Scy	} else {
1177337817Scy		end = os_strchr(tmp + 1, '"');
1178337817Scy		if (!end) {
1179337817Scy			os_free(tmp);
1180337817Scy			return -1;
1181337817Scy		}
1182337817Scy
1183337817Scy		end[1] = '\0';
1184337817Scy	}
1185337817Scy
1186337817Scy	res = wpa_config_parse_string(tmp, &len);
1187337817Scy	if (res && len <= SSID_MAX_LEN) {
1188337817Scy		ssid->ssid_len = len;
1189337817Scy		os_memcpy(ssid->ssid, res, len);
1190337817Scy	}
1191337817Scy
1192337817Scy	os_free(tmp);
1193337817Scy	os_free(res);
1194337817Scy
1195337817Scy	return ssid->ssid_len ? 0 : -1;
1196337817Scy}
1197337817Scy
1198337817Scy
1199337817Scyint str_starts(const char *str, const char *start)
1200337817Scy{
1201337817Scy	return os_strncmp(str, start, os_strlen(start)) == 0;
1202337817Scy}
1203