1189251Ssam/* 2189251Ssam * Dynamic data buffer 3252726Srpaulo * Copyright (c) 2007-2012, 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 11189251Ssam#include "common.h" 12214734Srpaulo#include "trace.h" 13189251Ssam#include "wpabuf.h" 14189251Ssam 15214734Srpaulo#ifdef WPA_TRACE 16214734Srpaulo#define WPABUF_MAGIC 0x51a974e3 17214734Srpaulo 18214734Srpaulostruct wpabuf_trace { 19214734Srpaulo unsigned int magic; 20289549Srpaulo} __attribute__((aligned(8))); 21214734Srpaulo 22214734Srpaulostatic struct wpabuf_trace * wpabuf_get_trace(const struct wpabuf *buf) 23214734Srpaulo{ 24214734Srpaulo return (struct wpabuf_trace *) 25214734Srpaulo ((const u8 *) buf - sizeof(struct wpabuf_trace)); 26214734Srpaulo} 27214734Srpaulo#endif /* WPA_TRACE */ 28214734Srpaulo 29214734Srpaulo 30189251Ssamstatic void wpabuf_overflow(const struct wpabuf *buf, size_t len) 31189251Ssam{ 32214734Srpaulo#ifdef WPA_TRACE 33214734Srpaulo struct wpabuf_trace *trace = wpabuf_get_trace(buf); 34214734Srpaulo if (trace->magic != WPABUF_MAGIC) { 35214734Srpaulo wpa_printf(MSG_ERROR, "wpabuf: invalid magic %x", 36214734Srpaulo trace->magic); 37214734Srpaulo } 38214734Srpaulo#endif /* WPA_TRACE */ 39189251Ssam wpa_printf(MSG_ERROR, "wpabuf %p (size=%lu used=%lu) overflow len=%lu", 40189251Ssam buf, (unsigned long) buf->size, (unsigned long) buf->used, 41189251Ssam (unsigned long) len); 42214734Srpaulo wpa_trace_show("wpabuf overflow"); 43189251Ssam abort(); 44189251Ssam} 45189251Ssam 46189251Ssam 47189251Ssamint wpabuf_resize(struct wpabuf **_buf, size_t add_len) 48189251Ssam{ 49189251Ssam struct wpabuf *buf = *_buf; 50214734Srpaulo#ifdef WPA_TRACE 51214734Srpaulo struct wpabuf_trace *trace; 52214734Srpaulo#endif /* WPA_TRACE */ 53214734Srpaulo 54209158Srpaulo if (buf == NULL) { 55209158Srpaulo *_buf = wpabuf_alloc(add_len); 56209158Srpaulo return *_buf == NULL ? -1 : 0; 57209158Srpaulo } 58214734Srpaulo 59214734Srpaulo#ifdef WPA_TRACE 60214734Srpaulo trace = wpabuf_get_trace(buf); 61214734Srpaulo if (trace->magic != WPABUF_MAGIC) { 62214734Srpaulo wpa_printf(MSG_ERROR, "wpabuf: invalid magic %x", 63214734Srpaulo trace->magic); 64214734Srpaulo wpa_trace_show("wpabuf_resize invalid magic"); 65214734Srpaulo abort(); 66214734Srpaulo } 67214734Srpaulo#endif /* WPA_TRACE */ 68214734Srpaulo 69189251Ssam if (buf->used + add_len > buf->size) { 70189251Ssam unsigned char *nbuf; 71252726Srpaulo if (buf->flags & WPABUF_FLAG_EXT_DATA) { 72252726Srpaulo nbuf = os_realloc(buf->buf, buf->used + add_len); 73189251Ssam if (nbuf == NULL) 74189251Ssam return -1; 75189251Ssam os_memset(nbuf + buf->used, 0, add_len); 76252726Srpaulo buf->buf = nbuf; 77189251Ssam } else { 78214734Srpaulo#ifdef WPA_TRACE 79214734Srpaulo nbuf = os_realloc(trace, sizeof(struct wpabuf_trace) + 80214734Srpaulo sizeof(struct wpabuf) + 81214734Srpaulo buf->used + add_len); 82214734Srpaulo if (nbuf == NULL) 83214734Srpaulo return -1; 84214734Srpaulo trace = (struct wpabuf_trace *) nbuf; 85214734Srpaulo buf = (struct wpabuf *) (trace + 1); 86214734Srpaulo os_memset(nbuf + sizeof(struct wpabuf_trace) + 87214734Srpaulo sizeof(struct wpabuf) + buf->used, 0, 88214734Srpaulo add_len); 89214734Srpaulo#else /* WPA_TRACE */ 90189251Ssam nbuf = os_realloc(buf, sizeof(struct wpabuf) + 91189251Ssam buf->used + add_len); 92189251Ssam if (nbuf == NULL) 93189251Ssam return -1; 94189251Ssam buf = (struct wpabuf *) nbuf; 95189251Ssam os_memset(nbuf + sizeof(struct wpabuf) + buf->used, 0, 96189251Ssam add_len); 97214734Srpaulo#endif /* WPA_TRACE */ 98252726Srpaulo buf->buf = (u8 *) (buf + 1); 99189251Ssam *_buf = buf; 100189251Ssam } 101189251Ssam buf->size = buf->used + add_len; 102189251Ssam } 103189251Ssam 104189251Ssam return 0; 105189251Ssam} 106189251Ssam 107189251Ssam 108189251Ssam/** 109189251Ssam * wpabuf_alloc - Allocate a wpabuf of the given size 110189251Ssam * @len: Length for the allocated buffer 111189251Ssam * Returns: Buffer to the allocated wpabuf or %NULL on failure 112189251Ssam */ 113189251Ssamstruct wpabuf * wpabuf_alloc(size_t len) 114189251Ssam{ 115214734Srpaulo#ifdef WPA_TRACE 116214734Srpaulo struct wpabuf_trace *trace = os_zalloc(sizeof(struct wpabuf_trace) + 117214734Srpaulo sizeof(struct wpabuf) + len); 118214734Srpaulo struct wpabuf *buf; 119214734Srpaulo if (trace == NULL) 120214734Srpaulo return NULL; 121214734Srpaulo trace->magic = WPABUF_MAGIC; 122214734Srpaulo buf = (struct wpabuf *) (trace + 1); 123214734Srpaulo#else /* WPA_TRACE */ 124189251Ssam struct wpabuf *buf = os_zalloc(sizeof(struct wpabuf) + len); 125189251Ssam if (buf == NULL) 126189251Ssam return NULL; 127214734Srpaulo#endif /* WPA_TRACE */ 128214734Srpaulo 129189251Ssam buf->size = len; 130252726Srpaulo buf->buf = (u8 *) (buf + 1); 131189251Ssam return buf; 132189251Ssam} 133189251Ssam 134189251Ssam 135189251Ssamstruct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len) 136189251Ssam{ 137214734Srpaulo#ifdef WPA_TRACE 138214734Srpaulo struct wpabuf_trace *trace = os_zalloc(sizeof(struct wpabuf_trace) + 139214734Srpaulo sizeof(struct wpabuf)); 140214734Srpaulo struct wpabuf *buf; 141214734Srpaulo if (trace == NULL) 142214734Srpaulo return NULL; 143214734Srpaulo trace->magic = WPABUF_MAGIC; 144214734Srpaulo buf = (struct wpabuf *) (trace + 1); 145214734Srpaulo#else /* WPA_TRACE */ 146189251Ssam struct wpabuf *buf = os_zalloc(sizeof(struct wpabuf)); 147189251Ssam if (buf == NULL) 148189251Ssam return NULL; 149214734Srpaulo#endif /* WPA_TRACE */ 150189251Ssam 151189251Ssam buf->size = len; 152189251Ssam buf->used = len; 153252726Srpaulo buf->buf = data; 154252726Srpaulo buf->flags |= WPABUF_FLAG_EXT_DATA; 155189251Ssam 156189251Ssam return buf; 157189251Ssam} 158189251Ssam 159189251Ssam 160189251Ssamstruct wpabuf * wpabuf_alloc_copy(const void *data, size_t len) 161189251Ssam{ 162189251Ssam struct wpabuf *buf = wpabuf_alloc(len); 163189251Ssam if (buf) 164189251Ssam wpabuf_put_data(buf, data, len); 165189251Ssam return buf; 166189251Ssam} 167189251Ssam 168189251Ssam 169189251Ssamstruct wpabuf * wpabuf_dup(const struct wpabuf *src) 170189251Ssam{ 171189251Ssam struct wpabuf *buf = wpabuf_alloc(wpabuf_len(src)); 172189251Ssam if (buf) 173189251Ssam wpabuf_put_data(buf, wpabuf_head(src), wpabuf_len(src)); 174189251Ssam return buf; 175189251Ssam} 176189251Ssam 177189251Ssam 178189251Ssam/** 179189251Ssam * wpabuf_free - Free a wpabuf 180189251Ssam * @buf: wpabuf buffer 181189251Ssam */ 182189251Ssamvoid wpabuf_free(struct wpabuf *buf) 183189251Ssam{ 184214734Srpaulo#ifdef WPA_TRACE 185214734Srpaulo struct wpabuf_trace *trace; 186189251Ssam if (buf == NULL) 187189251Ssam return; 188214734Srpaulo trace = wpabuf_get_trace(buf); 189214734Srpaulo if (trace->magic != WPABUF_MAGIC) { 190214734Srpaulo wpa_printf(MSG_ERROR, "wpabuf_free: invalid magic %x", 191214734Srpaulo trace->magic); 192214734Srpaulo wpa_trace_show("wpabuf_free magic mismatch"); 193214734Srpaulo abort(); 194214734Srpaulo } 195252726Srpaulo if (buf->flags & WPABUF_FLAG_EXT_DATA) 196252726Srpaulo os_free(buf->buf); 197214734Srpaulo os_free(trace); 198214734Srpaulo#else /* WPA_TRACE */ 199214734Srpaulo if (buf == NULL) 200214734Srpaulo return; 201252726Srpaulo if (buf->flags & WPABUF_FLAG_EXT_DATA) 202252726Srpaulo os_free(buf->buf); 203189251Ssam os_free(buf); 204214734Srpaulo#endif /* WPA_TRACE */ 205189251Ssam} 206189251Ssam 207189251Ssam 208281806Srpaulovoid wpabuf_clear_free(struct wpabuf *buf) 209281806Srpaulo{ 210281806Srpaulo if (buf) { 211281806Srpaulo os_memset(wpabuf_mhead(buf), 0, wpabuf_len(buf)); 212281806Srpaulo wpabuf_free(buf); 213281806Srpaulo } 214281806Srpaulo} 215281806Srpaulo 216281806Srpaulo 217189251Ssamvoid * wpabuf_put(struct wpabuf *buf, size_t len) 218189251Ssam{ 219189251Ssam void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf); 220189251Ssam buf->used += len; 221189251Ssam if (buf->used > buf->size) { 222189251Ssam wpabuf_overflow(buf, len); 223189251Ssam } 224189251Ssam return tmp; 225189251Ssam} 226189251Ssam 227189251Ssam 228189251Ssam/** 229189251Ssam * wpabuf_concat - Concatenate two buffers into a newly allocated one 230189251Ssam * @a: First buffer 231189251Ssam * @b: Second buffer 232189251Ssam * Returns: wpabuf with concatenated a + b data or %NULL on failure 233189251Ssam * 234189251Ssam * Both buffers a and b will be freed regardless of the return value. Input 235189251Ssam * buffers can be %NULL which is interpreted as an empty buffer. 236189251Ssam */ 237189251Ssamstruct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b) 238189251Ssam{ 239189251Ssam struct wpabuf *n = NULL; 240189251Ssam size_t len = 0; 241189251Ssam 242189251Ssam if (b == NULL) 243189251Ssam return a; 244189251Ssam 245189251Ssam if (a) 246189251Ssam len += wpabuf_len(a); 247346981Scy len += wpabuf_len(b); 248189251Ssam 249189251Ssam n = wpabuf_alloc(len); 250189251Ssam if (n) { 251189251Ssam if (a) 252189251Ssam wpabuf_put_buf(n, a); 253346981Scy wpabuf_put_buf(n, b); 254189251Ssam } 255189251Ssam 256189251Ssam wpabuf_free(a); 257189251Ssam wpabuf_free(b); 258189251Ssam 259189251Ssam return n; 260189251Ssam} 261189251Ssam 262189251Ssam 263189251Ssam/** 264189251Ssam * wpabuf_zeropad - Pad buffer with 0x00 octets (prefix) to specified length 265189251Ssam * @buf: Buffer to be padded 266189251Ssam * @len: Length for the padded buffer 267189251Ssam * Returns: wpabuf padded to len octets or %NULL on failure 268189251Ssam * 269189251Ssam * If buf is longer than len octets or of same size, it will be returned as-is. 270189251Ssam * Otherwise a new buffer is allocated and prefixed with 0x00 octets followed 271189251Ssam * by the source data. The source buffer will be freed on error, i.e., caller 272189251Ssam * will only be responsible on freeing the returned buffer. If buf is %NULL, 273189251Ssam * %NULL will be returned. 274189251Ssam */ 275189251Ssamstruct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len) 276189251Ssam{ 277189251Ssam struct wpabuf *ret; 278189251Ssam size_t blen; 279189251Ssam 280189251Ssam if (buf == NULL) 281189251Ssam return NULL; 282189251Ssam 283189251Ssam blen = wpabuf_len(buf); 284189251Ssam if (blen >= len) 285189251Ssam return buf; 286189251Ssam 287189251Ssam ret = wpabuf_alloc(len); 288189251Ssam if (ret) { 289189251Ssam os_memset(wpabuf_put(ret, len - blen), 0, len - blen); 290189251Ssam wpabuf_put_buf(ret, buf); 291189251Ssam } 292189251Ssam wpabuf_free(buf); 293189251Ssam 294189251Ssam return ret; 295189251Ssam} 296189251Ssam 297189251Ssam 298189251Ssamvoid wpabuf_printf(struct wpabuf *buf, char *fmt, ...) 299189251Ssam{ 300189251Ssam va_list ap; 301189251Ssam void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf); 302189251Ssam int res; 303189251Ssam 304189251Ssam va_start(ap, fmt); 305189251Ssam res = vsnprintf(tmp, buf->size - buf->used, fmt, ap); 306189251Ssam va_end(ap); 307189251Ssam if (res < 0 || (size_t) res >= buf->size - buf->used) 308189251Ssam wpabuf_overflow(buf, res); 309189251Ssam buf->used += res; 310189251Ssam} 311337817Scy 312337817Scy 313337817Scy/** 314337817Scy * wpabuf_parse_bin - Parse a null terminated string of binary data to a wpabuf 315337817Scy * @buf: Buffer with null terminated string (hexdump) of binary data 316337817Scy * Returns: wpabuf or %NULL on failure 317337817Scy * 318337817Scy * The string len must be a multiple of two and contain only hexadecimal digits. 319337817Scy */ 320337817Scystruct wpabuf * wpabuf_parse_bin(const char *buf) 321337817Scy{ 322337817Scy size_t len; 323337817Scy struct wpabuf *ret; 324337817Scy 325337817Scy len = os_strlen(buf); 326337817Scy if (len & 0x01) 327337817Scy return NULL; 328337817Scy len /= 2; 329337817Scy 330337817Scy ret = wpabuf_alloc(len); 331337817Scy if (ret == NULL) 332337817Scy return NULL; 333337817Scy 334337817Scy if (hexstr2bin(buf, wpabuf_put(ret, len), len)) { 335337817Scy wpabuf_free(ret); 336337817Scy return NULL; 337337817Scy } 338337817Scy 339337817Scy return ret; 340337817Scy} 341