1146773Ssam/*-
2146773Ssam * Copyright (c) 2003, 2004 David Young.  All rights reserved.
3146773Ssam *
4146773Ssam * Redistribution and use in source and binary forms, with or without
5146773Ssam * modification, are permitted provided that the following conditions
6146773Ssam * are met:
7146773Ssam * 1. Redistributions of source code must retain the above copyright
8146773Ssam *    notice, this list of conditions and the following disclaimer.
9146773Ssam * 2. Redistributions in binary form must reproduce the above copyright
10146773Ssam *    notice, this list of conditions and the following disclaimer in the
11146773Ssam *    documentation and/or other materials provided with the distribution.
12146773Ssam * 3. The name of David Young may not be used to endorse or promote
13146773Ssam *    products derived from this software without specific prior
14146773Ssam *    written permission.
15146773Ssam *
16146773Ssam * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY
17146773Ssam * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18146773Ssam * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
19146773Ssam * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DAVID
20146773Ssam * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21146773Ssam * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
22146773Ssam * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23146773Ssam * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24146773Ssam * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25146773Ssam * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26146773Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
27146773Ssam * OF SUCH DAMAGE.
28146773Ssam */
29146773Ssam
30146773Ssam#ifdef HAVE_CONFIG_H
31146773Ssam#include "config.h"
32146773Ssam#endif
33146773Ssam
34146773Ssam#include <stdlib.h>
35146773Ssam#include <string.h>
36146773Ssam#include <tcpdump-stdinc.h>
37146773Ssam
38146773Ssam#include "cpack.h"
39146773Ssam#include "extract.h"
40146773Ssam
41235530Sdelphiju_int8_t *
42146773Ssamcpack_next_boundary(u_int8_t *buf, u_int8_t *p, size_t alignment)
43146773Ssam{
44146773Ssam	size_t misalignment = (size_t)(p - buf) % alignment;
45146773Ssam
46146773Ssam	if (misalignment == 0)
47146773Ssam		return p;
48146773Ssam
49146773Ssam	return p + (alignment - misalignment);
50146773Ssam}
51146773Ssam
52146773Ssam/* Advance to the next wordsize boundary. Return NULL if fewer than
53146773Ssam * wordsize bytes remain in the buffer after the boundary.  Otherwise,
54146773Ssam * return a pointer to the boundary.
55146773Ssam */
56235530Sdelphiju_int8_t *
57146773Ssamcpack_align_and_reserve(struct cpack_state *cs, size_t wordsize)
58146773Ssam{
59146773Ssam	u_int8_t *next;
60146773Ssam
61146773Ssam	/* Ensure alignment. */
62146773Ssam	next = cpack_next_boundary(cs->c_buf, cs->c_next, wordsize);
63146773Ssam
64146773Ssam	/* Too little space for wordsize bytes? */
65146773Ssam	if (next - cs->c_buf + wordsize > cs->c_len)
66146773Ssam		return NULL;
67146773Ssam
68146773Ssam	return next;
69146773Ssam}
70146773Ssam
71146773Ssamint
72146773Ssamcpack_init(struct cpack_state *cs, u_int8_t *buf, size_t buflen)
73146773Ssam{
74146773Ssam	memset(cs, 0, sizeof(*cs));
75146773Ssam
76146773Ssam	cs->c_buf = buf;
77146773Ssam	cs->c_len = buflen;
78146773Ssam	cs->c_next = cs->c_buf;
79146773Ssam
80146773Ssam	return 0;
81146773Ssam}
82146773Ssam
83146773Ssam/* Unpack a 64-bit unsigned integer. */
84146773Ssamint
85146773Ssamcpack_uint64(struct cpack_state *cs, u_int64_t *u)
86146773Ssam{
87146773Ssam	u_int8_t *next;
88146773Ssam
89146773Ssam	if ((next = cpack_align_and_reserve(cs, sizeof(*u))) == NULL)
90146773Ssam		return -1;
91146773Ssam
92146773Ssam	*u = EXTRACT_LE_64BITS(next);
93146773Ssam
94146773Ssam	/* Move pointer past the u_int64_t. */
95146773Ssam	cs->c_next = next + sizeof(*u);
96146773Ssam	return 0;
97146773Ssam}
98146773Ssam
99146773Ssam/* Unpack a 32-bit unsigned integer. */
100146773Ssamint
101146773Ssamcpack_uint32(struct cpack_state *cs, u_int32_t *u)
102146773Ssam{
103146773Ssam	u_int8_t *next;
104146773Ssam
105146773Ssam	if ((next = cpack_align_and_reserve(cs, sizeof(*u))) == NULL)
106146773Ssam		return -1;
107146773Ssam
108146773Ssam	*u = EXTRACT_LE_32BITS(next);
109146773Ssam
110146773Ssam	/* Move pointer past the u_int32_t. */
111146773Ssam	cs->c_next = next + sizeof(*u);
112146773Ssam	return 0;
113146773Ssam}
114146773Ssam
115146773Ssam/* Unpack a 16-bit unsigned integer. */
116146773Ssamint
117146773Ssamcpack_uint16(struct cpack_state *cs, u_int16_t *u)
118146773Ssam{
119146773Ssam	u_int8_t *next;
120146773Ssam
121146773Ssam	if ((next = cpack_align_and_reserve(cs, sizeof(*u))) == NULL)
122146773Ssam		return -1;
123146773Ssam
124146773Ssam	*u = EXTRACT_LE_16BITS(next);
125146773Ssam
126146773Ssam	/* Move pointer past the u_int16_t. */
127146773Ssam	cs->c_next = next + sizeof(*u);
128146773Ssam	return 0;
129146773Ssam}
130146773Ssam
131146773Ssam/* Unpack an 8-bit unsigned integer. */
132146773Ssamint
133146773Ssamcpack_uint8(struct cpack_state *cs, u_int8_t *u)
134146773Ssam{
135146773Ssam	/* No space left? */
136146773Ssam	if ((size_t)(cs->c_next - cs->c_buf) >= cs->c_len)
137146773Ssam		return -1;
138146773Ssam
139146773Ssam	*u = *cs->c_next;
140146773Ssam
141146773Ssam	/* Move pointer past the u_int8_t. */
142146773Ssam	cs->c_next++;
143146773Ssam	return 0;
144146773Ssam}
145