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