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