1/*-
2 * Copyright (c) 2003, 2004 David Young.  All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 * 3. The name of David Young may not be used to endorse or promote
13 *    products derived from this software without specific prior
14 *    written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
19 * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DAVID
20 * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
22 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
27 * OF SUCH DAMAGE.
28 */
29
30#ifdef HAVE_CONFIG_H
31#include <config.h>
32#endif
33
34#include <stdlib.h>
35#include <string.h>
36#include "netdissect-stdinc.h"
37
38#include "netdissect.h"
39#include "extract.h"
40
41#include "cpack.h"
42
43const uint8_t *
44nd_cpack_next_boundary(const uint8_t *buf, const uint8_t *p, size_t alignment)
45{
46	size_t misalignment = (size_t)(p - buf) % alignment;
47
48	if (misalignment == 0)
49		return p;
50
51	return p + (alignment - misalignment);
52}
53
54/* Advance to the next wordsize boundary. Return NULL if fewer than
55 * wordsize bytes remain in the buffer after the boundary.  Otherwise,
56 * return a pointer to the boundary.
57 */
58const uint8_t *
59nd_cpack_align_and_reserve(struct cpack_state *cs, size_t wordsize)
60{
61	const uint8_t *next;
62
63	/* Ensure alignment. */
64	next = nd_cpack_next_boundary(cs->c_buf, cs->c_next, wordsize);
65
66	/* Too little space for wordsize bytes? */
67	if (next - cs->c_buf + wordsize > cs->c_len)
68		return NULL;
69
70	return next;
71}
72
73/* Advance by N bytes without returning them. */
74int
75nd_cpack_advance(struct cpack_state *cs, const size_t toskip)
76{
77	/* No space left? */
78	if (cs->c_next - cs->c_buf + toskip > cs->c_len)
79		return -1;
80	cs->c_next += toskip;
81	return 0;
82}
83
84int
85nd_cpack_init(struct cpack_state *cs, const uint8_t *buf, size_t buflen)
86{
87	memset(cs, 0, sizeof(*cs));
88
89	cs->c_buf = buf;
90	cs->c_len = buflen;
91	cs->c_next = cs->c_buf;
92
93	return 0;
94}
95
96/* Unpack a 64-bit unsigned integer. */
97int
98nd_cpack_uint64(netdissect_options *ndo, struct cpack_state *cs, uint64_t *u)
99{
100	const uint8_t *next;
101
102	if ((next = nd_cpack_align_and_reserve(cs, sizeof(*u))) == NULL)
103		return -1;
104
105	*u = GET_LE_U_8(next);
106
107	/* Move pointer past the uint64_t. */
108	cs->c_next = next + sizeof(*u);
109	return 0;
110}
111
112/* Unpack a 64-bit signed integer. */
113int
114nd_cpack_int64(netdissect_options *ndo, struct cpack_state *cs, int64_t *u)
115{
116	const uint8_t *next;
117
118	if ((next = nd_cpack_align_and_reserve(cs, sizeof(*u))) == NULL)
119		return -1;
120
121	*u = GET_LE_S_8(next);
122
123	/* Move pointer past the int64_t. */
124	cs->c_next = next + sizeof(*u);
125	return 0;
126}
127
128/* Unpack a 32-bit unsigned integer. */
129int
130nd_cpack_uint32(netdissect_options *ndo, struct cpack_state *cs, uint32_t *u)
131{
132	const uint8_t *next;
133
134	if ((next = nd_cpack_align_and_reserve(cs, sizeof(*u))) == NULL)
135		return -1;
136
137	*u = GET_LE_U_4(next);
138
139	/* Move pointer past the uint32_t. */
140	cs->c_next = next + sizeof(*u);
141	return 0;
142}
143
144/* Unpack a 32-bit signed integer. */
145int
146nd_cpack_int32(netdissect_options *ndo, struct cpack_state *cs, int32_t *u)
147{
148	const uint8_t *next;
149
150	if ((next = nd_cpack_align_and_reserve(cs, sizeof(*u))) == NULL)
151		return -1;
152
153	*u = GET_LE_S_4(next);
154
155	/* Move pointer past the int32_t. */
156	cs->c_next = next + sizeof(*u);
157	return 0;
158}
159
160/* Unpack a 16-bit unsigned integer. */
161int
162nd_cpack_uint16(netdissect_options *ndo, struct cpack_state *cs, uint16_t *u)
163{
164	const uint8_t *next;
165
166	if ((next = nd_cpack_align_and_reserve(cs, sizeof(*u))) == NULL)
167		return -1;
168
169	*u = GET_LE_U_2(next);
170
171	/* Move pointer past the uint16_t. */
172	cs->c_next = next + sizeof(*u);
173	return 0;
174}
175
176/* Unpack a 16-bit signed integer. */
177int
178nd_cpack_int16(netdissect_options *ndo, struct cpack_state *cs, int16_t *u)
179{
180	const uint8_t *next;
181
182	if ((next = nd_cpack_align_and_reserve(cs, sizeof(*u))) == NULL)
183		return -1;
184
185	*u = GET_LE_S_2(next);
186
187	/* Move pointer past the int16_t. */
188	cs->c_next = next + sizeof(*u);
189	return 0;
190}
191
192/* Unpack an 8-bit unsigned integer. */
193int
194nd_cpack_uint8(netdissect_options *ndo, struct cpack_state *cs, uint8_t *u)
195{
196	/* No space left? */
197	if ((size_t)(cs->c_next - cs->c_buf) >= cs->c_len)
198		return -1;
199
200	*u = GET_U_1(cs->c_next);
201
202	/* Move pointer past the uint8_t. */
203	cs->c_next++;
204	return 0;
205}
206
207/* Unpack an 8-bit signed integer. */
208int
209nd_cpack_int8(netdissect_options *ndo, struct cpack_state *cs, int8_t *u)
210{
211	/* No space left? */
212	if ((size_t)(cs->c_next - cs->c_buf) >= cs->c_len)
213		return -1;
214
215	*u = GET_S_1(cs->c_next);
216
217	/* Move pointer past the int8_t. */
218	cs->c_next++;
219	return 0;
220}
221