xref: /freebsd/contrib/wpa/src/utils/wpabuf.c (revision 67350cb56a69468c118bd4ccf6e361b7ebfa9eb4)
139beb93cSSam Leffler /*
239beb93cSSam Leffler  * Dynamic data buffer
3f05cddf9SRui Paulo  * Copyright (c) 2007-2012, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo  * See README for more details.
739beb93cSSam Leffler  */
839beb93cSSam Leffler 
939beb93cSSam Leffler #include "includes.h"
1039beb93cSSam Leffler 
1139beb93cSSam Leffler #include "common.h"
12e28a4053SRui Paulo #include "trace.h"
1339beb93cSSam Leffler #include "wpabuf.h"
1439beb93cSSam Leffler 
15e28a4053SRui Paulo #ifdef WPA_TRACE
16e28a4053SRui Paulo #define WPABUF_MAGIC 0x51a974e3
17e28a4053SRui Paulo 
18e28a4053SRui Paulo struct wpabuf_trace {
19e28a4053SRui Paulo 	unsigned int magic;
20325151a3SRui Paulo } __attribute__((aligned(8)));
21e28a4053SRui Paulo 
wpabuf_get_trace(const struct wpabuf * buf)22e28a4053SRui Paulo static struct wpabuf_trace * wpabuf_get_trace(const struct wpabuf *buf)
23e28a4053SRui Paulo {
24e28a4053SRui Paulo 	return (struct wpabuf_trace *)
25e28a4053SRui Paulo 		((const u8 *) buf - sizeof(struct wpabuf_trace));
26e28a4053SRui Paulo }
27e28a4053SRui Paulo #endif /* WPA_TRACE */
28e28a4053SRui Paulo 
29e28a4053SRui Paulo 
wpabuf_overflow(const struct wpabuf * buf,size_t len)3039beb93cSSam Leffler static void wpabuf_overflow(const struct wpabuf *buf, size_t len)
3139beb93cSSam Leffler {
32e28a4053SRui Paulo #ifdef WPA_TRACE
33e28a4053SRui Paulo 	struct wpabuf_trace *trace = wpabuf_get_trace(buf);
34e28a4053SRui Paulo 	if (trace->magic != WPABUF_MAGIC) {
35e28a4053SRui Paulo 		wpa_printf(MSG_ERROR, "wpabuf: invalid magic %x",
36e28a4053SRui Paulo 			   trace->magic);
37e28a4053SRui Paulo 	}
38e28a4053SRui Paulo #endif /* WPA_TRACE */
3939beb93cSSam Leffler 	wpa_printf(MSG_ERROR, "wpabuf %p (size=%lu used=%lu) overflow len=%lu",
4039beb93cSSam Leffler 		   buf, (unsigned long) buf->size, (unsigned long) buf->used,
4139beb93cSSam Leffler 		   (unsigned long) len);
42e28a4053SRui Paulo 	wpa_trace_show("wpabuf overflow");
4339beb93cSSam Leffler 	abort();
4439beb93cSSam Leffler }
4539beb93cSSam Leffler 
4639beb93cSSam Leffler 
wpabuf_resize(struct wpabuf ** _buf,size_t add_len)4739beb93cSSam Leffler int wpabuf_resize(struct wpabuf **_buf, size_t add_len)
4839beb93cSSam Leffler {
4939beb93cSSam Leffler 	struct wpabuf *buf = *_buf;
50e28a4053SRui Paulo #ifdef WPA_TRACE
51e28a4053SRui Paulo 	struct wpabuf_trace *trace;
52e28a4053SRui Paulo #endif /* WPA_TRACE */
53e28a4053SRui Paulo 
543157ba21SRui Paulo 	if (buf == NULL) {
553157ba21SRui Paulo 		*_buf = wpabuf_alloc(add_len);
563157ba21SRui Paulo 		return *_buf == NULL ? -1 : 0;
573157ba21SRui Paulo 	}
58e28a4053SRui Paulo 
59e28a4053SRui Paulo #ifdef WPA_TRACE
60e28a4053SRui Paulo 	trace = wpabuf_get_trace(buf);
61e28a4053SRui Paulo 	if (trace->magic != WPABUF_MAGIC) {
62e28a4053SRui Paulo 		wpa_printf(MSG_ERROR, "wpabuf: invalid magic %x",
63e28a4053SRui Paulo 			   trace->magic);
64e28a4053SRui Paulo 		wpa_trace_show("wpabuf_resize invalid magic");
65e28a4053SRui Paulo 		abort();
66e28a4053SRui Paulo 	}
67e28a4053SRui Paulo #endif /* WPA_TRACE */
68e28a4053SRui Paulo 
6939beb93cSSam Leffler 	if (buf->used + add_len > buf->size) {
7039beb93cSSam Leffler 		unsigned char *nbuf;
71f05cddf9SRui Paulo 		if (buf->flags & WPABUF_FLAG_EXT_DATA) {
72f05cddf9SRui Paulo 			nbuf = os_realloc(buf->buf, buf->used + add_len);
7339beb93cSSam Leffler 			if (nbuf == NULL)
7439beb93cSSam Leffler 				return -1;
7539beb93cSSam Leffler 			os_memset(nbuf + buf->used, 0, add_len);
76f05cddf9SRui Paulo 			buf->buf = nbuf;
7739beb93cSSam Leffler 		} else {
78e28a4053SRui Paulo #ifdef WPA_TRACE
79e28a4053SRui Paulo 			nbuf = os_realloc(trace, sizeof(struct wpabuf_trace) +
80e28a4053SRui Paulo 					  sizeof(struct wpabuf) +
81e28a4053SRui Paulo 					  buf->used + add_len);
82e28a4053SRui Paulo 			if (nbuf == NULL)
83e28a4053SRui Paulo 				return -1;
84e28a4053SRui Paulo 			trace = (struct wpabuf_trace *) nbuf;
85e28a4053SRui Paulo 			buf = (struct wpabuf *) (trace + 1);
86e28a4053SRui Paulo 			os_memset(nbuf + sizeof(struct wpabuf_trace) +
87e28a4053SRui Paulo 				  sizeof(struct wpabuf) + buf->used, 0,
88e28a4053SRui Paulo 				  add_len);
89e28a4053SRui Paulo #else /* WPA_TRACE */
9039beb93cSSam Leffler 			nbuf = os_realloc(buf, sizeof(struct wpabuf) +
9139beb93cSSam Leffler 					  buf->used + add_len);
9239beb93cSSam Leffler 			if (nbuf == NULL)
9339beb93cSSam Leffler 				return -1;
9439beb93cSSam Leffler 			buf = (struct wpabuf *) nbuf;
9539beb93cSSam Leffler 			os_memset(nbuf + sizeof(struct wpabuf) + buf->used, 0,
9639beb93cSSam Leffler 				  add_len);
97e28a4053SRui Paulo #endif /* WPA_TRACE */
98f05cddf9SRui Paulo 			buf->buf = (u8 *) (buf + 1);
9939beb93cSSam Leffler 			*_buf = buf;
10039beb93cSSam Leffler 		}
10139beb93cSSam Leffler 		buf->size = buf->used + add_len;
10239beb93cSSam Leffler 	}
10339beb93cSSam Leffler 
10439beb93cSSam Leffler 	return 0;
10539beb93cSSam Leffler }
10639beb93cSSam Leffler 
10739beb93cSSam Leffler 
10839beb93cSSam Leffler /**
10939beb93cSSam Leffler  * wpabuf_alloc - Allocate a wpabuf of the given size
11039beb93cSSam Leffler  * @len: Length for the allocated buffer
11139beb93cSSam Leffler  * Returns: Buffer to the allocated wpabuf or %NULL on failure
11239beb93cSSam Leffler  */
wpabuf_alloc(size_t len)11339beb93cSSam Leffler struct wpabuf * wpabuf_alloc(size_t len)
11439beb93cSSam Leffler {
115e28a4053SRui Paulo #ifdef WPA_TRACE
116e28a4053SRui Paulo 	struct wpabuf_trace *trace = os_zalloc(sizeof(struct wpabuf_trace) +
117e28a4053SRui Paulo 					       sizeof(struct wpabuf) + len);
118e28a4053SRui Paulo 	struct wpabuf *buf;
119e28a4053SRui Paulo 	if (trace == NULL)
120e28a4053SRui Paulo 		return NULL;
121e28a4053SRui Paulo 	trace->magic = WPABUF_MAGIC;
122e28a4053SRui Paulo 	buf = (struct wpabuf *) (trace + 1);
123e28a4053SRui Paulo #else /* WPA_TRACE */
12439beb93cSSam Leffler 	struct wpabuf *buf = os_zalloc(sizeof(struct wpabuf) + len);
12539beb93cSSam Leffler 	if (buf == NULL)
12639beb93cSSam Leffler 		return NULL;
127e28a4053SRui Paulo #endif /* WPA_TRACE */
128e28a4053SRui Paulo 
12939beb93cSSam Leffler 	buf->size = len;
130f05cddf9SRui Paulo 	buf->buf = (u8 *) (buf + 1);
13139beb93cSSam Leffler 	return buf;
13239beb93cSSam Leffler }
13339beb93cSSam Leffler 
13439beb93cSSam Leffler 
wpabuf_alloc_ext_data(u8 * data,size_t len)13539beb93cSSam Leffler struct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len)
13639beb93cSSam Leffler {
137e28a4053SRui Paulo #ifdef WPA_TRACE
138e28a4053SRui Paulo 	struct wpabuf_trace *trace = os_zalloc(sizeof(struct wpabuf_trace) +
139e28a4053SRui Paulo 					       sizeof(struct wpabuf));
140e28a4053SRui Paulo 	struct wpabuf *buf;
141e28a4053SRui Paulo 	if (trace == NULL)
142e28a4053SRui Paulo 		return NULL;
143e28a4053SRui Paulo 	trace->magic = WPABUF_MAGIC;
144e28a4053SRui Paulo 	buf = (struct wpabuf *) (trace + 1);
145e28a4053SRui Paulo #else /* WPA_TRACE */
14639beb93cSSam Leffler 	struct wpabuf *buf = os_zalloc(sizeof(struct wpabuf));
14739beb93cSSam Leffler 	if (buf == NULL)
14839beb93cSSam Leffler 		return NULL;
149e28a4053SRui Paulo #endif /* WPA_TRACE */
15039beb93cSSam Leffler 
15139beb93cSSam Leffler 	buf->size = len;
15239beb93cSSam Leffler 	buf->used = len;
153f05cddf9SRui Paulo 	buf->buf = data;
154f05cddf9SRui Paulo 	buf->flags |= WPABUF_FLAG_EXT_DATA;
15539beb93cSSam Leffler 
15639beb93cSSam Leffler 	return buf;
15739beb93cSSam Leffler }
15839beb93cSSam Leffler 
15939beb93cSSam Leffler 
wpabuf_alloc_copy(const void * data,size_t len)16039beb93cSSam Leffler struct wpabuf * wpabuf_alloc_copy(const void *data, size_t len)
16139beb93cSSam Leffler {
16239beb93cSSam Leffler 	struct wpabuf *buf = wpabuf_alloc(len);
16339beb93cSSam Leffler 	if (buf)
16439beb93cSSam Leffler 		wpabuf_put_data(buf, data, len);
16539beb93cSSam Leffler 	return buf;
16639beb93cSSam Leffler }
16739beb93cSSam Leffler 
16839beb93cSSam Leffler 
wpabuf_dup(const struct wpabuf * src)16939beb93cSSam Leffler struct wpabuf * wpabuf_dup(const struct wpabuf *src)
17039beb93cSSam Leffler {
17139beb93cSSam Leffler 	struct wpabuf *buf = wpabuf_alloc(wpabuf_len(src));
17239beb93cSSam Leffler 	if (buf)
17339beb93cSSam Leffler 		wpabuf_put_data(buf, wpabuf_head(src), wpabuf_len(src));
17439beb93cSSam Leffler 	return buf;
17539beb93cSSam Leffler }
17639beb93cSSam Leffler 
17739beb93cSSam Leffler 
17839beb93cSSam Leffler /**
17939beb93cSSam Leffler  * wpabuf_free - Free a wpabuf
18039beb93cSSam Leffler  * @buf: wpabuf buffer
18139beb93cSSam Leffler  */
wpabuf_free(struct wpabuf * buf)18239beb93cSSam Leffler void wpabuf_free(struct wpabuf *buf)
18339beb93cSSam Leffler {
184e28a4053SRui Paulo #ifdef WPA_TRACE
185e28a4053SRui Paulo 	struct wpabuf_trace *trace;
186e28a4053SRui Paulo 	if (buf == NULL)
187e28a4053SRui Paulo 		return;
188e28a4053SRui Paulo 	trace = wpabuf_get_trace(buf);
189e28a4053SRui Paulo 	if (trace->magic != WPABUF_MAGIC) {
190e28a4053SRui Paulo 		wpa_printf(MSG_ERROR, "wpabuf_free: invalid magic %x",
191e28a4053SRui Paulo 			   trace->magic);
192e28a4053SRui Paulo 		wpa_trace_show("wpabuf_free magic mismatch");
193e28a4053SRui Paulo 		abort();
194e28a4053SRui Paulo 	}
195f05cddf9SRui Paulo 	if (buf->flags & WPABUF_FLAG_EXT_DATA)
196f05cddf9SRui Paulo 		os_free(buf->buf);
197e28a4053SRui Paulo 	os_free(trace);
198e28a4053SRui Paulo #else /* WPA_TRACE */
19939beb93cSSam Leffler 	if (buf == NULL)
20039beb93cSSam Leffler 		return;
201f05cddf9SRui Paulo 	if (buf->flags & WPABUF_FLAG_EXT_DATA)
202f05cddf9SRui Paulo 		os_free(buf->buf);
20339beb93cSSam Leffler 	os_free(buf);
204e28a4053SRui Paulo #endif /* WPA_TRACE */
20539beb93cSSam Leffler }
20639beb93cSSam Leffler 
20739beb93cSSam Leffler 
wpabuf_clear_free(struct wpabuf * buf)2085b9c547cSRui Paulo void wpabuf_clear_free(struct wpabuf *buf)
2095b9c547cSRui Paulo {
2105b9c547cSRui Paulo 	if (buf) {
2115b9c547cSRui Paulo 		os_memset(wpabuf_mhead(buf), 0, wpabuf_len(buf));
2125b9c547cSRui Paulo 		wpabuf_free(buf);
2135b9c547cSRui Paulo 	}
2145b9c547cSRui Paulo }
2155b9c547cSRui Paulo 
2165b9c547cSRui Paulo 
wpabuf_put(struct wpabuf * buf,size_t len)21739beb93cSSam Leffler void * wpabuf_put(struct wpabuf *buf, size_t len)
21839beb93cSSam Leffler {
21939beb93cSSam Leffler 	void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf);
22039beb93cSSam Leffler 	buf->used += len;
22139beb93cSSam Leffler 	if (buf->used > buf->size) {
22239beb93cSSam Leffler 		wpabuf_overflow(buf, len);
22339beb93cSSam Leffler 	}
22439beb93cSSam Leffler 	return tmp;
22539beb93cSSam Leffler }
22639beb93cSSam Leffler 
22739beb93cSSam Leffler 
22839beb93cSSam Leffler /**
22939beb93cSSam Leffler  * wpabuf_concat - Concatenate two buffers into a newly allocated one
23039beb93cSSam Leffler  * @a: First buffer
23139beb93cSSam Leffler  * @b: Second buffer
23239beb93cSSam Leffler  * Returns: wpabuf with concatenated a + b data or %NULL on failure
23339beb93cSSam Leffler  *
23439beb93cSSam Leffler  * Both buffers a and b will be freed regardless of the return value. Input
23539beb93cSSam Leffler  * buffers can be %NULL which is interpreted as an empty buffer.
23639beb93cSSam Leffler  */
wpabuf_concat(struct wpabuf * a,struct wpabuf * b)23739beb93cSSam Leffler struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b)
23839beb93cSSam Leffler {
23939beb93cSSam Leffler 	struct wpabuf *n = NULL;
24039beb93cSSam Leffler 	size_t len = 0;
24139beb93cSSam Leffler 
24239beb93cSSam Leffler 	if (b == NULL)
24339beb93cSSam Leffler 		return a;
24439beb93cSSam Leffler 
24539beb93cSSam Leffler 	if (a)
24639beb93cSSam Leffler 		len += wpabuf_len(a);
24739beb93cSSam Leffler 	len += wpabuf_len(b);
24839beb93cSSam Leffler 
24939beb93cSSam Leffler 	n = wpabuf_alloc(len);
25039beb93cSSam Leffler 	if (n) {
25139beb93cSSam Leffler 		if (a)
25239beb93cSSam Leffler 			wpabuf_put_buf(n, a);
25339beb93cSSam Leffler 		wpabuf_put_buf(n, b);
25439beb93cSSam Leffler 	}
25539beb93cSSam Leffler 
25639beb93cSSam Leffler 	wpabuf_free(a);
25739beb93cSSam Leffler 	wpabuf_free(b);
25839beb93cSSam Leffler 
25939beb93cSSam Leffler 	return n;
26039beb93cSSam Leffler }
26139beb93cSSam Leffler 
26239beb93cSSam Leffler 
26339beb93cSSam Leffler /**
26439beb93cSSam Leffler  * wpabuf_zeropad - Pad buffer with 0x00 octets (prefix) to specified length
26539beb93cSSam Leffler  * @buf: Buffer to be padded
26639beb93cSSam Leffler  * @len: Length for the padded buffer
26739beb93cSSam Leffler  * Returns: wpabuf padded to len octets or %NULL on failure
26839beb93cSSam Leffler  *
26939beb93cSSam Leffler  * If buf is longer than len octets or of same size, it will be returned as-is.
27039beb93cSSam Leffler  * Otherwise a new buffer is allocated and prefixed with 0x00 octets followed
27139beb93cSSam Leffler  * by the source data. The source buffer will be freed on error, i.e., caller
27239beb93cSSam Leffler  * will only be responsible on freeing the returned buffer. If buf is %NULL,
27339beb93cSSam Leffler  * %NULL will be returned.
27439beb93cSSam Leffler  */
wpabuf_zeropad(struct wpabuf * buf,size_t len)27539beb93cSSam Leffler struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len)
27639beb93cSSam Leffler {
27739beb93cSSam Leffler 	struct wpabuf *ret;
27839beb93cSSam Leffler 	size_t blen;
27939beb93cSSam Leffler 
28039beb93cSSam Leffler 	if (buf == NULL)
28139beb93cSSam Leffler 		return NULL;
28239beb93cSSam Leffler 
28339beb93cSSam Leffler 	blen = wpabuf_len(buf);
28439beb93cSSam Leffler 	if (blen >= len)
28539beb93cSSam Leffler 		return buf;
28639beb93cSSam Leffler 
28739beb93cSSam Leffler 	ret = wpabuf_alloc(len);
28839beb93cSSam Leffler 	if (ret) {
28939beb93cSSam Leffler 		os_memset(wpabuf_put(ret, len - blen), 0, len - blen);
29039beb93cSSam Leffler 		wpabuf_put_buf(ret, buf);
29139beb93cSSam Leffler 	}
29239beb93cSSam Leffler 	wpabuf_free(buf);
29339beb93cSSam Leffler 
29439beb93cSSam Leffler 	return ret;
29539beb93cSSam Leffler }
29639beb93cSSam Leffler 
29739beb93cSSam Leffler 
wpabuf_printf(struct wpabuf * buf,char * fmt,...)29839beb93cSSam Leffler void wpabuf_printf(struct wpabuf *buf, char *fmt, ...)
29939beb93cSSam Leffler {
30039beb93cSSam Leffler 	va_list ap;
30139beb93cSSam Leffler 	void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf);
30239beb93cSSam Leffler 	int res;
30339beb93cSSam Leffler 
30439beb93cSSam Leffler 	va_start(ap, fmt);
30539beb93cSSam Leffler 	res = vsnprintf(tmp, buf->size - buf->used, fmt, ap);
30639beb93cSSam Leffler 	va_end(ap);
30739beb93cSSam Leffler 	if (res < 0 || (size_t) res >= buf->size - buf->used)
30839beb93cSSam Leffler 		wpabuf_overflow(buf, res);
30939beb93cSSam Leffler 	buf->used += res;
31039beb93cSSam Leffler }
311*780fb4a2SCy Schubert 
312*780fb4a2SCy Schubert 
313*780fb4a2SCy Schubert /**
314*780fb4a2SCy Schubert  * wpabuf_parse_bin - Parse a null terminated string of binary data to a wpabuf
315*780fb4a2SCy Schubert  * @buf: Buffer with null terminated string (hexdump) of binary data
316*780fb4a2SCy Schubert  * Returns: wpabuf or %NULL on failure
317*780fb4a2SCy Schubert  *
318*780fb4a2SCy Schubert  * The string len must be a multiple of two and contain only hexadecimal digits.
319*780fb4a2SCy Schubert  */
wpabuf_parse_bin(const char * buf)320*780fb4a2SCy Schubert struct wpabuf * wpabuf_parse_bin(const char *buf)
321*780fb4a2SCy Schubert {
322*780fb4a2SCy Schubert 	size_t len;
323*780fb4a2SCy Schubert 	struct wpabuf *ret;
324*780fb4a2SCy Schubert 
325*780fb4a2SCy Schubert 	len = os_strlen(buf);
326*780fb4a2SCy Schubert 	if (len & 0x01)
327*780fb4a2SCy Schubert 		return NULL;
328*780fb4a2SCy Schubert 	len /= 2;
329*780fb4a2SCy Schubert 
330*780fb4a2SCy Schubert 	ret = wpabuf_alloc(len);
331*780fb4a2SCy Schubert 	if (ret == NULL)
332*780fb4a2SCy Schubert 		return NULL;
333*780fb4a2SCy Schubert 
334*780fb4a2SCy Schubert 	if (hexstr2bin(buf, wpabuf_put(ret, len), len)) {
335*780fb4a2SCy Schubert 		wpabuf_free(ret);
336*780fb4a2SCy Schubert 		return NULL;
337*780fb4a2SCy Schubert 	}
338*780fb4a2SCy Schubert 
339*780fb4a2SCy Schubert 	return ret;
340*780fb4a2SCy Schubert }
341