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