1/*
2 * Utilites for XDR encode and decode of data
3 *
4 * Copyright (C) 2015, Broadcom Corporation
5 * All Rights Reserved.
6 *
7 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;
8 * the contents of this file may not be disclosed to third parties, copied
9 * or duplicated in any form, in whole or in part, without the prior
10 * written permission of Broadcom Corporation.
11 *
12 * $Id: bcm_xdr.c 419467 2013-08-21 09:19:48Z $
13 */
14
15#include <osl.h>
16#include <typedefs.h>
17#include <bcmendian.h>
18#include <bcm_xdr.h>
19
20void
21bcm_xdr_buf_init(bcm_xdr_buf_t *b, void *buf, size_t len)
22{
23	b->buf = b->origbuf = buf;
24	b->size = b->origsize = (uint)len;
25}
26
27int
28bcm_xdr_pack_uint8_vec(bcm_xdr_buf_t *b, uint8 *vec, uint32 elems)
29{
30	int err = 0;
31	err = bcm_xdr_pack_opaque(b, elems, vec);
32
33	return err;
34}
35
36int
37bcm_xdr_unpack_uint8_vec(bcm_xdr_buf_t *b, uint8 *vec, uint32 elems)
38{
39	int err = 0;
40	err = bcm_xdr_unpack_opaque_cpy(b, elems, vec);
41
42	return err;
43}
44
45/* Pack 16-bit vectors */
46int
47bcm_xdr_pack_uint16_vec(bcm_xdr_buf_t *b, uint len, void *vec)
48{
49	size_t tot_len, r;
50	int i;
51	uint16	*vec16 = (uint16*)vec, *buf16 = (uint16*)b->buf;
52	ASSERT((len % sizeof(uint16)) == 0);
53
54	/* calc residual padding to 4 bytes */
55	r = (4 - len) & 3;
56
57	tot_len = len + r;
58
59	if (b->size < tot_len)
60		return -1;
61
62	/* Do the 16 bit swap and copy */
63	for (i = 0; i < (int)(len/sizeof(uint16)); i++)
64		buf16[i] = htol16(vec16[i]);
65
66	/* Padding */
67	memset(b->buf + len, 0, r);
68
69	b->size -= tot_len;
70	b->buf += tot_len;
71
72	return 0;
73}
74
75/* Unpack 16-bit vectors */
76int
77bcm_xdr_unpack_uint16_vec(bcm_xdr_buf_t *b, uint len, void *vec)
78{
79	int err = 0, i;
80	uint16	*vec16 = (uint16*)vec;
81	ASSERT((len % sizeof(uint16)) == 0);
82
83	err = bcm_xdr_unpack_opaque_cpy(b, len, vec);
84
85	/* Do the 16 bit swapping in the copied buffer */
86	for (i = 0; i < (int)(len/sizeof(uint16)); i++)
87		vec16[i] = ltoh16(vec16[i]);
88
89	return err;
90}
91
92/* Pack 32-bit vectors */
93int
94bcm_xdr_pack_uint32_vec(bcm_xdr_buf_t *b, uint len, void *vec)
95{
96	int i;
97	uint32	*vec32 = (uint32*)vec, *buf32 = (uint32*)b->buf;
98	ASSERT((len % sizeof(uint32)) == 0);
99
100	if (b->size < len)
101		return -1;
102
103	/* Do the 32 bit swap and copy */
104	for (i = 0; i < (int)(len/sizeof(uint32)); i++)
105		buf32[i] = htol32(vec32[i]);
106
107	b->size -= len;
108	b->buf += len;
109
110	return 0;
111}
112
113/* Unpack 32-bit vectors */
114int
115bcm_xdr_unpack_uint32_vec(bcm_xdr_buf_t *b, uint len, void *vec)
116{
117	int err = 0, i;
118	uint32	*vec32 = (uint32*)vec;
119	ASSERT((len % sizeof(uint32)) == 0);
120
121	err = bcm_xdr_unpack_opaque_cpy(b, len, vec);
122
123	/* Do the 32 bit swapping in the copied buffer */
124	for (i = 0; i < (int)(len/sizeof(uint32)); i++)
125		vec32[i] = ltoh32(vec32[i]);
126
127	return err;
128}
129
130int
131bcm_xdr_pack_uint32(bcm_xdr_buf_t *b, uint32 val)
132{
133	if (b->size < 4)
134		return -1;
135
136	*(uint32*)(b->buf) = htol32((uint32)val);
137	b->size -= 4;
138	b->buf += 4;
139
140	return 0;
141}
142
143int
144bcm_xdr_unpack_uint32(bcm_xdr_buf_t *b, uint32 *pval)
145{
146	if (b->size < 4)
147		return -1;
148
149	*pval = ltoh32(*(uint32*)(b->buf));
150
151	b->size -= 4;
152	b->buf += 4;
153
154	return 0;
155}
156
157int
158bcm_xdr_pack_int32(bcm_xdr_buf_t *b, int32 val)
159{
160	return bcm_xdr_pack_uint32(b, (uint32)val);
161}
162
163int
164bcm_xdr_unpack_int32(bcm_xdr_buf_t *b, int32 *pval)
165{
166	return bcm_xdr_unpack_uint32(b, (uint32*)pval);
167}
168
169int
170bcm_xdr_pack_int8(bcm_xdr_buf_t *b, int8 val)
171{
172	return bcm_xdr_pack_uint32(b, (uint32)val);
173}
174
175int
176bcm_xdr_unpack_int8(bcm_xdr_buf_t *b, int8 *pval)
177{
178	uint32 val = 0;
179	int err;
180
181	err = bcm_xdr_unpack_uint32(b, &val);
182	*pval = (int8)val;
183
184	return err;
185}
186
187int
188bcm_xdr_pack_opaque_raw(bcm_xdr_buf_t *b, uint len, void *data)
189{
190	if (b->size < len)
191		return -1;
192	memcpy(b->buf, data, len);
193
194	b->size -= len;
195	b->buf += len;
196
197	return 0;
198}
199
200/* Pad 0 at the remaining part of a rpc buffer */
201int
202bcm_xdr_pack_opaque_pad(bcm_xdr_buf_t *b)
203{
204	size_t len;
205	size_t r;
206
207	/* calc residual padding to 4 bytes */
208	len = (size_t)(b->buf - b->origbuf);
209	r = (4 - len) & 0x3;
210
211	if (r == 0)
212		return 0;
213
214	if (b->size < r)
215		return -1;
216
217	memset(b->buf, 0, r);
218
219	b->size -= r;
220	b->buf += r;
221
222	return 0;
223}
224
225/* pack a word-aligned buffer without dealing with the endianess, pad 0 at the end and make
226 * it word-aligned if len is not multiple of 4
227 */
228int
229bcm_xdr_pack_opaque(bcm_xdr_buf_t *b, uint len, const void *data)
230{
231	size_t tot_len;
232	size_t r;
233
234	/* calc residual padding to 4 bytes */
235	r = (4 - len) & 3;
236
237	tot_len = len + r;
238
239	if (b->size < tot_len)
240		return -1;
241
242	memcpy(b->buf, data, len);
243	memset(b->buf + len, 0, r);
244
245	b->size -= tot_len;
246	b->buf += tot_len;
247
248	return 0;
249}
250
251int
252bcm_xdr_unpack_opaque(bcm_xdr_buf_t *b, uint len, void **pdata)
253{
254	size_t tot_len;
255	size_t r;
256
257	/* calc residual padding to 4 bytes */
258	r = (4 - len) & 3;
259	tot_len = len + r;
260
261	if (b->size < tot_len)
262		return -1;
263
264	*pdata = b->buf;
265
266	b->size -= tot_len;
267	b->buf += tot_len;
268
269	return 0;
270}
271
272int
273bcm_xdr_unpack_opaque_cpy(bcm_xdr_buf_t *b, uint len, void *data)
274{
275	void *xdr_data;
276	int err;
277
278	err = bcm_xdr_unpack_opaque(b, len, &xdr_data);
279	if (err)
280		return err;
281
282	memcpy(data, xdr_data, len);
283
284	return 0;
285}
286
287int
288bcm_xdr_pack_opaque_varlen(bcm_xdr_buf_t *b, uint len, const void *data)
289{
290	int err;
291
292	err = bcm_xdr_pack_uint32(b, len);
293	if (err)
294		return err;
295
296	return bcm_xdr_pack_opaque(b, len, data);
297}
298
299int
300bcm_xdr_unpack_opaque_varlen(bcm_xdr_buf_t *b, uint *plen, void **pdata)
301{
302	int err;
303
304	err = bcm_xdr_unpack_uint32(b, plen);
305	if (err)
306		return err;
307
308	return bcm_xdr_unpack_opaque(b, *plen, pdata);
309}
310
311int
312bcm_xdr_pack_string(bcm_xdr_buf_t *b, char *str)
313{
314	return bcm_xdr_pack_opaque_varlen(b, strlen(str), str);
315}
316
317int
318bcm_xdr_unpack_string(bcm_xdr_buf_t *b, uint *plen, char **pstr)
319{
320	return bcm_xdr_unpack_opaque_varlen(b, plen, (void**)pstr);
321}
322
323
324int
325bcm_xdr_opaque_resrv(bcm_xdr_buf_t *b, uint len, void **pdata)
326{
327	return bcm_xdr_unpack_opaque(b, len, pdata);
328}
329
330int
331bcm_xdr_opaque_resrv_varlen(bcm_xdr_buf_t *b, uint len, void **pdata)
332{
333	int err;
334	err =  bcm_xdr_pack_uint32(b, len);
335
336	if (err)
337		return err;
338
339	return bcm_xdr_opaque_resrv(b, len, pdata);
340}
341