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