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 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