]>
Commit | Line | Data |
---|---|---|
6fc6879b JM |
1 | /* |
2 | * Dynamic data buffer | |
1871f711 | 3 | * Copyright (c) 2007-2012, Jouni Malinen <j@w1.fi> |
6fc6879b | 4 | * |
0f3d578e JM |
5 | * This software may be distributed under the terms of the BSD license. |
6 | * See README for more details. | |
6fc6879b JM |
7 | */ |
8 | ||
9 | #include "includes.h" | |
10 | ||
11 | #include "common.h" | |
eeb04821 | 12 | #include "trace.h" |
6fc6879b JM |
13 | #include "wpabuf.h" |
14 | ||
eeb04821 JM |
15 | #ifdef WPA_TRACE |
16 | #define WPABUF_MAGIC 0x51a974e3 | |
17 | ||
18 | struct wpabuf_trace { | |
19 | unsigned int magic; | |
e01281fc | 20 | } __attribute__((aligned(8))); |
eeb04821 | 21 | |
2e854275 | 22 | static struct wpabuf_trace * wpabuf_get_trace(const struct wpabuf *buf) |
eeb04821 JM |
23 | { |
24 | return (struct wpabuf_trace *) | |
25 | ((const u8 *) buf - sizeof(struct wpabuf_trace)); | |
26 | } | |
27 | #endif /* WPA_TRACE */ | |
28 | ||
29 | ||
6fc6879b JM |
30 | static void wpabuf_overflow(const struct wpabuf *buf, size_t len) |
31 | { | |
eeb04821 JM |
32 | #ifdef WPA_TRACE |
33 | struct wpabuf_trace *trace = wpabuf_get_trace(buf); | |
34 | if (trace->magic != WPABUF_MAGIC) { | |
35 | wpa_printf(MSG_ERROR, "wpabuf: invalid magic %x", | |
36 | trace->magic); | |
37 | } | |
38 | #endif /* WPA_TRACE */ | |
6fc6879b JM |
39 | wpa_printf(MSG_ERROR, "wpabuf %p (size=%lu used=%lu) overflow len=%lu", |
40 | buf, (unsigned long) buf->size, (unsigned long) buf->used, | |
41 | (unsigned long) len); | |
eeb04821 | 42 | wpa_trace_show("wpabuf overflow"); |
6fc6879b JM |
43 | abort(); |
44 | } | |
45 | ||
46 | ||
47 | int wpabuf_resize(struct wpabuf **_buf, size_t add_len) | |
48 | { | |
49 | struct wpabuf *buf = *_buf; | |
eeb04821 JM |
50 | #ifdef WPA_TRACE |
51 | struct wpabuf_trace *trace; | |
52 | #endif /* WPA_TRACE */ | |
53 | ||
859db534 JM |
54 | if (buf == NULL) { |
55 | *_buf = wpabuf_alloc(add_len); | |
56 | return *_buf == NULL ? -1 : 0; | |
57 | } | |
eeb04821 JM |
58 | |
59 | #ifdef WPA_TRACE | |
60 | trace = wpabuf_get_trace(buf); | |
61 | if (trace->magic != WPABUF_MAGIC) { | |
62 | wpa_printf(MSG_ERROR, "wpabuf: invalid magic %x", | |
63 | trace->magic); | |
64 | wpa_trace_show("wpabuf_resize invalid magic"); | |
65 | abort(); | |
66 | } | |
67 | #endif /* WPA_TRACE */ | |
68 | ||
6fc6879b JM |
69 | if (buf->used + add_len > buf->size) { |
70 | unsigned char *nbuf; | |
1871f711 JM |
71 | if (buf->flags & WPABUF_FLAG_EXT_DATA) { |
72 | nbuf = os_realloc(buf->buf, buf->used + add_len); | |
6fc6879b JM |
73 | if (nbuf == NULL) |
74 | return -1; | |
75 | os_memset(nbuf + buf->used, 0, add_len); | |
1871f711 | 76 | buf->buf = nbuf; |
6fc6879b | 77 | } else { |
eeb04821 JM |
78 | #ifdef WPA_TRACE |
79 | nbuf = os_realloc(trace, sizeof(struct wpabuf_trace) + | |
80 | sizeof(struct wpabuf) + | |
81 | buf->used + add_len); | |
82 | if (nbuf == NULL) | |
83 | return -1; | |
84 | trace = (struct wpabuf_trace *) nbuf; | |
85 | buf = (struct wpabuf *) (trace + 1); | |
86 | os_memset(nbuf + sizeof(struct wpabuf_trace) + | |
87 | sizeof(struct wpabuf) + buf->used, 0, | |
88 | add_len); | |
89 | #else /* WPA_TRACE */ | |
6fc6879b JM |
90 | nbuf = os_realloc(buf, sizeof(struct wpabuf) + |
91 | buf->used + add_len); | |
92 | if (nbuf == NULL) | |
93 | return -1; | |
94 | buf = (struct wpabuf *) nbuf; | |
95 | os_memset(nbuf + sizeof(struct wpabuf) + buf->used, 0, | |
96 | add_len); | |
eeb04821 | 97 | #endif /* WPA_TRACE */ |
1871f711 | 98 | buf->buf = (u8 *) (buf + 1); |
6fc6879b JM |
99 | *_buf = buf; |
100 | } | |
101 | buf->size = buf->used + add_len; | |
102 | } | |
103 | ||
104 | return 0; | |
105 | } | |
106 | ||
107 | ||
108 | /** | |
109 | * wpabuf_alloc - Allocate a wpabuf of the given size | |
110 | * @len: Length for the allocated buffer | |
111 | * Returns: Buffer to the allocated wpabuf or %NULL on failure | |
112 | */ | |
113 | struct wpabuf * wpabuf_alloc(size_t len) | |
114 | { | |
eeb04821 JM |
115 | #ifdef WPA_TRACE |
116 | struct wpabuf_trace *trace = os_zalloc(sizeof(struct wpabuf_trace) + | |
117 | sizeof(struct wpabuf) + len); | |
118 | struct wpabuf *buf; | |
119 | if (trace == NULL) | |
120 | return NULL; | |
121 | trace->magic = WPABUF_MAGIC; | |
122 | buf = (struct wpabuf *) (trace + 1); | |
123 | #else /* WPA_TRACE */ | |
6fc6879b JM |
124 | struct wpabuf *buf = os_zalloc(sizeof(struct wpabuf) + len); |
125 | if (buf == NULL) | |
126 | return NULL; | |
eeb04821 JM |
127 | #endif /* WPA_TRACE */ |
128 | ||
6fc6879b | 129 | buf->size = len; |
1871f711 | 130 | buf->buf = (u8 *) (buf + 1); |
6fc6879b JM |
131 | return buf; |
132 | } | |
133 | ||
134 | ||
135 | struct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len) | |
136 | { | |
eeb04821 JM |
137 | #ifdef WPA_TRACE |
138 | struct wpabuf_trace *trace = os_zalloc(sizeof(struct wpabuf_trace) + | |
139 | sizeof(struct wpabuf)); | |
140 | struct wpabuf *buf; | |
141 | if (trace == NULL) | |
142 | return NULL; | |
143 | trace->magic = WPABUF_MAGIC; | |
144 | buf = (struct wpabuf *) (trace + 1); | |
145 | #else /* WPA_TRACE */ | |
6fc6879b JM |
146 | struct wpabuf *buf = os_zalloc(sizeof(struct wpabuf)); |
147 | if (buf == NULL) | |
148 | return NULL; | |
eeb04821 | 149 | #endif /* WPA_TRACE */ |
6fc6879b JM |
150 | |
151 | buf->size = len; | |
152 | buf->used = len; | |
1871f711 JM |
153 | buf->buf = data; |
154 | buf->flags |= WPABUF_FLAG_EXT_DATA; | |
6fc6879b JM |
155 | |
156 | return buf; | |
157 | } | |
158 | ||
159 | ||
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 | ||
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 | */ | |
182 | void wpabuf_free(struct wpabuf *buf) | |
183 | { | |
eeb04821 JM |
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 | wpa_trace_show("wpabuf_free magic mismatch"); | |
193 | abort(); | |
194 | } | |
1871f711 JM |
195 | if (buf->flags & WPABUF_FLAG_EXT_DATA) |
196 | os_free(buf->buf); | |
eeb04821 JM |
197 | os_free(trace); |
198 | #else /* WPA_TRACE */ | |
6fc6879b JM |
199 | if (buf == NULL) |
200 | return; | |
1871f711 JM |
201 | if (buf->flags & WPABUF_FLAG_EXT_DATA) |
202 | os_free(buf->buf); | |
6fc6879b | 203 | os_free(buf); |
eeb04821 | 204 | #endif /* WPA_TRACE */ |
6fc6879b JM |
205 | } |
206 | ||
207 | ||
77c45e2b JM |
208 | void wpabuf_clear_free(struct wpabuf *buf) |
209 | { | |
210 | if (buf) { | |
211 | os_memset(wpabuf_mhead(buf), 0, wpabuf_len(buf)); | |
212 | wpabuf_free(buf); | |
213 | } | |
214 | } | |
215 | ||
216 | ||
6fc6879b JM |
217 | void * wpabuf_put(struct wpabuf *buf, size_t len) |
218 | { | |
219 | void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf); | |
220 | buf->used += len; | |
221 | if (buf->used > buf->size) { | |
222 | wpabuf_overflow(buf, len); | |
223 | } | |
224 | return tmp; | |
225 | } | |
7914585f JM |
226 | |
227 | ||
228 | /** | |
229 | * wpabuf_concat - Concatenate two buffers into a newly allocated one | |
230 | * @a: First buffer | |
231 | * @b: Second buffer | |
232 | * Returns: wpabuf with concatenated a + b data or %NULL on failure | |
233 | * | |
234 | * Both buffers a and b will be freed regardless of the return value. Input | |
235 | * buffers can be %NULL which is interpreted as an empty buffer. | |
236 | */ | |
237 | struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b) | |
238 | { | |
239 | struct wpabuf *n = NULL; | |
240 | size_t len = 0; | |
241 | ||
242 | if (b == NULL) | |
243 | return a; | |
244 | ||
245 | if (a) | |
246 | len += wpabuf_len(a); | |
230b2b2c | 247 | len += wpabuf_len(b); |
7914585f JM |
248 | |
249 | n = wpabuf_alloc(len); | |
250 | if (n) { | |
251 | if (a) | |
252 | wpabuf_put_buf(n, a); | |
230b2b2c | 253 | wpabuf_put_buf(n, b); |
7914585f JM |
254 | } |
255 | ||
256 | wpabuf_free(a); | |
257 | wpabuf_free(b); | |
258 | ||
259 | return n; | |
260 | } | |
b3ddab21 JM |
261 | |
262 | ||
263 | /** | |
264 | * wpabuf_zeropad - Pad buffer with 0x00 octets (prefix) to specified length | |
265 | * @buf: Buffer to be padded | |
266 | * @len: Length for the padded buffer | |
267 | * Returns: wpabuf padded to len octets or %NULL on failure | |
268 | * | |
269 | * If buf is longer than len octets or of same size, it will be returned as-is. | |
270 | * Otherwise a new buffer is allocated and prefixed with 0x00 octets followed | |
271 | * by the source data. The source buffer will be freed on error, i.e., caller | |
272 | * will only be responsible on freeing the returned buffer. If buf is %NULL, | |
273 | * %NULL will be returned. | |
274 | */ | |
275 | struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len) | |
276 | { | |
277 | struct wpabuf *ret; | |
278 | size_t blen; | |
279 | ||
280 | if (buf == NULL) | |
281 | return NULL; | |
282 | ||
283 | blen = wpabuf_len(buf); | |
284 | if (blen >= len) | |
285 | return buf; | |
286 | ||
287 | ret = wpabuf_alloc(len); | |
288 | if (ret) { | |
289 | os_memset(wpabuf_put(ret, len - blen), 0, len - blen); | |
290 | wpabuf_put_buf(ret, buf); | |
291 | } | |
292 | wpabuf_free(buf); | |
293 | ||
294 | return ret; | |
295 | } | |
f620268f JM |
296 | |
297 | ||
298 | void wpabuf_printf(struct wpabuf *buf, char *fmt, ...) | |
299 | { | |
300 | va_list ap; | |
301 | void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf); | |
302 | int res; | |
303 | ||
304 | va_start(ap, fmt); | |
305 | res = vsnprintf(tmp, buf->size - buf->used, fmt, ap); | |
306 | va_end(ap); | |
307 | if (res < 0 || (size_t) res >= buf->size - buf->used) | |
308 | wpabuf_overflow(buf, res); | |
309 | buf->used += res; | |
310 | } | |
9d955f75 DS |
311 | |
312 | ||
313 | /** | |
314 | * wpabuf_parse_bin - Parse a null terminated string of binary data to a wpabuf | |
315 | * @buf: Buffer with null terminated string (hexdump) of binary data | |
316 | * Returns: wpabuf or %NULL on failure | |
317 | * | |
318 | * The string len must be a multiple of two and contain only hexadecimal digits. | |
319 | */ | |
320 | struct wpabuf * wpabuf_parse_bin(const char *buf) | |
321 | { | |
322 | size_t len; | |
323 | struct wpabuf *ret; | |
324 | ||
325 | len = os_strlen(buf); | |
326 | if (len & 0x01) | |
327 | return NULL; | |
328 | len /= 2; | |
329 | ||
330 | ret = wpabuf_alloc(len); | |
331 | if (ret == NULL) | |
332 | return NULL; | |
333 | ||
334 | if (hexstr2bin(buf, wpabuf_put(ret, len), len)) { | |
335 | wpabuf_free(ret); | |
336 | return NULL; | |
337 | } | |
338 | ||
339 | return ret; | |
340 | } |