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