xref: /freebsd/contrib/wpa/src/utils/wpabuf.c (revision 39beb93c)
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 }
213