]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - contrib/wpa/src/utils/wpabuf.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / contrib / wpa / src / utils / wpabuf.c
1 /*
2  * Dynamic data buffer
3  * Copyright (c) 2007-2009, Jouni Malinen <j@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 "wpabuf.h"
19
20 static void wpabuf_overflow(const struct wpabuf *buf, size_t len)
21 {
22         wpa_printf(MSG_ERROR, "wpabuf %p (size=%lu used=%lu) overflow len=%lu",
23                    buf, (unsigned long) buf->size, (unsigned long) buf->used,
24                    (unsigned long) len);
25         abort();
26 }
27
28
29 int wpabuf_resize(struct wpabuf **_buf, size_t add_len)
30 {
31         struct wpabuf *buf = *_buf;
32         if (buf->used + add_len > buf->size) {
33                 unsigned char *nbuf;
34                 if (buf->ext_data) {
35                         nbuf = os_realloc(buf->ext_data, buf->used + add_len);
36                         if (nbuf == NULL)
37                                 return -1;
38                         os_memset(nbuf + buf->used, 0, add_len);
39                         buf->ext_data = nbuf;
40                 } else {
41                         nbuf = os_realloc(buf, sizeof(struct wpabuf) +
42                                           buf->used + add_len);
43                         if (nbuf == NULL)
44                                 return -1;
45                         buf = (struct wpabuf *) nbuf;
46                         os_memset(nbuf + sizeof(struct wpabuf) + buf->used, 0,
47                                   add_len);
48                         *_buf = buf;
49                 }
50                 buf->size = buf->used + add_len;
51         }
52
53         return 0;
54 }
55
56
57 /**
58  * wpabuf_alloc - Allocate a wpabuf of the given size
59  * @len: Length for the allocated buffer
60  * Returns: Buffer to the allocated wpabuf or %NULL on failure
61  */
62 struct wpabuf * wpabuf_alloc(size_t len)
63 {
64         struct wpabuf *buf = os_zalloc(sizeof(struct wpabuf) + len);
65         if (buf == NULL)
66                 return NULL;
67         buf->size = len;
68         return buf;
69 }
70
71
72 struct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len)
73 {
74         struct wpabuf *buf = os_zalloc(sizeof(struct wpabuf));
75         if (buf == NULL)
76                 return NULL;
77
78         buf->size = len;
79         buf->used = len;
80         buf->ext_data = data;
81
82         return buf;
83 }
84
85
86 struct wpabuf * wpabuf_alloc_copy(const void *data, size_t len)
87 {
88         struct wpabuf *buf = wpabuf_alloc(len);
89         if (buf)
90                 wpabuf_put_data(buf, data, len);
91         return buf;
92 }
93
94
95 struct wpabuf * wpabuf_dup(const struct wpabuf *src)
96 {
97         struct wpabuf *buf = wpabuf_alloc(wpabuf_len(src));
98         if (buf)
99                 wpabuf_put_data(buf, wpabuf_head(src), wpabuf_len(src));
100         return buf;
101 }
102
103
104 /**
105  * wpabuf_free - Free a wpabuf
106  * @buf: wpabuf buffer
107  */
108 void wpabuf_free(struct wpabuf *buf)
109 {
110         if (buf == NULL)
111                 return;
112         os_free(buf->ext_data);
113         os_free(buf);
114 }
115
116
117 void * wpabuf_put(struct wpabuf *buf, size_t len)
118 {
119         void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf);
120         buf->used += len;
121         if (buf->used > buf->size) {
122                 wpabuf_overflow(buf, len);
123         }
124         return tmp;
125 }
126
127
128 /**
129  * wpabuf_concat - Concatenate two buffers into a newly allocated one
130  * @a: First buffer
131  * @b: Second buffer
132  * Returns: wpabuf with concatenated a + b data or %NULL on failure
133  *
134  * Both buffers a and b will be freed regardless of the return value. Input
135  * buffers can be %NULL which is interpreted as an empty buffer.
136  */
137 struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b)
138 {
139         struct wpabuf *n = NULL;
140         size_t len = 0;
141
142         if (b == NULL)
143                 return a;
144
145         if (a)
146                 len += wpabuf_len(a);
147         if (b)
148                 len += wpabuf_len(b);
149
150         n = wpabuf_alloc(len);
151         if (n) {
152                 if (a)
153                         wpabuf_put_buf(n, a);
154                 if (b)
155                         wpabuf_put_buf(n, b);
156         }
157
158         wpabuf_free(a);
159         wpabuf_free(b);
160
161         return n;
162 }
163
164
165 /**
166  * wpabuf_zeropad - Pad buffer with 0x00 octets (prefix) to specified length
167  * @buf: Buffer to be padded
168  * @len: Length for the padded buffer
169  * Returns: wpabuf padded to len octets or %NULL on failure
170  *
171  * If buf is longer than len octets or of same size, it will be returned as-is.
172  * Otherwise a new buffer is allocated and prefixed with 0x00 octets followed
173  * by the source data. The source buffer will be freed on error, i.e., caller
174  * will only be responsible on freeing the returned buffer. If buf is %NULL,
175  * %NULL will be returned.
176  */
177 struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len)
178 {
179         struct wpabuf *ret;
180         size_t blen;
181
182         if (buf == NULL)
183                 return NULL;
184
185         blen = wpabuf_len(buf);
186         if (blen >= len)
187                 return buf;
188
189         ret = wpabuf_alloc(len);
190         if (ret) {
191                 os_memset(wpabuf_put(ret, len - blen), 0, len - blen);
192                 wpabuf_put_buf(ret, buf);
193         }
194         wpabuf_free(buf);
195
196         return ret;
197 }
198
199
200 void wpabuf_printf(struct wpabuf *buf, char *fmt, ...)
201 {
202         va_list ap;
203         void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf);
204         int res;
205
206         va_start(ap, fmt);
207         res = vsnprintf(tmp, buf->size - buf->used, fmt, ap);
208         va_end(ap);
209         if (res < 0 || (size_t) res >= buf->size - buf->used)
210                 wpabuf_overflow(buf, res);
211         buf->used += res;
212 }