Home | History | Annotate | Line # | Download | only in dist
      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.8 2024/09/02 16:15:30 christos Exp $");
     30 #endif
     31 
     32 #include <config.h>
     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 
     43 const uint8_t *
     44 nd_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  */
     58 const uint8_t *
     59 nd_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. */
     74 int
     75 nd_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 
     84 int
     85 nd_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. */
     97 int
     98 nd_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. */
    113 int
    114 nd_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. */
    129 int
    130 nd_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. */
    145 int
    146 nd_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. */
    161 int
    162 nd_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. */
    177 int
    178 nd_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. */
    193 int
    194 nd_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. */
    208 int
    209 nd_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