1189251Ssam/* 2189251Ssam * Dynamic data buffer 3189251Ssam * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi> 4189251Ssam * 5189251Ssam * This program is free software; you can redistribute it and/or modify 6189251Ssam * it under the terms of the GNU General Public License version 2 as 7189251Ssam * published by the Free Software Foundation. 8189251Ssam * 9189251Ssam * Alternatively, this software may be distributed under the terms of BSD 10189251Ssam * license. 11189251Ssam * 12189251Ssam * See README and COPYING for more details. 13189251Ssam */ 14189251Ssam 15189251Ssam#include "includes.h" 16189251Ssam 17189251Ssam#include "common.h" 18214734Srpaulo#include "trace.h" 19189251Ssam#include "wpabuf.h" 20189251Ssam 21214734Srpaulo#ifdef WPA_TRACE 22214734Srpaulo#define WPABUF_MAGIC 0x51a974e3 23214734Srpaulo 24214734Srpaulostruct wpabuf_trace { 25214734Srpaulo unsigned int magic; 26214734Srpaulo}; 27214734Srpaulo 28214734Srpaulostatic struct wpabuf_trace * wpabuf_get_trace(const struct wpabuf *buf) 29214734Srpaulo{ 30214734Srpaulo return (struct wpabuf_trace *) 31214734Srpaulo ((const u8 *) buf - sizeof(struct wpabuf_trace)); 32214734Srpaulo} 33214734Srpaulo#endif /* WPA_TRACE */ 34214734Srpaulo 35214734Srpaulo 36189251Ssamstatic void wpabuf_overflow(const struct wpabuf *buf, size_t len) 37189251Ssam{ 38214734Srpaulo#ifdef WPA_TRACE 39214734Srpaulo struct wpabuf_trace *trace = wpabuf_get_trace(buf); 40214734Srpaulo if (trace->magic != WPABUF_MAGIC) { 41214734Srpaulo wpa_printf(MSG_ERROR, "wpabuf: invalid magic %x", 42214734Srpaulo trace->magic); 43214734Srpaulo } 44214734Srpaulo#endif /* WPA_TRACE */ 45189251Ssam wpa_printf(MSG_ERROR, "wpabuf %p (size=%lu used=%lu) overflow len=%lu", 46189251Ssam buf, (unsigned long) buf->size, (unsigned long) buf->used, 47189251Ssam (unsigned long) len); 48214734Srpaulo wpa_trace_show("wpabuf overflow"); 49189251Ssam abort(); 50189251Ssam} 51189251Ssam 52189251Ssam 53189251Ssamint wpabuf_resize(struct wpabuf **_buf, size_t add_len) 54189251Ssam{ 55189251Ssam struct wpabuf *buf = *_buf; 56214734Srpaulo#ifdef WPA_TRACE 57214734Srpaulo struct wpabuf_trace *trace; 58214734Srpaulo#endif /* WPA_TRACE */ 59214734Srpaulo 60209158Srpaulo if (buf == NULL) { 61209158Srpaulo *_buf = wpabuf_alloc(add_len); 62209158Srpaulo return *_buf == NULL ? -1 : 0; 63209158Srpaulo } 64214734Srpaulo 65214734Srpaulo#ifdef WPA_TRACE 66214734Srpaulo trace = wpabuf_get_trace(buf); 67214734Srpaulo if (trace->magic != WPABUF_MAGIC) { 68214734Srpaulo wpa_printf(MSG_ERROR, "wpabuf: invalid magic %x", 69214734Srpaulo trace->magic); 70214734Srpaulo wpa_trace_show("wpabuf_resize invalid magic"); 71214734Srpaulo abort(); 72214734Srpaulo } 73214734Srpaulo#endif /* WPA_TRACE */ 74214734Srpaulo 75189251Ssam if (buf->used + add_len > buf->size) { 76189251Ssam unsigned char *nbuf; 77189251Ssam if (buf->ext_data) { 78189251Ssam nbuf = os_realloc(buf->ext_data, buf->used + add_len); 79189251Ssam if (nbuf == NULL) 80189251Ssam return -1; 81189251Ssam os_memset(nbuf + buf->used, 0, add_len); 82189251Ssam buf->ext_data = nbuf; 83189251Ssam } else { 84214734Srpaulo#ifdef WPA_TRACE 85214734Srpaulo nbuf = os_realloc(trace, sizeof(struct wpabuf_trace) + 86214734Srpaulo sizeof(struct wpabuf) + 87214734Srpaulo buf->used + add_len); 88214734Srpaulo if (nbuf == NULL) 89214734Srpaulo return -1; 90214734Srpaulo trace = (struct wpabuf_trace *) nbuf; 91214734Srpaulo buf = (struct wpabuf *) (trace + 1); 92214734Srpaulo os_memset(nbuf + sizeof(struct wpabuf_trace) + 93214734Srpaulo sizeof(struct wpabuf) + buf->used, 0, 94214734Srpaulo add_len); 95214734Srpaulo#else /* WPA_TRACE */ 96189251Ssam nbuf = os_realloc(buf, sizeof(struct wpabuf) + 97189251Ssam buf->used + add_len); 98189251Ssam if (nbuf == NULL) 99189251Ssam return -1; 100189251Ssam buf = (struct wpabuf *) nbuf; 101189251Ssam os_memset(nbuf + sizeof(struct wpabuf) + buf->used, 0, 102189251Ssam add_len); 103214734Srpaulo#endif /* WPA_TRACE */ 104189251Ssam *_buf = buf; 105189251Ssam } 106189251Ssam buf->size = buf->used + add_len; 107189251Ssam } 108189251Ssam 109189251Ssam return 0; 110189251Ssam} 111189251Ssam 112189251Ssam 113189251Ssam/** 114189251Ssam * wpabuf_alloc - Allocate a wpabuf of the given size 115189251Ssam * @len: Length for the allocated buffer 116189251Ssam * Returns: Buffer to the allocated wpabuf or %NULL on failure 117189251Ssam */ 118189251Ssamstruct wpabuf * wpabuf_alloc(size_t len) 119189251Ssam{ 120214734Srpaulo#ifdef WPA_TRACE 121214734Srpaulo struct wpabuf_trace *trace = os_zalloc(sizeof(struct wpabuf_trace) + 122214734Srpaulo sizeof(struct wpabuf) + len); 123214734Srpaulo struct wpabuf *buf; 124214734Srpaulo if (trace == NULL) 125214734Srpaulo return NULL; 126214734Srpaulo trace->magic = WPABUF_MAGIC; 127214734Srpaulo buf = (struct wpabuf *) (trace + 1); 128214734Srpaulo#else /* WPA_TRACE */ 129189251Ssam struct wpabuf *buf = os_zalloc(sizeof(struct wpabuf) + len); 130189251Ssam if (buf == NULL) 131189251Ssam return NULL; 132214734Srpaulo#endif /* WPA_TRACE */ 133214734Srpaulo 134189251Ssam buf->size = len; 135189251Ssam return buf; 136189251Ssam} 137189251Ssam 138189251Ssam 139189251Ssamstruct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len) 140189251Ssam{ 141214734Srpaulo#ifdef WPA_TRACE 142214734Srpaulo struct wpabuf_trace *trace = os_zalloc(sizeof(struct wpabuf_trace) + 143214734Srpaulo sizeof(struct wpabuf)); 144214734Srpaulo struct wpabuf *buf; 145214734Srpaulo if (trace == NULL) 146214734Srpaulo return NULL; 147214734Srpaulo trace->magic = WPABUF_MAGIC; 148214734Srpaulo buf = (struct wpabuf *) (trace + 1); 149214734Srpaulo#else /* WPA_TRACE */ 150189251Ssam struct wpabuf *buf = os_zalloc(sizeof(struct wpabuf)); 151189251Ssam if (buf == NULL) 152189251Ssam return NULL; 153214734Srpaulo#endif /* WPA_TRACE */ 154189251Ssam 155189251Ssam buf->size = len; 156189251Ssam buf->used = len; 157189251Ssam buf->ext_data = data; 158189251Ssam 159189251Ssam return buf; 160189251Ssam} 161189251Ssam 162189251Ssam 163189251Ssamstruct wpabuf * wpabuf_alloc_copy(const void *data, size_t len) 164189251Ssam{ 165189251Ssam struct wpabuf *buf = wpabuf_alloc(len); 166189251Ssam if (buf) 167189251Ssam wpabuf_put_data(buf, data, len); 168189251Ssam return buf; 169189251Ssam} 170189251Ssam 171189251Ssam 172189251Ssamstruct wpabuf * wpabuf_dup(const struct wpabuf *src) 173189251Ssam{ 174189251Ssam struct wpabuf *buf = wpabuf_alloc(wpabuf_len(src)); 175189251Ssam if (buf) 176189251Ssam wpabuf_put_data(buf, wpabuf_head(src), wpabuf_len(src)); 177189251Ssam return buf; 178189251Ssam} 179189251Ssam 180189251Ssam 181189251Ssam/** 182189251Ssam * wpabuf_free - Free a wpabuf 183189251Ssam * @buf: wpabuf buffer 184189251Ssam */ 185189251Ssamvoid wpabuf_free(struct wpabuf *buf) 186189251Ssam{ 187214734Srpaulo#ifdef WPA_TRACE 188214734Srpaulo struct wpabuf_trace *trace; 189189251Ssam if (buf == NULL) 190189251Ssam return; 191214734Srpaulo trace = wpabuf_get_trace(buf); 192214734Srpaulo if (trace->magic != WPABUF_MAGIC) { 193214734Srpaulo wpa_printf(MSG_ERROR, "wpabuf_free: invalid magic %x", 194214734Srpaulo trace->magic); 195214734Srpaulo wpa_trace_show("wpabuf_free magic mismatch"); 196214734Srpaulo abort(); 197214734Srpaulo } 198189251Ssam os_free(buf->ext_data); 199214734Srpaulo os_free(trace); 200214734Srpaulo#else /* WPA_TRACE */ 201214734Srpaulo if (buf == NULL) 202214734Srpaulo return; 203214734Srpaulo os_free(buf->ext_data); 204189251Ssam os_free(buf); 205214734Srpaulo#endif /* WPA_TRACE */ 206189251Ssam} 207189251Ssam 208189251Ssam 209189251Ssamvoid * wpabuf_put(struct wpabuf *buf, size_t len) 210189251Ssam{ 211189251Ssam void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf); 212189251Ssam buf->used += len; 213189251Ssam if (buf->used > buf->size) { 214189251Ssam wpabuf_overflow(buf, len); 215189251Ssam } 216189251Ssam return tmp; 217189251Ssam} 218189251Ssam 219189251Ssam 220189251Ssam/** 221189251Ssam * wpabuf_concat - Concatenate two buffers into a newly allocated one 222189251Ssam * @a: First buffer 223189251Ssam * @b: Second buffer 224189251Ssam * Returns: wpabuf with concatenated a + b data or %NULL on failure 225189251Ssam * 226189251Ssam * Both buffers a and b will be freed regardless of the return value. Input 227189251Ssam * buffers can be %NULL which is interpreted as an empty buffer. 228189251Ssam */ 229189251Ssamstruct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b) 230189251Ssam{ 231189251Ssam struct wpabuf *n = NULL; 232189251Ssam size_t len = 0; 233189251Ssam 234189251Ssam if (b == NULL) 235189251Ssam return a; 236189251Ssam 237189251Ssam if (a) 238189251Ssam len += wpabuf_len(a); 239189251Ssam if (b) 240189251Ssam len += wpabuf_len(b); 241189251Ssam 242189251Ssam n = wpabuf_alloc(len); 243189251Ssam if (n) { 244189251Ssam if (a) 245189251Ssam wpabuf_put_buf(n, a); 246189251Ssam if (b) 247189251Ssam wpabuf_put_buf(n, b); 248189251Ssam } 249189251Ssam 250189251Ssam wpabuf_free(a); 251189251Ssam wpabuf_free(b); 252189251Ssam 253189251Ssam return n; 254189251Ssam} 255189251Ssam 256189251Ssam 257189251Ssam/** 258189251Ssam * wpabuf_zeropad - Pad buffer with 0x00 octets (prefix) to specified length 259189251Ssam * @buf: Buffer to be padded 260189251Ssam * @len: Length for the padded buffer 261189251Ssam * Returns: wpabuf padded to len octets or %NULL on failure 262189251Ssam * 263189251Ssam * If buf is longer than len octets or of same size, it will be returned as-is. 264189251Ssam * Otherwise a new buffer is allocated and prefixed with 0x00 octets followed 265189251Ssam * by the source data. The source buffer will be freed on error, i.e., caller 266189251Ssam * will only be responsible on freeing the returned buffer. If buf is %NULL, 267189251Ssam * %NULL will be returned. 268189251Ssam */ 269189251Ssamstruct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len) 270189251Ssam{ 271189251Ssam struct wpabuf *ret; 272189251Ssam size_t blen; 273189251Ssam 274189251Ssam if (buf == NULL) 275189251Ssam return NULL; 276189251Ssam 277189251Ssam blen = wpabuf_len(buf); 278189251Ssam if (blen >= len) 279189251Ssam return buf; 280189251Ssam 281189251Ssam ret = wpabuf_alloc(len); 282189251Ssam if (ret) { 283189251Ssam os_memset(wpabuf_put(ret, len - blen), 0, len - blen); 284189251Ssam wpabuf_put_buf(ret, buf); 285189251Ssam } 286189251Ssam wpabuf_free(buf); 287189251Ssam 288189251Ssam return ret; 289189251Ssam} 290189251Ssam 291189251Ssam 292189251Ssamvoid wpabuf_printf(struct wpabuf *buf, char *fmt, ...) 293189251Ssam{ 294189251Ssam va_list ap; 295189251Ssam void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf); 296189251Ssam int res; 297189251Ssam 298189251Ssam va_start(ap, fmt); 299189251Ssam res = vsnprintf(tmp, buf->size - buf->used, fmt, ap); 300189251Ssam va_end(ap); 301189251Ssam if (res < 0 || (size_t) res >= buf->size - buf->used) 302189251Ssam wpabuf_overflow(buf, res); 303189251Ssam buf->used += res; 304189251Ssam} 305