common.c revision 289549
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 */
89281806Srpaulo	if (*r == '\0' || isspace(*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:
501252726Srpaulo			if (data[i] >= 32 && data[i] <= 127) {
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
700252726Srpaulosize_t merge_byte_arrays(u8 *res, size_t res_len,
701252726Srpaulo			 const u8 *src1, size_t src1_len,
702252726Srpaulo			 const u8 *src2, size_t src2_len)
703252726Srpaulo{
704252726Srpaulo	size_t len = 0;
705252726Srpaulo
706252726Srpaulo	os_memset(res, 0, res_len);
707252726Srpaulo
708252726Srpaulo	if (src1) {
709252726Srpaulo		if (src1_len >= res_len) {
710252726Srpaulo			os_memcpy(res, src1, res_len);
711252726Srpaulo			return res_len;
712252726Srpaulo		}
713252726Srpaulo
714252726Srpaulo		os_memcpy(res, src1, src1_len);
715252726Srpaulo		len += src1_len;
716252726Srpaulo	}
717252726Srpaulo
718252726Srpaulo	if (src2) {
719252726Srpaulo		if (len + src2_len >= res_len) {
720252726Srpaulo			os_memcpy(res + len, src2, res_len - len);
721252726Srpaulo			return res_len;
722252726Srpaulo		}
723252726Srpaulo
724252726Srpaulo		os_memcpy(res + len, src2, src2_len);
725252726Srpaulo		len += src2_len;
726252726Srpaulo	}
727252726Srpaulo
728252726Srpaulo	return len;
729252726Srpaulo}
730281806Srpaulo
731281806Srpaulo
732281806Srpaulochar * dup_binstr(const void *src, size_t len)
733281806Srpaulo{
734281806Srpaulo	char *res;
735281806Srpaulo
736281806Srpaulo	if (src == NULL)
737281806Srpaulo		return NULL;
738281806Srpaulo	res = os_malloc(len + 1);
739281806Srpaulo	if (res == NULL)
740281806Srpaulo		return NULL;
741281806Srpaulo	os_memcpy(res, src, len);
742281806Srpaulo	res[len] = '\0';
743281806Srpaulo
744281806Srpaulo	return res;
745281806Srpaulo}
746281806Srpaulo
747281806Srpaulo
748281806Srpauloint freq_range_list_parse(struct wpa_freq_range_list *res, const char *value)
749281806Srpaulo{
750281806Srpaulo	struct wpa_freq_range *freq = NULL, *n;
751281806Srpaulo	unsigned int count = 0;
752281806Srpaulo	const char *pos, *pos2, *pos3;
753281806Srpaulo
754281806Srpaulo	/*
755281806Srpaulo	 * Comma separated list of frequency ranges.
756281806Srpaulo	 * For example: 2412-2432,2462,5000-6000
757281806Srpaulo	 */
758281806Srpaulo	pos = value;
759281806Srpaulo	while (pos && pos[0]) {
760281806Srpaulo		n = os_realloc_array(freq, count + 1,
761281806Srpaulo				     sizeof(struct wpa_freq_range));
762281806Srpaulo		if (n == NULL) {
763281806Srpaulo			os_free(freq);
764281806Srpaulo			return -1;
765281806Srpaulo		}
766281806Srpaulo		freq = n;
767281806Srpaulo		freq[count].min = atoi(pos);
768281806Srpaulo		pos2 = os_strchr(pos, '-');
769281806Srpaulo		pos3 = os_strchr(pos, ',');
770281806Srpaulo		if (pos2 && (!pos3 || pos2 < pos3)) {
771281806Srpaulo			pos2++;
772281806Srpaulo			freq[count].max = atoi(pos2);
773281806Srpaulo		} else
774281806Srpaulo			freq[count].max = freq[count].min;
775281806Srpaulo		pos = pos3;
776281806Srpaulo		if (pos)
777281806Srpaulo			pos++;
778281806Srpaulo		count++;
779281806Srpaulo	}
780281806Srpaulo
781281806Srpaulo	os_free(res->range);
782281806Srpaulo	res->range = freq;
783281806Srpaulo	res->num = count;
784281806Srpaulo
785281806Srpaulo	return 0;
786281806Srpaulo}
787281806Srpaulo
788281806Srpaulo
789281806Srpauloint freq_range_list_includes(const struct wpa_freq_range_list *list,
790281806Srpaulo			     unsigned int freq)
791281806Srpaulo{
792281806Srpaulo	unsigned int i;
793281806Srpaulo
794281806Srpaulo	if (list == NULL)
795281806Srpaulo		return 0;
796281806Srpaulo
797281806Srpaulo	for (i = 0; i < list->num; i++) {
798281806Srpaulo		if (freq >= list->range[i].min && freq <= list->range[i].max)
799281806Srpaulo			return 1;
800281806Srpaulo	}
801281806Srpaulo
802281806Srpaulo	return 0;
803281806Srpaulo}
804281806Srpaulo
805281806Srpaulo
806281806Srpaulochar * freq_range_list_str(const struct wpa_freq_range_list *list)
807281806Srpaulo{
808281806Srpaulo	char *buf, *pos, *end;
809281806Srpaulo	size_t maxlen;
810281806Srpaulo	unsigned int i;
811281806Srpaulo	int res;
812281806Srpaulo
813281806Srpaulo	if (list->num == 0)
814281806Srpaulo		return NULL;
815281806Srpaulo
816281806Srpaulo	maxlen = list->num * 30;
817281806Srpaulo	buf = os_malloc(maxlen);
818281806Srpaulo	if (buf == NULL)
819281806Srpaulo		return NULL;
820281806Srpaulo	pos = buf;
821281806Srpaulo	end = buf + maxlen;
822281806Srpaulo
823281806Srpaulo	for (i = 0; i < list->num; i++) {
824281806Srpaulo		struct wpa_freq_range *range = &list->range[i];
825281806Srpaulo
826281806Srpaulo		if (range->min == range->max)
827281806Srpaulo			res = os_snprintf(pos, end - pos, "%s%u",
828281806Srpaulo					  i == 0 ? "" : ",", range->min);
829281806Srpaulo		else
830281806Srpaulo			res = os_snprintf(pos, end - pos, "%s%u-%u",
831281806Srpaulo					  i == 0 ? "" : ",",
832281806Srpaulo					  range->min, range->max);
833281806Srpaulo		if (os_snprintf_error(end - pos, res)) {
834281806Srpaulo			os_free(buf);
835281806Srpaulo			return NULL;
836281806Srpaulo		}
837281806Srpaulo		pos += res;
838281806Srpaulo	}
839281806Srpaulo
840281806Srpaulo	return buf;
841281806Srpaulo}
842281806Srpaulo
843281806Srpaulo
844281806Srpauloint int_array_len(const int *a)
845281806Srpaulo{
846281806Srpaulo	int i;
847281806Srpaulo	for (i = 0; a && a[i]; i++)
848281806Srpaulo		;
849281806Srpaulo	return i;
850281806Srpaulo}
851281806Srpaulo
852281806Srpaulo
853281806Srpaulovoid int_array_concat(int **res, const int *a)
854281806Srpaulo{
855281806Srpaulo	int reslen, alen, i;
856281806Srpaulo	int *n;
857281806Srpaulo
858281806Srpaulo	reslen = int_array_len(*res);
859281806Srpaulo	alen = int_array_len(a);
860281806Srpaulo
861281806Srpaulo	n = os_realloc_array(*res, reslen + alen + 1, sizeof(int));
862281806Srpaulo	if (n == NULL) {
863281806Srpaulo		os_free(*res);
864281806Srpaulo		*res = NULL;
865281806Srpaulo		return;
866281806Srpaulo	}
867281806Srpaulo	for (i = 0; i <= alen; i++)
868281806Srpaulo		n[reslen + i] = a[i];
869281806Srpaulo	*res = n;
870281806Srpaulo}
871281806Srpaulo
872281806Srpaulo
873281806Srpaulostatic int freq_cmp(const void *a, const void *b)
874281806Srpaulo{
875281806Srpaulo	int _a = *(int *) a;
876281806Srpaulo	int _b = *(int *) b;
877281806Srpaulo
878281806Srpaulo	if (_a == 0)
879281806Srpaulo		return 1;
880281806Srpaulo	if (_b == 0)
881281806Srpaulo		return -1;
882281806Srpaulo	return _a - _b;
883281806Srpaulo}
884281806Srpaulo
885281806Srpaulo
886281806Srpaulovoid int_array_sort_unique(int *a)
887281806Srpaulo{
888281806Srpaulo	int alen;
889281806Srpaulo	int i, j;
890281806Srpaulo
891281806Srpaulo	if (a == NULL)
892281806Srpaulo		return;
893281806Srpaulo
894281806Srpaulo	alen = int_array_len(a);
895281806Srpaulo	qsort(a, alen, sizeof(int), freq_cmp);
896281806Srpaulo
897281806Srpaulo	i = 0;
898281806Srpaulo	j = 1;
899281806Srpaulo	while (a[i] && a[j]) {
900281806Srpaulo		if (a[i] == a[j]) {
901281806Srpaulo			j++;
902281806Srpaulo			continue;
903281806Srpaulo		}
904281806Srpaulo		a[++i] = a[j++];
905281806Srpaulo	}
906281806Srpaulo	if (a[i])
907281806Srpaulo		i++;
908281806Srpaulo	a[i] = 0;
909281806Srpaulo}
910281806Srpaulo
911281806Srpaulo
912281806Srpaulovoid int_array_add_unique(int **res, int a)
913281806Srpaulo{
914281806Srpaulo	int reslen;
915281806Srpaulo	int *n;
916281806Srpaulo
917281806Srpaulo	for (reslen = 0; *res && (*res)[reslen]; reslen++) {
918281806Srpaulo		if ((*res)[reslen] == a)
919281806Srpaulo			return; /* already in the list */
920281806Srpaulo	}
921281806Srpaulo
922281806Srpaulo	n = os_realloc_array(*res, reslen + 2, sizeof(int));
923281806Srpaulo	if (n == NULL) {
924281806Srpaulo		os_free(*res);
925281806Srpaulo		*res = NULL;
926281806Srpaulo		return;
927281806Srpaulo	}
928281806Srpaulo
929281806Srpaulo	n[reslen] = a;
930281806Srpaulo	n[reslen + 1] = 0;
931281806Srpaulo
932281806Srpaulo	*res = n;
933281806Srpaulo}
934281806Srpaulo
935281806Srpaulo
936281806Srpaulovoid str_clear_free(char *str)
937281806Srpaulo{
938281806Srpaulo	if (str) {
939281806Srpaulo		size_t len = os_strlen(str);
940281806Srpaulo		os_memset(str, 0, len);
941281806Srpaulo		os_free(str);
942281806Srpaulo	}
943281806Srpaulo}
944281806Srpaulo
945281806Srpaulo
946281806Srpaulovoid bin_clear_free(void *bin, size_t len)
947281806Srpaulo{
948281806Srpaulo	if (bin) {
949281806Srpaulo		os_memset(bin, 0, len);
950281806Srpaulo		os_free(bin);
951281806Srpaulo	}
952281806Srpaulo}
953281806Srpaulo
954281806Srpaulo
955281806Srpauloint random_mac_addr(u8 *addr)
956281806Srpaulo{
957281806Srpaulo	if (os_get_random(addr, ETH_ALEN) < 0)
958281806Srpaulo		return -1;
959281806Srpaulo	addr[0] &= 0xfe; /* unicast */
960281806Srpaulo	addr[0] |= 0x02; /* locally administered */
961281806Srpaulo	return 0;
962281806Srpaulo}
963281806Srpaulo
964281806Srpaulo
965281806Srpauloint random_mac_addr_keep_oui(u8 *addr)
966281806Srpaulo{
967281806Srpaulo	if (os_get_random(addr + 3, 3) < 0)
968281806Srpaulo		return -1;
969281806Srpaulo	addr[0] &= 0xfe; /* unicast */
970281806Srpaulo	addr[0] |= 0x02; /* locally administered */
971281806Srpaulo	return 0;
972281806Srpaulo}
973281806Srpaulo
974281806Srpaulo
975281806Srpaulo/**
976289549Srpaulo * cstr_token - Get next token from const char string
977289549Srpaulo * @str: a constant string to tokenize
978289549Srpaulo * @delim: a string of delimiters
979289549Srpaulo * @last: a pointer to a character following the returned token
980289549Srpaulo *      It has to be set to NULL for the first call and passed for any
981289549Srpaulo *      futher call.
982289549Srpaulo * Returns: a pointer to token position in str or NULL
983289549Srpaulo *
984289549Srpaulo * This function is similar to str_token, but it can be used with both
985289549Srpaulo * char and const char strings. Differences:
986289549Srpaulo * - The str buffer remains unmodified
987289549Srpaulo * - The returned token is not a NULL terminated string, but a token
988289549Srpaulo *   position in str buffer. If a return value is not NULL a size
989289549Srpaulo *   of the returned token could be calculated as (last - token).
990289549Srpaulo */
991289549Srpauloconst char * cstr_token(const char *str, const char *delim, const char **last)
992289549Srpaulo{
993289549Srpaulo	const char *end, *token = str;
994289549Srpaulo
995289549Srpaulo	if (!str || !delim || !last)
996289549Srpaulo		return NULL;
997289549Srpaulo
998289549Srpaulo	if (*last)
999289549Srpaulo		token = *last;
1000289549Srpaulo
1001289549Srpaulo	while (*token && os_strchr(delim, *token))
1002289549Srpaulo		token++;
1003289549Srpaulo
1004289549Srpaulo	if (!*token)
1005289549Srpaulo		return NULL;
1006289549Srpaulo
1007289549Srpaulo	end = token + 1;
1008289549Srpaulo
1009289549Srpaulo	while (*end && !os_strchr(delim, *end))
1010289549Srpaulo		end++;
1011289549Srpaulo
1012289549Srpaulo	*last = end;
1013289549Srpaulo	return token;
1014289549Srpaulo}
1015289549Srpaulo
1016289549Srpaulo
1017289549Srpaulo/**
1018281806Srpaulo * str_token - Get next token from a string
1019281806Srpaulo * @buf: String to tokenize. Note that the string might be modified.
1020281806Srpaulo * @delim: String of delimiters
1021281806Srpaulo * @context: Pointer to save our context. Should be initialized with
1022281806Srpaulo *	NULL on the first call, and passed for any further call.
1023281806Srpaulo * Returns: The next token, NULL if there are no more valid tokens.
1024281806Srpaulo */
1025281806Srpaulochar * str_token(char *str, const char *delim, char **context)
1026281806Srpaulo{
1027289549Srpaulo	char *token = (char *) cstr_token(str, delim, (const char **) context);
1028281806Srpaulo
1029289549Srpaulo	if (token && **context)
1030289549Srpaulo		*(*context)++ = '\0';
1031281806Srpaulo
1032289549Srpaulo	return token;
1033281806Srpaulo}
1034281806Srpaulo
1035281806Srpaulo
1036281806Srpaulosize_t utf8_unescape(const char *inp, size_t in_size,
1037281806Srpaulo		     char *outp, size_t out_size)
1038281806Srpaulo{
1039281806Srpaulo	size_t res_size = 0;
1040281806Srpaulo
1041281806Srpaulo	if (!inp || !outp)
1042281806Srpaulo		return 0;
1043281806Srpaulo
1044281806Srpaulo	if (!in_size)
1045281806Srpaulo		in_size = os_strlen(inp);
1046281806Srpaulo
1047281806Srpaulo	/* Advance past leading single quote */
1048281806Srpaulo	if (*inp == '\'' && in_size) {
1049281806Srpaulo		inp++;
1050281806Srpaulo		in_size--;
1051281806Srpaulo	}
1052281806Srpaulo
1053281806Srpaulo	while (in_size--) {
1054281806Srpaulo		if (res_size >= out_size)
1055281806Srpaulo			return 0;
1056281806Srpaulo
1057281806Srpaulo		switch (*inp) {
1058281806Srpaulo		case '\'':
1059281806Srpaulo			/* Terminate on bare single quote */
1060281806Srpaulo			*outp = '\0';
1061281806Srpaulo			return res_size;
1062281806Srpaulo
1063281806Srpaulo		case '\\':
1064281806Srpaulo			if (!in_size--)
1065281806Srpaulo				return 0;
1066281806Srpaulo			inp++;
1067281806Srpaulo			/* fall through */
1068281806Srpaulo
1069281806Srpaulo		default:
1070281806Srpaulo			*outp++ = *inp++;
1071281806Srpaulo			res_size++;
1072281806Srpaulo		}
1073281806Srpaulo	}
1074281806Srpaulo
1075281806Srpaulo	/* NUL terminate if space allows */
1076281806Srpaulo	if (res_size < out_size)
1077281806Srpaulo		*outp = '\0';
1078281806Srpaulo
1079281806Srpaulo	return res_size;
1080281806Srpaulo}
1081281806Srpaulo
1082281806Srpaulo
1083281806Srpaulosize_t utf8_escape(const char *inp, size_t in_size,
1084281806Srpaulo		   char *outp, size_t out_size)
1085281806Srpaulo{
1086281806Srpaulo	size_t res_size = 0;
1087281806Srpaulo
1088281806Srpaulo	if (!inp || !outp)
1089281806Srpaulo		return 0;
1090281806Srpaulo
1091281806Srpaulo	/* inp may or may not be NUL terminated, but must be if 0 size
1092281806Srpaulo	 * is specified */
1093281806Srpaulo	if (!in_size)
1094281806Srpaulo		in_size = os_strlen(inp);
1095281806Srpaulo
1096281806Srpaulo	while (in_size--) {
1097281806Srpaulo		if (res_size++ >= out_size)
1098281806Srpaulo			return 0;
1099281806Srpaulo
1100281806Srpaulo		switch (*inp) {
1101281806Srpaulo		case '\\':
1102281806Srpaulo		case '\'':
1103281806Srpaulo			if (res_size++ >= out_size)
1104281806Srpaulo				return 0;
1105281806Srpaulo			*outp++ = '\\';
1106281806Srpaulo			/* fall through */
1107281806Srpaulo
1108281806Srpaulo		default:
1109281806Srpaulo			*outp++ = *inp++;
1110281806Srpaulo			break;
1111281806Srpaulo		}
1112281806Srpaulo	}
1113281806Srpaulo
1114281806Srpaulo	/* NUL terminate if space allows */
1115281806Srpaulo	if (res_size < out_size)
1116281806Srpaulo		*outp = '\0';
1117281806Srpaulo
1118281806Srpaulo	return res_size;
1119281806Srpaulo}
1120289549Srpaulo
1121289549Srpaulo
1122289549Srpauloint is_ctrl_char(char c)
1123289549Srpaulo{
1124289549Srpaulo	return c > 0 && c < 32;
1125289549Srpaulo}
1126