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.6 2017/01/24 23:29:13 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 "cpack.h" 41 #include "extract.h" 42 43 const uint8_t * 44 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 cpack_align_and_reserve(struct cpack_state *cs, size_t wordsize) 60 { 61 const uint8_t *next; 62 63 /* Ensure alignment. */ 64 next = 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 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 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 cpack_uint64(struct cpack_state *cs, uint64_t *u) 99 { 100 const uint8_t *next; 101 102 if ((next = cpack_align_and_reserve(cs, sizeof(*u))) == NULL) 103 return -1; 104 105 *u = EXTRACT_LE_64BITS(next); 106 107 /* Move pointer past the uint64_t. */ 108 cs->c_next = next + sizeof(*u); 109 return 0; 110 } 111 112 /* Unpack a 32-bit unsigned integer. */ 113 int 114 cpack_uint32(struct cpack_state *cs, uint32_t *u) 115 { 116 const uint8_t *next; 117 118 if ((next = cpack_align_and_reserve(cs, sizeof(*u))) == NULL) 119 return -1; 120 121 *u = EXTRACT_LE_32BITS(next); 122 123 /* Move pointer past the uint32_t. */ 124 cs->c_next = next + sizeof(*u); 125 return 0; 126 } 127 128 /* Unpack a 16-bit unsigned integer. */ 129 int 130 cpack_uint16(struct cpack_state *cs, uint16_t *u) 131 { 132 const uint8_t *next; 133 134 if ((next = cpack_align_and_reserve(cs, sizeof(*u))) == NULL) 135 return -1; 136 137 *u = EXTRACT_LE_16BITS(next); 138 139 /* Move pointer past the uint16_t. */ 140 cs->c_next = next + sizeof(*u); 141 return 0; 142 } 143 144 /* Unpack an 8-bit unsigned integer. */ 145 int 146 cpack_uint8(struct cpack_state *cs, uint8_t *u) 147 { 148 /* No space left? */ 149 if ((size_t)(cs->c_next - cs->c_buf) >= cs->c_len) 150 return -1; 151 152 *u = *cs->c_next; 153 154 /* Move pointer past the uint8_t. */ 155 cs->c_next++; 156 return 0; 157 } 158