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; 20214734Srpaulo}; 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 208189251Ssamvoid * wpabuf_put(struct wpabuf *buf, size_t len) 209189251Ssam{ 210189251Ssam void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf); 211189251Ssam buf->used += len; 212189251Ssam if (buf->used > buf->size) { 213189251Ssam wpabuf_overflow(buf, len); 214189251Ssam } 215189251Ssam return tmp; 216189251Ssam} 217189251Ssam 218189251Ssam 219189251Ssam/** 220189251Ssam * wpabuf_concat - Concatenate two buffers into a newly allocated one 221189251Ssam * @a: First buffer 222189251Ssam * @b: Second buffer 223189251Ssam * Returns: wpabuf with concatenated a + b data or %NULL on failure 224189251Ssam * 225189251Ssam * Both buffers a and b will be freed regardless of the return value. Input 226189251Ssam * buffers can be %NULL which is interpreted as an empty buffer. 227189251Ssam */ 228189251Ssamstruct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b) 229189251Ssam{ 230189251Ssam struct wpabuf *n = NULL; 231189251Ssam size_t len = 0; 232189251Ssam 233189251Ssam if (b == NULL) 234189251Ssam return a; 235189251Ssam 236189251Ssam if (a) 237189251Ssam len += wpabuf_len(a); 238189251Ssam if (b) 239189251Ssam len += wpabuf_len(b); 240189251Ssam 241189251Ssam n = wpabuf_alloc(len); 242189251Ssam if (n) { 243189251Ssam if (a) 244189251Ssam wpabuf_put_buf(n, a); 245189251Ssam if (b) 246189251Ssam wpabuf_put_buf(n, b); 247189251Ssam } 248189251Ssam 249189251Ssam wpabuf_free(a); 250189251Ssam wpabuf_free(b); 251189251Ssam 252189251Ssam return n; 253189251Ssam} 254189251Ssam 255189251Ssam 256189251Ssam/** 257189251Ssam * wpabuf_zeropad - Pad buffer with 0x00 octets (prefix) to specified length 258189251Ssam * @buf: Buffer to be padded 259189251Ssam * @len: Length for the padded buffer 260189251Ssam * Returns: wpabuf padded to len octets or %NULL on failure 261189251Ssam * 262189251Ssam * If buf is longer than len octets or of same size, it will be returned as-is. 263189251Ssam * Otherwise a new buffer is allocated and prefixed with 0x00 octets followed 264189251Ssam * by the source data. The source buffer will be freed on error, i.e., caller 265189251Ssam * will only be responsible on freeing the returned buffer. If buf is %NULL, 266189251Ssam * %NULL will be returned. 267189251Ssam */ 268189251Ssamstruct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len) 269189251Ssam{ 270189251Ssam struct wpabuf *ret; 271189251Ssam size_t blen; 272189251Ssam 273189251Ssam if (buf == NULL) 274189251Ssam return NULL; 275189251Ssam 276189251Ssam blen = wpabuf_len(buf); 277189251Ssam if (blen >= len) 278189251Ssam return buf; 279189251Ssam 280189251Ssam ret = wpabuf_alloc(len); 281189251Ssam if (ret) { 282189251Ssam os_memset(wpabuf_put(ret, len - blen), 0, len - blen); 283189251Ssam wpabuf_put_buf(ret, buf); 284189251Ssam } 285189251Ssam wpabuf_free(buf); 286189251Ssam 287189251Ssam return ret; 288189251Ssam} 289189251Ssam 290189251Ssam 291189251Ssamvoid wpabuf_printf(struct wpabuf *buf, char *fmt, ...) 292189251Ssam{ 293189251Ssam va_list ap; 294189251Ssam void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf); 295189251Ssam int res; 296189251Ssam 297189251Ssam va_start(ap, fmt); 298189251Ssam res = vsnprintf(tmp, buf->size - buf->used, fmt, ap); 299189251Ssam va_end(ap); 300189251Ssam if (res < 0 || (size_t) res >= buf->size - buf->used) 301189251Ssam wpabuf_overflow(buf, res); 302189251Ssam buf->used += res; 303189251Ssam} 304