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