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.3 2004/12/13 00:25:22 lindak Exp $ 33 */ 34 35 #pragma ident "%Z%%M% %I% %E% SMI" 36 37 #include <sys/types.h> 38 #include <ctype.h> 39 #include <errno.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <strings.h> 44 #include <libintl.h> 45 #include <assert.h> 46 47 #include <netsmb/smb.h> 48 #include <netsmb/smb_lib.h> 49 #include <netsmb/mchain.h> 50 51 #ifdef APPLE 52 #define __func__ "" 53 #define MBERROR(format, args...) \ 54 printf("%s(%d): "format, __func__, __LINE__, ## args) 55 #endif 56 57 static int 58 m_get(size_t len, struct mbuf **mpp) 59 { 60 struct mbuf *m; 61 62 assert(len < 0x100000); /* sanity */ 63 64 len = M_ALIGN(len); 65 if (len < M_MINSIZE) 66 len = M_MINSIZE; 67 m = malloc(M_BASESIZE + len); 68 if (m == NULL) 69 return (ENOMEM); 70 bzero(m, M_BASESIZE + len); 71 m->m_maxlen = len; 72 m->m_data = M_TOP(m); 73 *mpp = m; 74 return (0); 75 } 76 77 static void 78 m_free(struct mbuf *m) 79 { 80 free(m); 81 } 82 83 static void 84 m_freem(struct mbuf *m0) 85 { 86 struct mbuf *m; 87 88 while (m0) { 89 m = m0->m_next; 90 m_free(m0); 91 m0 = m; 92 } 93 } 94 95 static size_t 96 m_totlen(struct mbuf *m0) 97 { 98 struct mbuf *m = m0; 99 int len = 0; 100 101 while (m) { 102 len += m->m_len; 103 m = m->m_next; 104 } 105 return (len); 106 } 107 108 int 109 m_lineup(struct mbuf *m0, struct mbuf **mpp) 110 { 111 struct mbuf *nm, *m; 112 char *dp; 113 size_t len; 114 int error; 115 116 if (m0->m_next == NULL) { 117 *mpp = m0; 118 return (0); 119 } 120 if ((error = m_get(m_totlen(m0), &nm)) != 0) 121 return (error); 122 dp = mtod(nm, char *); 123 while (m0) { 124 len = m0->m_len; 125 bcopy(m0->m_data, dp, len); 126 dp += len; 127 m = m0->m_next; 128 m_free(m0); 129 m0 = m; 130 } 131 *mpp = nm; 132 return (0); 133 } 134 135 int 136 mb_init(struct mbdata *mbp, size_t size) 137 { 138 struct mbuf *m; 139 int error; 140 141 if ((error = m_get(size, &m)) != 0) 142 return (error); 143 return (mb_initm(mbp, m)); 144 } 145 146 int 147 mb_initm(struct mbdata *mbp, struct mbuf *m) 148 { 149 bzero(mbp, sizeof (*mbp)); 150 mbp->mb_top = mbp->mb_cur = m; 151 mbp->mb_pos = mtod(m, char *); 152 return (0); 153 } 154 155 int 156 mb_done(struct mbdata *mbp) 157 { 158 if (mbp->mb_top) { 159 m_freem(mbp->mb_top); 160 mbp->mb_top = NULL; 161 } 162 return (0); 163 } 164 165 int 166 m_getm(struct mbuf *top, size_t len, struct mbuf **mpp) 167 { 168 struct mbuf *m, *mp; 169 int error, ts; 170 171 for (mp = top; ; mp = mp->m_next) { 172 ts = M_TRAILINGSPACE(mp); 173 if (len <= ts) 174 goto out; 175 len -= ts; 176 if (mp->m_next == NULL) 177 break; 178 179 } 180 if (len > 0) { 181 if ((error = m_get(len, &m)) != 0) 182 return (error); 183 mp->m_next = m; 184 } 185 out: 186 *mpp = top; 187 return (0); 188 } 189 190 /* 191 * Routines to put data in a buffer 192 */ 193 #define MB_PUT(t) int error; t *p; \ 194 if ((error = mb_fit(mbp, sizeof (t), (char **)&p)) != 0) \ 195 return (error) 196 197 /* 198 * Check if object of size 'size' fit to the current position and 199 * allocate new mbuf if not. Advance pointers and increase length of mbuf(s). 200 * Return pointer to the object placeholder or NULL if any error occured. 201 */ 202 int 203 mb_fit(struct mbdata *mbp, size_t size, char **pp) 204 { 205 struct mbuf *m, *mn; 206 int error; 207 208 m = mbp->mb_cur; 209 if (M_TRAILINGSPACE(m) < (int)size) { 210 if ((error = m_get(size, &mn)) != 0) 211 return (error); 212 mbp->mb_pos = mtod(mn, char *); 213 mbp->mb_cur = m->m_next = mn; 214 m = mn; 215 } 216 m->m_len += size; 217 *pp = mbp->mb_pos; 218 mbp->mb_pos += size; 219 mbp->mb_count += size; 220 return (0); 221 } 222 223 int 224 mb_put_uint8(struct mbdata *mbp, uint8_t x) 225 { 226 MB_PUT(uint8_t); 227 *p = x; 228 return (0); 229 } 230 231 int 232 mb_put_uint16be(struct mbdata *mbp, uint16_t x) 233 { 234 MB_PUT(uint16_t); 235 /* LINTED */ 236 setwbe(p, 0, x); 237 return (0); 238 } 239 240 int 241 mb_put_uint16le(struct mbdata *mbp, uint16_t x) 242 { 243 MB_PUT(uint16_t); 244 /* LINTED */ 245 setwle(p, 0, x); 246 return (0); 247 } 248 249 int 250 mb_put_uint32be(struct mbdata *mbp, uint32_t x) 251 { 252 MB_PUT(uint32_t); 253 /* LINTED */ 254 setdbe(p, 0, x); 255 return (0); 256 } 257 258 int 259 mb_put_uint32le(struct mbdata *mbp, uint32_t x) 260 { 261 MB_PUT(uint32_t); 262 /* LINTED */ 263 setdle(p, 0, x); 264 return (0); 265 } 266 267 int 268 mb_put_uint64be(struct mbdata *mbp, uint64_t x) 269 { 270 MB_PUT(uint64_t); 271 *p = htobeq(x); 272 return (0); 273 } 274 275 int 276 mb_put_uint64le(struct mbdata *mbp, uint64_t x) 277 { 278 MB_PUT(uint64_t); 279 *p = htoleq(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, uint8_t *x) 354 { 355 return (mb_get_mem(mbp, (char *)x, 1)); 356 } 357 358 int 359 mb_get_uint16(struct mbdata *mbp, uint16_t *x) 360 { 361 return (mb_get_mem(mbp, (char *)x, 2)); 362 } 363 364 int 365 mb_get_uint16le(struct mbdata *mbp, uint16_t *x) 366 { 367 uint16_t v; 368 int error = mb_get_uint16(mbp, &v); 369 370 if (x != NULL) 371 *x = letohs(v); 372 return (error); 373 } 374 375 int 376 mb_get_uint16be(struct mbdata *mbp, uint16_t *x) { 377 uint16_t v; 378 int error = mb_get_uint16(mbp, &v); 379 380 if (x != NULL) 381 *x = betohs(v); 382 return (error); 383 } 384 385 int 386 mb_get_uint32(struct mbdata *mbp, uint32_t *x) 387 { 388 return (mb_get_mem(mbp, (char *)x, 4)); 389 } 390 391 int 392 mb_get_uint32be(struct mbdata *mbp, uint32_t *x) 393 { 394 uint32_t v; 395 int error; 396 397 error = mb_get_uint32(mbp, &v); 398 if (x != NULL) 399 *x = betohl(v); 400 return (error); 401 } 402 403 int 404 mb_get_uint32le(struct mbdata *mbp, uint32_t *x) 405 { 406 uint32_t v; 407 int error; 408 409 error = mb_get_uint32(mbp, &v); 410 if (x != NULL) 411 *x = letohl(v); 412 return (error); 413 } 414 415 int 416 mb_get_uint64(struct mbdata *mbp, uint64_t *x) 417 { 418 return (mb_get_mem(mbp, (char *)x, 8)); 419 } 420 421 int 422 mb_get_uint64be(struct mbdata *mbp, uint64_t *x) 423 { 424 uint64_t v; 425 int error; 426 427 error = mb_get_uint64(mbp, &v); 428 if (x != NULL) 429 *x = betohq(v); 430 return (error); 431 } 432 433 int 434 mb_get_uint64le(struct mbdata *mbp, uint64_t *x) 435 { 436 uint64_t v; 437 int error; 438 439 error = mb_get_uint64(mbp, &v); 440 if (x != NULL) 441 *x = letohq(v); 442 return (error); 443 } 444 445 int 446 mb_get_mem(struct mbdata *mbp, char *target, size_t size) 447 { 448 struct mbuf *m = mbp->mb_cur; 449 uint_t count; 450 451 while (size > 0) { 452 if (m == NULL) { 453 #ifdef DEBUG 454 printf( 455 dgettext(TEXT_DOMAIN, "incomplete copy\n")); 456 #endif 457 #ifdef APPLE 458 MBERROR("incomplete copy\n"); 459 #endif 460 return (EBADRPC); 461 } 462 count = mb_left(m, mbp->mb_pos); 463 if (count == 0) { 464 mbp->mb_cur = m = m->m_next; 465 if (m) 466 mbp->mb_pos = mtod(m, char *); 467 continue; 468 } 469 if (count > size) 470 count = size; 471 size -= count; 472 if (target) { 473 if (count == 1) { 474 *target++ = *mbp->mb_pos; 475 } else { 476 bcopy(mbp->mb_pos, target, count); 477 target += count; 478 } 479 } 480 mbp->mb_pos += count; 481 } 482 return (0); 483 } 484