1 /*
2 * Dynamic data buffer
3 * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
11 *
12 * See README and COPYING for more details.
13 */
14
15 #include "utils/includes.h"
16
17 #include "utils/common.h"
18 #include "utils/wpabuf.h"
19 #include "stdio.h"
20 #include "stdarg.h"
21
22 #ifdef WPA_TRACE
23 #define WPABUF_MAGIC 0x51a974e3
24
25 struct wpabuf_trace {
26 unsigned int magic;
27 };
28
wpabuf_get_trace(const struct wpabuf * buf)29 static struct wpabuf_trace * wpabuf_get_trace(const struct wpabuf *buf)
30 {
31 return (struct wpabuf_trace *)
32 ((const u8 *) buf - sizeof(struct wpabuf_trace));
33 }
34 #endif /* WPA_TRACE */
35
36
wpabuf_overflow(const struct wpabuf * buf,size_t len)37 static void wpabuf_overflow(const struct wpabuf *buf, size_t len)
38 {
39 #ifdef WPA_TRACE
40 struct wpabuf_trace *trace = wpabuf_get_trace(buf);
41 if (trace->magic != WPABUF_MAGIC) {
42 wpa_printf( MSG_ERROR, "wpabuf: invalid magic %x",
43 trace->magic);
44 }
45 #endif /* WPA_TRACE */
46 wpa_printf( MSG_ERROR, "wpabuf %p (size=%lu used=%lu) overflow len=%lu",
47 buf, (unsigned long) buf->size, (unsigned long) buf->used,
48 (unsigned long) len);
49 }
50
51
wpabuf_resize(struct wpabuf ** _buf,size_t add_len)52 int wpabuf_resize(struct wpabuf **_buf, size_t add_len)
53 {
54 struct wpabuf *buf = *_buf;
55 #ifdef WPA_TRACE
56 struct wpabuf_trace *trace;
57 #endif /* WPA_TRACE */
58
59 if (buf == NULL) {
60 *_buf = wpabuf_alloc(add_len);
61 return *_buf == NULL ? -1 : 0;
62 }
63
64 #ifdef WPA_TRACE
65 trace = wpabuf_get_trace(buf);
66 if (trace->magic != WPABUF_MAGIC) {
67 wpa_printf( MSG_ERROR, "wpabuf: invalid magic %x",
68 trace->magic);
69 abort();
70 }
71 #endif /* WPA_TRACE */
72
73 if (buf->used + add_len > buf->size) {
74 unsigned char *nbuf;
75 if (buf->ext_data) {
76 nbuf = (unsigned char*)os_realloc(buf->ext_data, buf->used + add_len);
77 if (nbuf == NULL)
78 return -1;
79 memset(nbuf + buf->used, 0, add_len);
80 buf->ext_data = nbuf;
81 } else {
82 #ifdef WPA_TRACE
83 nbuf = os_realloc(trace, sizeof(struct wpabuf_trace) +
84 sizeof(struct wpabuf) +
85 buf->used + add_len);
86 if (nbuf == NULL)
87 return -1;
88 trace = (struct wpabuf_trace *) nbuf;
89 buf = (struct wpabuf *) (trace + 1);
90 memset(nbuf + sizeof(struct wpabuf_trace) +
91 sizeof(struct wpabuf) + buf->used, 0,
92 add_len);
93 #else /* WPA_TRACE */
94 nbuf = (unsigned char*)os_realloc(buf, sizeof(struct wpabuf) +
95 buf->used + add_len);
96 if (nbuf == NULL)
97 return -1;
98 buf = (struct wpabuf *) nbuf;
99 memset(nbuf + sizeof(struct wpabuf) + buf->used, 0,
100 add_len);
101 #endif /* WPA_TRACE */
102 *_buf = buf;
103 }
104 buf->size = buf->used + add_len;
105 }
106
107 return 0;
108 }
109
110
111 /**
112 * wpabuf_alloc - Allocate a wpabuf of the given size
113 * @len: Length for the allocated buffer
114 * Returns: Buffer to the allocated wpabuf or %NULL on failure
115 */
wpabuf_alloc(size_t len)116 struct wpabuf * wpabuf_alloc(size_t len)
117 {
118 #ifdef WPA_TRACE
119 struct wpabuf_trace *trace = os_zalloc(sizeof(struct wpabuf_trace) +
120 sizeof(struct wpabuf) + len);
121 struct wpabuf *buf;
122 if (trace == NULL)
123 return NULL;
124 trace->magic = WPABUF_MAGIC;
125 buf = (struct wpabuf *) (trace + 1);
126 #else /* WPA_TRACE */
127 struct wpabuf *buf = (struct wpabuf *)os_zalloc(sizeof(struct wpabuf) + len);
128 if (buf == NULL)
129 return NULL;
130 #endif /* WPA_TRACE */
131
132 buf->size = len;
133 return buf;
134 }
135
wpabuf_alloc_ext_data(u8 * data,size_t len)136 struct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len)
137 {
138 #ifdef WPA_TRACE
139 struct wpabuf_trace *trace = os_zalloc(sizeof(struct wpabuf_trace) +
140 sizeof(struct wpabuf));
141 struct wpabuf *buf;
142 if (trace == NULL)
143 return NULL;
144 trace->magic = WPABUF_MAGIC;
145 buf = (struct wpabuf *) (trace + 1);
146 #else /* WPA_TRACE */
147 struct wpabuf *buf = (struct wpabuf *)os_zalloc(sizeof(struct wpabuf));
148 if (buf == NULL)
149 return NULL;
150 #endif /* WPA_TRACE */
151
152 buf->size = len;
153 buf->used = len;
154 buf->ext_data = data;
155
156 return buf;
157 }
158
159
wpabuf_alloc_copy(const void * data,size_t len)160 struct wpabuf * wpabuf_alloc_copy(const void *data, size_t len)
161 {
162 struct wpabuf *buf = wpabuf_alloc(len);
163 if (buf)
164 wpabuf_put_data(buf, data, len);
165 return buf;
166 }
167
168
wpabuf_dup(const struct wpabuf * src)169 struct wpabuf * wpabuf_dup(const struct wpabuf *src)
170 {
171 struct wpabuf *buf = wpabuf_alloc(wpabuf_len(src));
172 if (buf)
173 wpabuf_put_data(buf, wpabuf_head(src), wpabuf_len(src));
174 return buf;
175 }
176
177
178 /**
179 * wpabuf_free - Free a wpabuf
180 * @buf: wpabuf buffer
181 */
wpabuf_free(struct wpabuf * buf)182 void wpabuf_free(struct wpabuf *buf)
183 {
184 #ifdef WPA_TRACE
185 struct wpabuf_trace *trace;
186 if (buf == NULL)
187 return;
188 trace = wpabuf_get_trace(buf);
189 if (trace->magic != WPABUF_MAGIC) {
190 wpa_printf( MSG_ERROR, "wpabuf_free: invalid magic %x",
191 trace->magic);
192 abort();
193 }
194 os_free(buf->ext_data);
195 os_free(trace);
196 #else /* WPA_TRACE */
197 if (buf == NULL)
198 return;
199 os_free(buf->ext_data);
200 os_free(buf);
201 #endif /* WPA_TRACE */
202 }
203
204
wpabuf_put(struct wpabuf * buf,size_t len)205 void * wpabuf_put(struct wpabuf *buf, size_t len)
206 {
207 void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf);
208 buf->used += len;
209 if (buf->used > buf->size) {
210 wpabuf_overflow(buf, len);
211 }
212 return tmp;
213 }
214
215
216 /**
217 * wpabuf_concat - Concatenate two buffers into a newly allocated one
218 * @a: First buffer
219 * @b: Second buffer
220 * Returns: wpabuf with concatenated a + b data or %NULL on failure
221 *
222 * Both buffers a and b will be freed regardless of the return value. Input
223 * buffers can be %NULL which is interpreted as an empty buffer.
224 */
wpabuf_concat(struct wpabuf * a,struct wpabuf * b)225 struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b)
226 {
227 struct wpabuf *n = NULL;
228 size_t len = 0;
229
230 if (b == NULL)
231 return a;
232
233 if (a)
234 len += wpabuf_len(a);
235 if (b)
236 len += wpabuf_len(b);
237
238 n = wpabuf_alloc(len);
239 if (n) {
240 if (a)
241 wpabuf_put_buf(n, a);
242 if (b)
243 wpabuf_put_buf(n, b);
244 }
245
246 wpabuf_free(a);
247 wpabuf_free(b);
248
249 return n;
250 }
251
252
253 /**
254 * wpabuf_zeropad - Pad buffer with 0x00 octets (prefix) to specified length
255 * @buf: Buffer to be padded
256 * @len: Length for the padded buffer
257 * Returns: wpabuf padded to len octets or %NULL on failure
258 *
259 * If buf is longer than len octets or of same size, it will be returned as-is.
260 * Otherwise a new buffer is allocated and prefixed with 0x00 octets followed
261 * by the source data. The source buffer will be freed on error, i.e., caller
262 * will only be responsible on freeing the returned buffer. If buf is %NULL,
263 * %NULL will be returned.
264 */
wpabuf_zeropad(struct wpabuf * buf,size_t len)265 struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len)
266 {
267 struct wpabuf *ret;
268 size_t blen;
269
270 if (buf == NULL)
271 return NULL;
272
273 blen = wpabuf_len(buf);
274 if (blen >= len)
275 return buf;
276
277 ret = wpabuf_alloc(len);
278 if (ret) {
279 memset(wpabuf_put(ret, len - blen), 0, len - blen);
280 wpabuf_put_buf(ret, buf);
281 }
282 wpabuf_free(buf);
283
284 return ret;
285 }
286
wpabuf_printf(struct wpabuf * buf,const char * fmt,...)287 void wpabuf_printf(struct wpabuf *buf, const char *fmt, ...)
288 {
289 va_list ap;
290 void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf);
291 int res;
292
293 va_start(ap, fmt);
294 res = vsnprintf(tmp, buf->size - buf->used, fmt, ap);
295 va_end(ap);
296 if (res < 0 || (size_t) res >= buf->size - buf->used)
297 wpabuf_overflow(buf, res);
298 buf->used += res;
299 }
300