1/* 2 * Copyright (c) 2000, Boris Popov 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Boris Popov. 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * from: Id: mbuf.c,v 1.6 2001/02/24 15:56:04 bp Exp 33 */ 34 35#include <sys/cdefs.h> 36__RCSID("$NetBSD: mbuf.c,v 1.8 2008/06/27 02:09:49 gmcgarry Exp $"); 37 38#include <sys/types.h> 39#include <sys/endian.h> 40#include <ctype.h> 41#include <errno.h> 42#include <stdio.h> 43#include <stdlib.h> 44#include <string.h> 45 46#include <netsmb/smb_lib.h> 47 48#define MBERROR(x) printf x 49 50static int 51m_get(size_t len, struct mbuf **mpp) 52{ 53 struct mbuf *m; 54 55 len = M_ALIGN(len); 56 if (len < M_MINSIZE) 57 len = M_MINSIZE; 58 m = malloc(M_BASESIZE + len); 59 if (m == NULL) 60 return ENOMEM; 61 bzero(m, M_BASESIZE + len); 62 m->m_maxlen = len; 63 m->m_data = M_TOP(m); 64 *mpp = m; 65 return 0; 66} 67 68static void 69m_free(struct mbuf *m) 70{ 71 free(m); 72} 73 74static void 75m_freem(struct mbuf *m0) 76{ 77 struct mbuf *m; 78 79 while (m0) { 80 m = m0->m_next; 81 m_free(m0); 82 m0 = m; 83 } 84} 85 86static size_t 87m_totlen(struct mbuf *m0) 88{ 89 struct mbuf *m = m0; 90 int len = 0; 91 92 while (m) { 93 len += m->m_len; 94 m = m->m_next; 95 } 96 return len; 97} 98 99int 100m_lineup(struct mbuf *m0, struct mbuf **mpp) 101{ 102 struct mbuf *nm, *m; 103 char *dp; 104 size_t len; 105 int error; 106 107 if (m0->m_next == NULL) { 108 *mpp = m0; 109 return 0; 110 } 111 if ((error = m_get(m_totlen(m0), &nm)) != 0) 112 return error; 113 dp = mtod(nm, char *); 114 while (m0) { 115 len = m0->m_len; 116 bcopy(m0->m_data, dp, len); 117 dp += len; 118 m = m0->m_next; 119 m_free(m0); 120 m0 = m; 121 } 122 *mpp = nm; 123 return 0; 124} 125 126int 127mb_init(struct mbdata *mbp, size_t size) 128{ 129 struct mbuf *m; 130 int error; 131 132 if ((error = m_get(size, &m)) != 0) 133 return error; 134 return mb_initm(mbp, m); 135} 136 137int 138mb_initm(struct mbdata *mbp, struct mbuf *m) 139{ 140 bzero(mbp, sizeof(*mbp)); 141 mbp->mb_top = mbp->mb_cur = m; 142 mbp->mb_pos = mtod(m, char *); 143 return 0; 144} 145 146int 147mb_done(struct mbdata *mbp) 148{ 149 if (mbp->mb_top) { 150 m_freem(mbp->mb_top); 151 mbp->mb_top = NULL; 152 } 153 return 0; 154} 155 156/* 157int 158mb_fixhdr(struct mbdata *mbp) 159{ 160 struct mbuf *m = mbp->mb_top; 161 int len = 0; 162 163 while (m) { 164 len += m->m_len; 165 m = m->m_next; 166 } 167 mbp->mb_top->m_pkthdr.len = len; 168 return len; 169} 170*/ 171int 172m_getm(struct mbuf *top, size_t len, struct mbuf **mpp) 173{ 174 struct mbuf *m, *mp; 175 int error; 176 177 for (mp = top; ; mp = mp->m_next) { 178 len -= M_TRAILINGSPACE(mp); 179 if (mp->m_next == NULL) 180 break; 181 182 } 183 if (len > 0) { 184 if ((error = m_get(len, &m)) != 0) 185 return error; 186 mp->m_next = m; 187 } 188 *mpp = top; 189 return 0; 190} 191 192/* 193 * Routines to put data in a buffer 194 */ 195#define MB_PUT(t) int error; t *p; \ 196 if ((error = mb_fit(mbp, sizeof(t), \ 197 (void **)(void *)&p)) != 0) \ 198 return error 199 200/* 201 * Check if object of size 'size' fit to the current position and 202 * allocate new mbuf if not. Advance pointers and increase length of mbuf(s). 203 * Return pointer to the object placeholder or NULL if any error occured. 204 */ 205int 206mb_fit(struct mbdata *mbp, size_t size, void **pp) 207{ 208 struct mbuf *m, *mn; 209 int error; 210 211 m = mbp->mb_cur; 212 if (M_TRAILINGSPACE(m) < (int)size) { 213 if ((error = m_get(size, &mn)) != 0) 214 return error; 215 mbp->mb_pos = mtod(mn, char *); 216 mbp->mb_cur = m->m_next = mn; 217 m = mn; 218 } 219 m->m_len += size; 220 *pp = mbp->mb_pos; 221 mbp->mb_pos += size; 222 mbp->mb_count += size; 223 return 0; 224} 225 226int 227mb_put_uint8(struct mbdata *mbp, u_int8_t x) 228{ 229 MB_PUT(u_int8_t); 230 *p = x; 231 return 0; 232} 233 234int 235mb_put_uint16be(struct mbdata *mbp, u_int16_t x) 236{ 237 MB_PUT(u_int16_t); 238 setwbe(p, 0, x); 239 return 0; 240} 241 242int 243mb_put_uint16le(struct mbdata *mbp, u_int16_t x) 244{ 245 MB_PUT(u_int16_t); 246 setwle(p, 0, x); 247 return 0; 248} 249 250int 251mb_put_uint32be(struct mbdata *mbp, u_int32_t x) 252{ 253 MB_PUT(u_int32_t); 254 setdbe(p, 0, x); 255 return 0; 256} 257 258int 259mb_put_uint32le(struct mbdata *mbp, u_int32_t x) 260{ 261 MB_PUT(u_int32_t); 262 setdle(p, 0, x); 263 return 0; 264} 265 266int 267mb_put_int64be(struct mbdata *mbp, int64_t x) 268{ 269 MB_PUT(int64_t); 270 *p = htobe64(x); 271 return 0; 272} 273 274int 275mb_put_int64le(struct mbdata *mbp, int64_t x) 276{ 277 MB_PUT(int64_t); 278 *p = htole64(x); 279 return 0; 280} 281 282int 283mb_put_mem(struct mbdata *mbp, const char *source, size_t size) 284{ 285 struct mbuf *m; 286 char * dst; 287 size_t cplen; 288 int error; 289 290 if (size == 0) 291 return 0; 292 m = mbp->mb_cur; 293 if ((error = m_getm(m, size, &m)) != 0) 294 return error; 295 while (size > 0) { 296 cplen = M_TRAILINGSPACE(m); 297 if (cplen == 0) { 298 m = m->m_next; 299 continue; 300 } 301 if (cplen > size) 302 cplen = size; 303 dst = mtod(m, char *) + m->m_len; 304 if (source) { 305 bcopy(source, dst, cplen); 306 source += cplen; 307 } else 308 bzero(dst, cplen); 309 size -= cplen; 310 m->m_len += cplen; 311 mbp->mb_count += cplen; 312 } 313 mbp->mb_pos = mtod(m, char *) + m->m_len; 314 mbp->mb_cur = m; 315 return 0; 316} 317 318int 319mb_put_mbuf(struct mbdata *mbp, struct mbuf *m) 320{ 321 mbp->mb_cur->m_next = m; 322 while (m) { 323 mbp->mb_count += m->m_len; 324 if (m->m_next == NULL) 325 break; 326 m = m->m_next; 327 } 328 mbp->mb_pos = mtod(m, char *) + m->m_len; 329 mbp->mb_cur = m; 330 return 0; 331} 332 333int 334mb_put_pstring(struct mbdata *mbp, const char *s) 335{ 336 int error, len = strlen(s); 337 338 if (len > 255) { 339 len = 255; 340 } 341 if ((error = mb_put_uint8(mbp, len)) != 0) 342 return error; 343 return mb_put_mem(mbp, s, len); 344} 345 346/* 347 * Routines for fetching data from an mbuf chain 348 */ 349#define mb_left(m,p) (mtod(m, char *) + (m)->m_len - (p)) 350 351int 352mb_get_uint8(struct mbdata *mbp, u_int8_t *x) 353{ 354 return mb_get_mem(mbp, x, 1); 355} 356 357int 358mb_get_uint16(struct mbdata *mbp, u_int16_t *x) 359{ 360 return mb_get_mem(mbp, (char *)x, 2); 361} 362 363int 364mb_get_uint16le(struct mbdata *mbp, u_int16_t *x) 365{ 366 u_int16_t v; 367 int error = mb_get_uint16(mbp, &v); 368 369 *x = le16toh(v); 370 return error; 371} 372 373int 374mb_get_uint16be(struct mbdata *mbp, u_int16_t *x) { 375 u_int16_t v; 376 int error = mb_get_uint16(mbp, &v); 377 378 *x = be16toh(v); 379 return error; 380} 381 382int 383mb_get_uint32(struct mbdata *mbp, u_int32_t *x) 384{ 385 return mb_get_mem(mbp, (char *)x, 4); 386} 387 388int 389mb_get_uint32be(struct mbdata *mbp, u_int32_t *x) 390{ 391 u_int32_t v; 392 int error; 393 394 error = mb_get_uint32(mbp, &v); 395 *x = be32toh(v); 396 return error; 397} 398 399int 400mb_get_uint32le(struct mbdata *mbp, u_int32_t *x) 401{ 402 u_int32_t v; 403 int error; 404 405 error = mb_get_uint32(mbp, &v); 406 *x = le32toh(v); 407 return error; 408} 409 410int 411mb_get_int64(struct mbdata *mbp, int64_t *x) 412{ 413 return mb_get_mem(mbp, (char *)x, 8); 414} 415 416int 417mb_get_int64be(struct mbdata *mbp, int64_t *x) 418{ 419 int64_t v; 420 int error; 421 422 error = mb_get_int64(mbp, &v); 423 *x = be64toh(v); 424 return error; 425} 426 427int 428mb_get_int64le(struct mbdata *mbp, int64_t *x) 429{ 430 int64_t v; 431 int error; 432 433 error = mb_get_int64(mbp, &v); 434 *x = le64toh(v); 435 return error; 436} 437 438int 439mb_get_mem(struct mbdata *mbp, char * target, size_t size) 440{ 441 struct mbuf *m = mbp->mb_cur; 442 u_int count; 443 444 while (size > 0) { 445 if (m == NULL) { 446 MBERROR(("incomplete copy\n")); 447 return EBADRPC; 448 } 449 count = mb_left(m, mbp->mb_pos); 450 if (count == 0) { 451 mbp->mb_cur = m = m->m_next; 452 if (m) 453 mbp->mb_pos = mtod(m, char *); 454 continue; 455 } 456 if (count > size) 457 count = size; 458 size -= count; 459 if (target) { 460 if (count == 1) { 461 *target++ = *mbp->mb_pos; 462 } else { 463 bcopy(mbp->mb_pos, target, count); 464 target += count; 465 } 466 } 467 mbp->mb_pos += count; 468 } 469 return 0; 470} 471