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 52 static int 53 m_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 70 static void 71 m_free(struct mbuf *m) 72 { 73 free(m); 74 } 75 76 static void 77 m_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 88 static size_t 89 m_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 101 int 102 m_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 128 int 129 mb_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 139 int 140 mb_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 148 int 149 mb_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 /* 159 int 160 mb_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 */ 173 int 174 m_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 */ 206 int 207 mb_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 227 int 228 mb_put_uint8(struct mbdata *mbp, u_int8_t x) 229 { 230 MB_PUT(u_int8_t); 231 *p = x; 232 return 0; 233 } 234 235 int 236 mb_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 243 int 244 mb_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 251 int 252 mb_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 259 int 260 mb_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 267 int 268 mb_put_int64be(struct mbdata *mbp, int64_t x) 269 { 270 MB_PUT(int64_t); 271 *p = htobe64(x); 272 return 0; 273 } 274 275 int 276 mb_put_int64le(struct mbdata *mbp, int64_t x) 277 { 278 MB_PUT(int64_t); 279 *p = htole64(x); 280 return 0; 281 } 282 283 int 284 mb_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 319 int 320 mb_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 334 int 335 mb_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 352 int 353 mb_get_uint8(struct mbdata *mbp, u_int8_t *x) 354 { 355 return mb_get_mem(mbp, x, 1); 356 } 357 358 int 359 mb_get_uint16(struct mbdata *mbp, u_int16_t *x) 360 { 361 return mb_get_mem(mbp, (char *)x, 2); 362 } 363 364 int 365 mb_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 374 int 375 mb_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 383 int 384 mb_get_uint32(struct mbdata *mbp, u_int32_t *x) 385 { 386 return mb_get_mem(mbp, (char *)x, 4); 387 } 388 389 int 390 mb_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 400 int 401 mb_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 411 int 412 mb_get_int64(struct mbdata *mbp, int64_t *x) 413 { 414 return mb_get_mem(mbp, (char *)x, 8); 415 } 416 417 int 418 mb_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 428 int 429 mb_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 439 int 440 mb_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