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 * $Id: mbuf.c,v 1.6 2001/02/24 15:56:04 bp Exp $ 33 */ 34 35#include <sys/cdefs.h> 36__FBSDID("$FreeBSD$"); 37 38#include <sys/types.h> 39#include <sys/endian.h> 40#include <arpa/inet.h> 41#include <ctype.h> 42#include <errno.h> 43#include <stdio.h> 44#include <stdlib.h> 45#include <string.h> 46 47#include <netsmb/smb_lib.h> 48 49#define MBERROR(format, args...) printf("%s(%d): "format, __FUNCTION__ , \ 50 __LINE__ ,## args) 51 52static int 53m_get(size_t len, struct mbuf **mpp) 54{ 55 struct mbuf *m; 56 57 len = M_ALIGN(len); 58 if (len < M_MINSIZE) 59 len = M_MINSIZE; 60 m = malloc(M_BASESIZE + len); 61 if (m == NULL) 62 return ENOMEM; 63 bzero(m, M_BASESIZE + len); 64 m->m_maxlen = len; 65 m->m_data = M_TOP(m); 66 *mpp = m; 67 return 0; 68} 69 70static void 71m_free(struct mbuf *m) 72{ 73 free(m); 74} 75 76static void 77m_freem(struct mbuf *m0) 78{ 79 struct mbuf *m; 80 81 while (m0) { 82 m = m0->m_next; 83 m_free(m0); 84 m0 = m; 85 } 86} 87 88static size_t 89m_totlen(struct mbuf *m0) 90{ 91 struct mbuf *m = m0; 92 int len = 0; 93 94 while (m) { 95 len += m->m_len; 96 m = m->m_next; 97 } 98 return len; 99} 100 101int 102m_lineup(struct mbuf *m0, struct mbuf **mpp) 103{ 104 struct mbuf *nm, *m; 105 char *dp; 106 size_t len; 107 int error; 108 109 if (m0->m_next == NULL) { 110 *mpp = m0; 111 return 0; 112 } 113 if ((error = m_get(m_totlen(m0), &nm)) != 0) 114 return error; 115 dp = mtod(nm, char *); 116 while (m0) { 117 len = m0->m_len; 118 bcopy(m0->m_data, dp, len); 119 dp += len; 120 m = m0->m_next; 121 m_free(m0); 122 m0 = m; 123 } 124 *mpp = nm; 125 return 0; 126} 127 128int 129mb_init(struct mbdata *mbp, size_t size) 130{ 131 struct mbuf *m; 132 int error; 133 134 if ((error = m_get(size, &m)) != 0) 135 return error; 136 return mb_initm(mbp, m); 137} 138 139int 140mb_initm(struct mbdata *mbp, struct mbuf *m) 141{ 142 bzero(mbp, sizeof(*mbp)); 143 mbp->mb_top = mbp->mb_cur = m; 144 mbp->mb_pos = mtod(m, char *); 145 return 0; 146} 147 148int 149mb_done(struct mbdata *mbp) 150{ 151 if (mbp->mb_top) { 152 m_freem(mbp->mb_top); 153 mbp->mb_top = NULL; 154 } 155 return 0; 156} 157 158/* 159int 160mb_fixhdr(struct mbdata *mbp) 161{ 162 struct mbuf *m = mbp->mb_top; 163 int len = 0; 164 165 while (m) { 166 len += m->m_len; 167 m = m->m_next; 168 } 169 mbp->mb_top->m_pkthdr.len = len; 170 return len; 171} 172*/ 173int 174m_getm(struct mbuf *top, size_t len, struct mbuf **mpp) 175{ 176 struct mbuf *m, *mp; 177 int error; 178 179 for (mp = top; ; mp = mp->m_next) { 180 len -= M_TRAILINGSPACE(mp); 181 if (mp->m_next == NULL) 182 break; 183 184 } 185 if (len > 0) { 186 if ((error = m_get(len, &m)) != 0) 187 return error; 188 mp->m_next = m; 189 } 190 *mpp = top; 191 return 0; 192} 193 194/* 195 * Routines to put data in a buffer 196 */ 197#define MB_PUT(t) int error; t *p; \ 198 if ((error = mb_fit(mbp, sizeof(t), (char**)&p)) != 0) \ 199 return error 200 201/* 202 * Check if object of size 'size' fit to the current position and 203 * allocate new mbuf if not. Advance pointers and increase length of mbuf(s). 204 * Return pointer to the object placeholder or NULL if any error occured. 205 */ 206int 207mb_fit(struct mbdata *mbp, size_t size, char **pp) 208{ 209 struct mbuf *m, *mn; 210 int error; 211 212 m = mbp->mb_cur; 213 if (M_TRAILINGSPACE(m) < (int)size) { 214 if ((error = m_get(size, &mn)) != 0) 215 return error; 216 mbp->mb_pos = mtod(mn, char *); 217 mbp->mb_cur = m->m_next = mn; 218 m = mn; 219 } 220 m->m_len += size; 221 *pp = mbp->mb_pos; 222 mbp->mb_pos += size; 223 mbp->mb_count += size; 224 return 0; 225} 226 227int 228mb_put_uint8(struct mbdata *mbp, u_int8_t x) 229{ 230 MB_PUT(u_int8_t); 231 *p = x; 232 return 0; 233} 234 235int 236mb_put_uint16be(struct mbdata *mbp, u_int16_t x) 237{ 238 MB_PUT(u_int16_t); 239 setwbe(p, 0, x); 240 return 0; 241} 242 243int 244mb_put_uint16le(struct mbdata *mbp, u_int16_t x) 245{ 246 MB_PUT(u_int16_t); 247 setwle(p, 0, x); 248 return 0; 249} 250 251int 252mb_put_uint32be(struct mbdata *mbp, u_int32_t x) 253{ 254 MB_PUT(u_int32_t); 255 setdbe(p, 0, x); 256 return 0; 257} 258 259int 260mb_put_uint32le(struct mbdata *mbp, u_int32_t x) 261{ 262 MB_PUT(u_int32_t); 263 setdle(p, 0, x); 264 return 0; 265} 266 267int 268mb_put_int64be(struct mbdata *mbp, int64_t x) 269{ 270 MB_PUT(int64_t); 271 *p = htobe64(x); 272 return 0; 273} 274 275int 276mb_put_int64le(struct mbdata *mbp, int64_t x) 277{ 278 MB_PUT(int64_t); 279 *p = htole64(x); 280 return 0; 281} 282 283int 284mb_put_mem(struct mbdata *mbp, const char *source, size_t size) 285{ 286 struct mbuf *m; 287 char * dst; 288 size_t cplen; 289 int error; 290 291 if (size == 0) 292 return 0; 293 m = mbp->mb_cur; 294 if ((error = m_getm(m, size, &m)) != 0) 295 return error; 296 while (size > 0) { 297 cplen = M_TRAILINGSPACE(m); 298 if (cplen == 0) { 299 m = m->m_next; 300 continue; 301 } 302 if (cplen > size) 303 cplen = size; 304 dst = mtod(m, char *) + m->m_len; 305 if (source) { 306 bcopy(source, dst, cplen); 307 source += cplen; 308 } else 309 bzero(dst, cplen); 310 size -= cplen; 311 m->m_len += cplen; 312 mbp->mb_count += cplen; 313 } 314 mbp->mb_pos = mtod(m, char *) + m->m_len; 315 mbp->mb_cur = m; 316 return 0; 317} 318 319int 320mb_put_mbuf(struct mbdata *mbp, struct mbuf *m) 321{ 322 mbp->mb_cur->m_next = m; 323 while (m) { 324 mbp->mb_count += m->m_len; 325 if (m->m_next == NULL) 326 break; 327 m = m->m_next; 328 } 329 mbp->mb_pos = mtod(m, char *) + m->m_len; 330 mbp->mb_cur = m; 331 return 0; 332} 333 334int 335mb_put_pstring(struct mbdata *mbp, const char *s) 336{ 337 int error, len = strlen(s); 338 339 if (len > 255) { 340 len = 255; 341 } 342 if ((error = mb_put_uint8(mbp, len)) != 0) 343 return error; 344 return mb_put_mem(mbp, s, len); 345} 346 347/* 348 * Routines for fetching data from an mbuf chain 349 */ 350#define mb_left(m,p) (mtod(m, char *) + (m)->m_len - (p)) 351 352int 353mb_get_uint8(struct mbdata *mbp, u_int8_t *x) 354{ 355 return mb_get_mem(mbp, x, 1); 356} 357 358int 359mb_get_uint16(struct mbdata *mbp, u_int16_t *x) 360{ 361 return mb_get_mem(mbp, (char *)x, 2); 362} 363 364int 365mb_get_uint16le(struct mbdata *mbp, u_int16_t *x) 366{ 367 u_int16_t v; 368 int error = mb_get_uint16(mbp, &v); 369 370 *x = le16toh(v); 371 return error; 372} 373 374int 375mb_get_uint16be(struct mbdata *mbp, u_int16_t *x) { 376 u_int16_t v; 377 int error = mb_get_uint16(mbp, &v); 378 379 *x = be16toh(v); 380 return error; 381} 382 383int 384mb_get_uint32(struct mbdata *mbp, u_int32_t *x) 385{ 386 return mb_get_mem(mbp, (char *)x, 4); 387} 388 389int 390mb_get_uint32be(struct mbdata *mbp, u_int32_t *x) 391{ 392 u_int32_t v; 393 int error; 394 395 error = mb_get_uint32(mbp, &v); 396 *x = be32toh(v); 397 return error; 398} 399 400int 401mb_get_uint32le(struct mbdata *mbp, u_int32_t *x) 402{ 403 u_int32_t v; 404 int error; 405 406 error = mb_get_uint32(mbp, &v); 407 *x = le32toh(v); 408 return error; 409} 410 411int 412mb_get_int64(struct mbdata *mbp, int64_t *x) 413{ 414 return mb_get_mem(mbp, (char *)x, 8); 415} 416 417int 418mb_get_int64be(struct mbdata *mbp, int64_t *x) 419{ 420 int64_t v; 421 int error; 422 423 error = mb_get_int64(mbp, &v); 424 *x = be64toh(v); 425 return error; 426} 427 428int 429mb_get_int64le(struct mbdata *mbp, int64_t *x) 430{ 431 int64_t v; 432 int error; 433 434 error = mb_get_int64(mbp, &v); 435 *x = le64toh(v); 436 return error; 437} 438 439int 440mb_get_mem(struct mbdata *mbp, char * target, size_t size) 441{ 442 struct mbuf *m = mbp->mb_cur; 443 u_int count; 444 445 while (size > 0) { 446 if (m == NULL) { 447 MBERROR("incomplete copy\n"); 448 return EBADRPC; 449 } 450 count = mb_left(m, mbp->mb_pos); 451 if (count == 0) { 452 mbp->mb_cur = m = m->m_next; 453 if (m) 454 mbp->mb_pos = mtod(m, char *); 455 continue; 456 } 457 if (count > size) 458 count = size; 459 size -= count; 460 if (target) { 461 if (count == 1) { 462 *target++ = *mbp->mb_pos; 463 } else { 464 bcopy(mbp->mb_pos, target, count); 465 target += count; 466 } 467 } 468 mbp->mb_pos += count; 469 } 470 return 0; 471} 472