1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "@(#)smb_mbuf_marshaling.c 1.6 08/08/08 SMI" 27 28 /* 29 * SMB mbuf marshaling encode/decode. 30 */ 31 32 #include <smbsrv/smb_incl.h> 33 34 #define MALLOC_QUANTUM 80 35 36 #define DECODE_NO_ERROR 0 37 #define DECODE_NO_MORE_DATA 1 38 #define DECODE_ALLOCATION_ERROR 2 39 #define DECODE_CONVERSION_ERROR 3 40 41 static int mbc_marshal_make_room(mbuf_chain_t *, int32_t); 42 static void mbc_marshal_store_byte(mbuf_chain_t *, uint8_t); 43 static int mbc_marshal_put_char(mbuf_chain_t *mbc, uint8_t); 44 static int mbc_marshal_put_short(mbuf_chain_t *mbc, uint16_t); 45 static int mbc_marshal_put_long(mbuf_chain_t *mbc, uint32_t); 46 static int mbc_marshal_put_long_long(mbuf_chain_t *mbc, uint64_t); 47 static int mbc_marshal_put_ascii_string(mbuf_chain_t *, char *, int); 48 static int mbc_marshal_put_unicode_string(mbuf_chain_t *, char *, int); 49 static int mbc_marshal_put_uio(mbuf_chain_t *, struct uio *); 50 static int mbc_marshal_put_mbufs(mbuf_chain_t *mbc, mbuf_t *m); 51 static int mbc_marshal_put_mbuf_chain(mbuf_chain_t *mbc, mbuf_chain_t *nmbc); 52 static uint8_t mbc_marshal_fetch_byte(mbuf_chain_t *mbc); 53 static int mbc_marshal_get_char(mbuf_chain_t *mbc, uint8_t *data); 54 static int mbc_marshal_get_short(mbuf_chain_t *mbc, uint16_t *data); 55 static int mbc_marshal_get_long(mbuf_chain_t *mbc, uint32_t *data); 56 static uint64_t qswap(uint64_t ll); 57 static int mbc_marshal_get_odd_long_long(mbuf_chain_t *mbc, uint64_t *data); 58 static int mbc_marshal_get_long_long(mbuf_chain_t *mbc, uint64_t *data); 59 static int mbc_marshal_get_ascii_string(struct smb_malloc_list *, 60 mbuf_chain_t *, uint8_t **ascii, int); 61 static int mbc_marshal_get_unicode_string(struct smb_malloc_list *, 62 mbuf_chain_t *, uint8_t **, int); 63 static int mbc_marshal_get_mbufs(mbuf_chain_t *, int32_t, mbuf_t **); 64 static int mbc_marshal_get_mbuf_chain(mbuf_chain_t *, int32_t, mbuf_chain_t *); 65 static int mbc_marshal_get_uio(mbuf_chain_t *, struct uio *); 66 static int mbc_marshal_get_skip(mbuf_chain_t *, uint_t); 67 68 /* 69 * smb_mbc_vdecodef 70 * 71 * This function reads the contents of the mbc chain passed in under the list 72 * of arguments passed in. 73 * 74 * The format string provides a description of the parameters passed in as well 75 * as an action to be taken by smb_mbc_vdecodef(). 76 * 77 * % Pointer to an SMB request structure (smb_request_t *). There 78 * should be only one of these in the string. 79 * 80 * C Pointer to an mbuf chain. Copy to that mbuf chain the number of 81 * bytes specified (number preceding C). 82 * 83 * m Pointer to an mbuf. Copy to that mbuf the number of bytes 84 * specified (number preceding m). 85 * 86 * M Read the 32 bit value at the current location of the mbuf chain 87 * and check if it matches the signature of an SMB request (SMBX). 88 * 89 * b Pointer to a buffer. Copy to that buffer the number of bytes 90 * specified (number preceding b). 91 * 92 * c Same as 'b'. 93 * 94 * w Pointer to a word (16bit value). Copy the next 16bit value into 95 * that location. 96 * 97 * l Pointer to a long (32bit value). Copy the next 32bit value into 98 * that location. 99 * 100 * q Pointer to a quad (64bit value). Copy the next 64bit value into 101 * that location. 102 * 103 * Q Same as above with a call to qswap(). 104 * 105 * B Pointer to a vardata_block structure. That structure is used to 106 * retrieve data from the mbuf chain (an iovec type structure is 107 * embedded in a vardata_block). 108 * 109 * D Pointer to a vardata_block structure. That structure is used to 110 * retrieve data from the mbuf chain, however, two fields of the 111 * vardata_block structure (tag and len) are first initialized 112 * using the mbuf chain itself. 113 * 114 * V Same as 'D'. 115 * 116 * L 117 * 118 * A 119 * 120 * P Same as 'A' 121 * 122 * S Same as 'A' 123 * 124 * u Pointer to a string pointer. Allocate memory and retrieve the 125 * string at the current location in the mbuf chain. Store the 126 * address to the buffer allocated at the address specified by 127 * the pointer. In addition if an sr was passed and it indicates 128 * that the string is an unicode string, convert it. 129 * 130 * s Same as 'u' without convertion. 131 * 132 * U Same as 'u'. The string to retrieve is unicode. 133 * 134 * y Pointer to a 32bit value. Read the dos time at the current mbuf 135 * chain location, convert it to unix time and store it at the 136 * location indicated by the pointer. 137 * 138 * Y Same as 'y' bt the dos time coded in the mbuf chain is inverted. 139 * 140 * . Skip the number of bytes indicated by the number preceding '.'. 141 * 142 * , Same as '.' but take in account it is an unicode string. 143 */ 144 int 145 smb_mbc_vdecodef(mbuf_chain_t *mbc, char *fmt, va_list ap) 146 { 147 uint8_t c; 148 uint8_t cval; 149 uint8_t *cvalp; 150 uint8_t **cvalpp; 151 uint16_t *wvalp; 152 uint32_t *lvalp; 153 uint64_t *llvalp; 154 smb_vdb_t *vdp; 155 smb_request_t *sr = NULL; 156 uint32_t lval; 157 int unicode = 0; 158 int repc; 159 160 while ((c = *fmt++) != 0) { 161 repc = 1; 162 163 if ('0' <= c && c <= '9') { 164 repc = 0; 165 do { 166 repc = repc * 10 + c - '0'; 167 c = *fmt++; 168 } while ('0' <= c && c <= '9'); 169 } else if (c == '#') { 170 repc = va_arg(ap, int); 171 c = *fmt++; 172 } 173 174 switch (c) { 175 case '%': 176 sr = va_arg(ap, struct smb_request *); 177 unicode = sr->smb_flg2 & SMB_FLAGS2_UNICODE; 178 break; 179 180 case 'C': /* Mbuf_chain */ 181 if (mbc_marshal_get_mbuf_chain(mbc, repc, 182 va_arg(ap, mbuf_chain_t *)) != 0) 183 return (-1); 184 break; 185 186 case 'm': /* struct_mbuf */ 187 if (mbc_marshal_get_mbufs(mbc, repc, 188 va_arg(ap, mbuf_t **)) != 0) 189 return (-1); 190 break; 191 192 case 'M': 193 if (mbc_marshal_get_long(mbc, &lval) != 0) 194 /* Data will never be available */ 195 return (-1); 196 197 if (lval != 0x424D53FF) /* 0xFF S M B */ 198 return (-1); 199 break; 200 201 case 'b': 202 case 'c': 203 cvalp = va_arg(ap, uint8_t *); 204 if (MBC_ROOM_FOR(mbc, repc) == 0) 205 /* Data will never be available */ 206 return (-1); 207 208 while (repc-- > 0) 209 *cvalp++ = mbc_marshal_fetch_byte(mbc); 210 break; 211 212 case 'w': 213 wvalp = va_arg(ap, uint16_t *); 214 while (repc-- > 0) 215 if (mbc_marshal_get_short(mbc, wvalp++) != 0) 216 return (-1); 217 break; 218 219 case 'l': 220 lvalp = va_arg(ap, uint32_t *); 221 while (repc-- > 0) 222 if (mbc_marshal_get_long(mbc, lvalp++) != 0) 223 return (-1); 224 break; 225 226 case 'q': 227 llvalp = va_arg(ap, uint64_t *); 228 while (repc-- > 0) 229 if (mbc_marshal_get_long_long( 230 mbc, llvalp++) != 0) 231 return (-1); 232 break; 233 234 case 'Q': 235 llvalp = va_arg(ap, uint64_t *); 236 while (repc-- > 0) 237 if (mbc_marshal_get_odd_long_long( 238 mbc, llvalp++) != 0) 239 return (-1); 240 break; 241 242 case 'B': 243 vdp = va_arg(ap, struct vardata_block *); 244 vdp->tag = 0; 245 246 /*LINTED E_ASSIGN_NARROW_CONV (BYTE)*/ 247 vdp->len = repc; 248 vdp->uio.uio_iov = &vdp->iovec[0]; 249 vdp->uio.uio_iovcnt = MAX_IOVEC; 250 vdp->uio.uio_resid = repc; 251 if (mbc_marshal_get_uio(mbc, &vdp->uio) != 0) 252 return (-1); 253 break; 254 255 case 'D': 256 case 'V': 257 vdp = va_arg(ap, struct vardata_block *); 258 if (mbc_marshal_get_char(mbc, &vdp->tag) != 0) 259 return (-1); 260 if (mbc_marshal_get_short(mbc, &vdp->len) != 0) 261 return (-1); 262 vdp->uio.uio_iov = &vdp->iovec[0]; 263 vdp->uio.uio_iovcnt = MAX_IOVEC; 264 vdp->uio.uio_resid = vdp->len; 265 if (vdp->len != 0) { 266 if (mbc_marshal_get_uio(mbc, &vdp->uio) != 0) 267 return (-1); 268 } 269 break; 270 271 case 'L': 272 if (mbc_marshal_get_char(mbc, &cval) != 0) 273 return (-1); 274 if (cval != 2) 275 return (-1); 276 goto ascii_conversion; 277 278 case 'A': 279 case 'S': 280 if (mbc_marshal_get_char(mbc, &cval) != 0) 281 return (-1); 282 if (((c == 'A' || c == 'S') && cval != 4) || 283 (c == 'L' && cval != 2)) 284 return (-1); 285 /* FALLTHROUGH */ 286 287 case 'u': /* Convert from unicode if flags are set */ 288 if (unicode) 289 goto unicode_translation; 290 /* FALLTHROUGH */ 291 292 case 's': 293 ascii_conversion: 294 ASSERT(sr != NULL); 295 cvalpp = va_arg(ap, uint8_t **); 296 if (repc <= 1) 297 repc = 0; 298 if (mbc_marshal_get_ascii_string(&sr->request_storage, 299 mbc, cvalpp, repc) != 0) 300 return (-1); 301 break; 302 303 case 'U': /* Convert from unicode */ 304 unicode_translation: 305 ASSERT(sr != 0); 306 cvalpp = va_arg(ap, uint8_t **); 307 if (repc <= 1) 308 repc = 0; 309 if (mbc->chain_offset & 1) 310 mbc->chain_offset++; 311 if (mbc_marshal_get_unicode_string(&sr->request_storage, 312 mbc, cvalpp, repc) != 0) 313 return (-1); 314 break; 315 316 case 'Y': /* dos time to unix time tt/dd */ 317 lvalp = va_arg(ap, uint32_t *); 318 while (repc-- > 0) { 319 short d, t; 320 321 if (mbc_marshal_get_short(mbc, 322 (uint16_t *)&t) != 0) 323 return (-1); 324 if (mbc_marshal_get_short(mbc, 325 (uint16_t *)&d) != 0) 326 return (-1); 327 *lvalp++ = smb_dos_to_ux_time(d, t); 328 } 329 break; 330 331 case 'y': /* dos time to unix time dd/tt */ 332 lvalp = va_arg(ap, uint32_t *); 333 while (repc-- > 0) { 334 short d, t; 335 336 if (mbc_marshal_get_short(mbc, 337 (uint16_t *)&d) != 0) 338 return (-1); 339 if (mbc_marshal_get_short(mbc, 340 (uint16_t *)&t) != 0) 341 return (-1); 342 *lvalp++ = smb_dos_to_ux_time(d, t); 343 } 344 break; 345 346 case ',': 347 if (unicode) 348 repc *= 2; 349 /* FALLTHROUGH */ 350 351 case '.': 352 if (mbc_marshal_get_skip(mbc, repc) != 0) 353 return (-1); 354 break; 355 356 default: 357 ASSERT(0); 358 return (-1); 359 } 360 } 361 return (0); 362 } 363 364 /* 365 * smb_mbc_decodef 366 * 367 * This function reads the contents of the mbc chain passed in under the 368 * control of the format fmt. 369 * 370 * (for a description of the format string see smb_mbc_vencodef()). 371 */ 372 int 373 smb_mbc_decodef(mbuf_chain_t *mbc, char *fmt, ...) 374 { 375 int xx; 376 va_list ap; 377 378 va_start(ap, fmt); 379 xx = smb_mbc_vdecodef(mbc, fmt, ap); 380 va_end(ap); 381 return (xx); 382 } 383 384 /* 385 * smb_mbc_peek 386 * 387 * This function reads the contents of the mbc passed in at the specified offset 388 * under the control of the format fmt. The offset of the chain passed in is not 389 * modified. 390 * 391 * (for a description of the format string see smb_mbc_vdecodef()). 392 */ 393 int 394 smb_mbc_peek(mbuf_chain_t *mbc, int offset, char *fmt, ...) 395 { 396 mbuf_chain_t tmp; 397 va_list ap; 398 int xx; 399 400 va_start(ap, fmt); 401 402 (void) MBC_SHADOW_CHAIN(&tmp, mbc, offset, mbc->max_bytes - offset); 403 xx = smb_mbc_vdecodef(&tmp, fmt, ap); 404 va_end(ap); 405 return (xx); 406 } 407 408 /* 409 * smb_mbc_vencodef 410 * 411 * This function builds a stream of bytes in the mbc chain passed in under the 412 * control of the list of arguments passed in. 413 * 414 * The format string provides a description of the parameters passed in as well 415 * as an action to be taken by smb_mbc_vencodef(). 416 * 417 * \b Restore the mbuf chain offset to its initial value. 418 * 419 * % Pointer to an SMB request structure (smb_request_t *). There 420 * should be only one of these in the string. If an sr in present 421 * it will be used to determine if unicode conversion should be 422 * applied to the strings. 423 * 424 * C Pointer to an mbuf chain. Copy that mbuf chain into the 425 * destination mbuf chain. 426 * 427 * D Pointer to a vardata_block structure. Copy the data described 428 * by that structure into the mbuf chain. The tag field is hard 429 * coded to '1'. 430 * 431 * M Write the SMB request signature ('SMBX') into the mbuf chain. 432 * 433 * T Pointer to a timestruc_t. Convert the content of the structure 434 * into NT time and store the result of the conversion in the 435 * mbuf chain. 436 * 437 * V Same as 'D' but the tag field is hard coded to '5'. 438 * 439 * b Byte. Store the byte or the nymber of bytes specified into the 440 * the mbuf chain. A format string like this "2b" would require 2 441 * bytes to be passed in. 442 * 443 * m Pointer to an mbuf. Copy the contents of the mbuf into the mbuf 444 * chain. 445 * 446 * c Pointer to a buffer. Copy the buffer into the mbuf chain. The 447 * size of the buffer is indicated by the number preceding 'c'. 448 * 449 * w Word (16bit value). Store the word or the number of words 450 * specified into the the mbuf chain. A format string like this 451 * "2w" would require 2 words to be passed in. 452 * 453 * l Long (32bit value). Store the long or the number of longs 454 * specified into the the mbuf chain. A format string like this 455 * "2l" would require 2 longs to be passed in. 456 * 457 * q Quad (64bit value). Store the quad or the number of quads 458 * specified into the the mbuf chain. A format string like this 459 * "2q" would require 2 quads to be passed in. 460 * 461 * L Pointer to a string. Store the string passed in into the mbuf 462 * chain preceded with a tag value of '2'. 463 * 464 * S Pointer to a string. Store the string passed in into the mbuf 465 * chain preceded with a tag value of '4'. Applied a unicode 466 * conversion is appropriate. 467 * 468 * A Same as 'S' 469 * 470 * P Pointer to a string. Store the string passed in into the mbuf 471 * chain preceded with a tag value of '5'. Applied a unicode 472 * conversion is appropriate. 473 * 474 * u Pointer to a string. Store the string passed in into the mbuf 475 * chain. Applied a unicode conversion is appropriate. 476 * 477 * s Pointer to a string. Store the string passed in into the mbuf 478 * chain. 479 * 480 * Y Date/Time. Store the Date/Time or the number of Date/Time(s) 481 * specified into the the mbuf chain. A format string like this 482 * "2Y" would require 2 Date/Time values. The Date/Time is 483 * converted to DOS before storing. 484 * 485 * y Same as 'Y'. The order of Date and Time is reversed. 486 * 487 * , Character. Store the character or number of character specified 488 * into the mbuf chain. A format string like this "2c" would 489 * require 2 characters to be passed in. A unicode conversion is 490 * applied if appropriate. 491 * 492 * . Same as '`' without unicode conversion. 493 * 494 * U Align the offset of the mbuf chain on a 16bit boundary. 495 * 496 * Z Unicode string. Store the unicode string into the mbuf chain 497 * without alignment considerations. 498 * 499 * z Pointer to a string. If appropriate convert to unicode and store 500 * in mbuf chain without alignment ajustment (same as 'Z'), 501 * otherwise store in mbuf chain as ascii (same as 's'). 502 */ 503 int 504 smb_mbc_vencodef(mbuf_chain_t *mbc, char *fmt, va_list ap) 505 { 506 uint8_t *cvalp; 507 timestruc_t *tvp; 508 smb_vdb_t *vdp; 509 smb_request_t *sr = NULL; 510 uint64_t llval; 511 int64_t nt_time; 512 uint32_t lval; 513 uint_t tag; 514 int unicode = 0; 515 int repc = 1; 516 uint16_t wval; 517 uint8_t cval; 518 uint8_t c; 519 520 while ((c = *fmt++) != 0) { 521 repc = 1; 522 523 if ('0' <= c && c <= '9') { 524 repc = 0; 525 do { 526 repc = repc * 10 + c - '0'; 527 c = *fmt++; 528 } while ('0' <= c && c <= '9'); 529 } else if (c == '#') { 530 repc = va_arg(ap, int); 531 c = *fmt++; 532 } 533 534 switch (c) { 535 case '%': 536 sr = va_arg(ap, struct smb_request *); 537 unicode = sr->smb_flg2 & SMB_FLAGS2_UNICODE; 538 break; 539 540 case 'C': /* Mbuf_chain */ 541 if (mbc_marshal_put_mbuf_chain(mbc, 542 va_arg(ap, mbuf_chain_t *)) != 0) 543 return (DECODE_NO_MORE_DATA); 544 break; 545 546 case 'D': 547 vdp = va_arg(ap, struct vardata_block *); 548 549 if (mbc_marshal_put_char(mbc, 1) != 0) 550 return (DECODE_NO_MORE_DATA); 551 if (mbc_marshal_put_short(mbc, vdp->len) != 0) 552 return (DECODE_NO_MORE_DATA); 553 if (mbc_marshal_put_uio(mbc, &vdp->uio) != 0) 554 return (DECODE_NO_MORE_DATA); 555 break; 556 557 case 'M': 558 /* 0xFF S M B */ 559 if (mbc_marshal_put_long(mbc, 0x424D53FF)) 560 return (DECODE_NO_MORE_DATA); 561 break; 562 563 case 'T': 564 tvp = va_arg(ap, timestruc_t *); 565 nt_time = unix_to_nt_time(tvp); 566 if (mbc_marshal_put_long_long(mbc, nt_time) != 0) 567 return (DECODE_NO_MORE_DATA); 568 break; 569 570 case 'V': 571 vdp = va_arg(ap, struct vardata_block *); 572 573 if (mbc_marshal_put_char(mbc, 5) != 0) 574 return (DECODE_NO_MORE_DATA); 575 if (mbc_marshal_put_short(mbc, vdp->len) != 0) 576 return (DECODE_NO_MORE_DATA); 577 if (mbc_marshal_put_uio(mbc, &vdp->uio) != 0) 578 return (DECODE_NO_MORE_DATA); 579 break; 580 581 case 'b': 582 while (repc-- > 0) { 583 cval = va_arg(ap, int); 584 if (mbc_marshal_put_char(mbc, cval) != 0) 585 return (DECODE_NO_MORE_DATA); 586 } 587 break; 588 589 case 'm': /* struct_mbuf */ 590 if (mbc_marshal_put_mbufs(mbc, 591 va_arg(ap, mbuf_t *)) != 0) 592 return (DECODE_NO_MORE_DATA); 593 break; 594 595 case 'c': 596 cvalp = va_arg(ap, uint8_t *); 597 while (repc-- > 0) { 598 if (mbc_marshal_put_char(mbc, 599 *cvalp++) != 0) 600 return (DECODE_NO_MORE_DATA); 601 } 602 break; 603 604 case 'w': 605 while (repc-- > 0) { 606 wval = va_arg(ap, int); 607 if (mbc_marshal_put_short(mbc, wval) != 0) 608 return (DECODE_NO_MORE_DATA); 609 } 610 break; 611 612 case 'l': 613 while (repc-- > 0) { 614 lval = va_arg(ap, uint32_t); 615 if (mbc_marshal_put_long(mbc, lval) != 0) 616 return (DECODE_NO_MORE_DATA); 617 } 618 break; 619 620 case 'q': 621 while (repc-- > 0) { 622 llval = va_arg(ap, uint64_t); 623 if (mbc_marshal_put_long_long(mbc, llval) != 0) 624 return (DECODE_NO_MORE_DATA); 625 } 626 break; 627 628 629 case 'L': 630 tag = 2; 631 goto ascii_conversion; 632 633 case 'S': 634 case 'A': 635 tag = 4; 636 goto tagged_str; 637 638 case 'P': 639 tag = 3; 640 goto tagged_str; 641 642 tagged_str: 643 if (mbc_marshal_put_char(mbc, tag) != 0) 644 return (DECODE_NO_MORE_DATA); 645 /* FALLTHROUGH */ 646 647 case 'u': /* Convert from unicode if flags are set */ 648 if (unicode) 649 goto unicode_translation; 650 /* FALLTHROUGH */ 651 652 case 's': /* ASCII/multibyte string */ 653 ascii_conversion: cvalp = va_arg(ap, uint8_t *); 654 if (mbc_marshal_put_ascii_string(mbc, 655 (char *)cvalp, repc) != 0) 656 return (DECODE_NO_MORE_DATA); 657 break; 658 659 case 'Y': /* int32_t, encode dos date/time */ 660 while (repc-- > 0) { 661 uint16_t d, t; 662 663 lval = va_arg(ap, uint32_t); 664 (void) smb_ux_to_dos_time(lval, 665 (short *)&d, (short *)&t); 666 if (mbc_marshal_put_short(mbc, t) != 0) 667 return (DECODE_NO_MORE_DATA); 668 if (mbc_marshal_put_short(mbc, d) != 0) 669 return (DECODE_NO_MORE_DATA); 670 } 671 break; 672 673 case 'y': /* int32_t, encode dos date/time */ 674 while (repc-- > 0) { 675 uint16_t d, t; 676 677 lval = va_arg(ap, uint32_t); 678 (void) smb_ux_to_dos_time(lval, 679 (short *)&d, (short *)&t); 680 if (mbc_marshal_put_short(mbc, d) != 0) 681 return (DECODE_NO_MORE_DATA); 682 if (mbc_marshal_put_short(mbc, t) != 0) 683 return (DECODE_NO_MORE_DATA); 684 } 685 break; 686 687 case ',': 688 if (unicode) 689 repc *= 2; 690 /* FALLTHROUGH */ 691 692 case '.': 693 while (repc-- > 0) 694 if (mbc_marshal_put_char(mbc, 0) != 0) 695 return (DECODE_NO_MORE_DATA); 696 break; 697 698 case 'U': /* Convert to unicode, align to word boundary */ 699 unicode_translation: 700 if (mbc->chain_offset & 1) 701 mbc->chain_offset++; 702 /* FALLTHROUGH */ 703 704 case 'Z': /* Convert to unicode, no alignment adjustment */ 705 cvalp = va_arg(ap, uint8_t *); 706 if (mbc_marshal_put_unicode_string(mbc, 707 (char *)cvalp, repc) != 0) 708 return (DECODE_NO_MORE_DATA); 709 break; 710 711 case 'z': 712 cvalp = va_arg(ap, uint8_t *); 713 if (unicode) { 714 if (mbc_marshal_put_unicode_string(mbc, 715 (char *)cvalp, repc) != 0) 716 return (DECODE_NO_MORE_DATA); 717 } else { 718 if (mbc_marshal_put_ascii_string(mbc, 719 (char *)cvalp, repc) != 0) 720 return (DECODE_NO_MORE_DATA); 721 } 722 break; 723 724 default: 725 ASSERT(0); 726 return (-1); 727 } 728 } 729 return (0); 730 } 731 732 /* 733 * smb_mbc_encodef 734 * 735 * This function builds a stream of bytes in the mbc chain passed in under the 736 * control of the format fmt. 737 * 738 * (for a description of the format string see smb_mbc_vencodef()). 739 */ 740 int 741 smb_mbc_encodef(mbuf_chain_t *mbc, char *fmt, ...) 742 { 743 int rc; 744 va_list ap; 745 746 va_start(ap, fmt); 747 rc = smb_mbc_vencodef(mbc, fmt, ap); 748 va_end(ap); 749 return (rc); 750 } 751 752 /* 753 * smb_mbc_poke 754 * 755 * This function writes a stream of bytes in the mbc passed in at the specified 756 * offset under the control of the format fmt. The offset of the chain passed in 757 * is not modified. 758 * 759 * (for a description of the format string see smb_mbc_vencodef()). 760 */ 761 int 762 smb_mbc_poke(mbuf_chain_t *mbc, int offset, char *fmt, ...) 763 { 764 int xx; 765 mbuf_chain_t tmp; 766 va_list ap; 767 768 (void) MBC_SHADOW_CHAIN(&tmp, mbc, offset, mbc->max_bytes - offset); 769 va_start(ap, fmt); 770 xx = smb_mbc_vencodef(&tmp, fmt, ap); 771 va_end(ap); 772 return (xx); 773 } 774 775 /* 776 * Put data into mbuf chain allocating as needed. 777 * Adds room to end of mbuf chain if needed. 778 */ 779 static int 780 mbc_marshal_make_room(mbuf_chain_t *mbc, int32_t bytes_needed) 781 { 782 mbuf_t *m; 783 mbuf_t *l; 784 int32_t bytes_available; 785 786 bytes_needed += mbc->chain_offset; 787 if (bytes_needed > mbc->max_bytes) 788 return (EMSGSIZE); 789 790 if ((m = mbc->chain) == 0) { 791 MGET(m, M_WAIT, MT_DATA); 792 m->m_len = 0; 793 if (mbc->max_bytes > MLEN) 794 MCLGET(m, M_WAIT); 795 mbc->chain = m; 796 /* xxxx */ 797 /* ^ */ 798 } 799 800 /* ---- ----- --xx ---xxx */ 801 /* ^ */ 802 803 l = 0; 804 while ((m != 0) && (bytes_needed >= m->m_len)) { 805 l = m; 806 bytes_needed -= m->m_len; 807 m = m->m_next; 808 } 809 810 if ((bytes_needed == 0) || (m != 0)) { 811 /* We have enough room already */ 812 return (0); 813 } 814 815 /* ---- ----- --xx ---xxx */ 816 /* ^ */ 817 /* Back up to start of last mbuf */ 818 m = l; 819 bytes_needed += m->m_len; 820 821 /* ---- ----- --xx ---xxx */ 822 /* ^ */ 823 824 bytes_available = (m->m_flags & M_EXT) ? 825 m->m_ext.ext_size : MLEN; 826 827 /* ---- ----- --xx ---xxx */ 828 /* ^ */ 829 while ((bytes_needed != 0) && (bytes_needed > bytes_available)) { 830 m->m_len = bytes_available; 831 bytes_needed -= m->m_len; 832 /* ---- ----- --xx ------ */ 833 /* ^ */ 834 835 MGET(m->m_next, M_WAIT, MT_DATA); 836 m = m->m_next; 837 m->m_len = 0; 838 if (bytes_needed > MLEN) 839 MCLGET(m, M_WAIT); 840 841 bytes_available = (m->m_flags & M_EXT) ? 842 m->m_ext.ext_size : MLEN; 843 844 /* ---- ----- --xx ------ xxxx */ 845 /* ^ */ 846 } 847 848 /* ---- ----- --xx ------ xxxx */ 849 /* ^ */ 850 /* Expand last tail as needed */ 851 if (m->m_len <= bytes_needed) { 852 m->m_len = bytes_needed; 853 /* ---- ----- --xx ------ --xx */ 854 /* ^ */ 855 } 856 857 return (0); 858 } 859 860 static void 861 mbc_marshal_store_byte(mbuf_chain_t *mbc, uint8_t data) 862 { 863 mbuf_t *m = mbc->chain; 864 int32_t cur_offset = mbc->chain_offset; 865 866 /* 867 * Scan forward looking for the last data currently in chain. 868 */ 869 while (cur_offset >= m->m_len) { 870 cur_offset -= m->m_len; 871 m = m->m_next; 872 } 873 ((char *)m->m_data)[cur_offset] = data; 874 mbc->chain_offset++; 875 } 876 877 static int 878 mbc_marshal_put_char(mbuf_chain_t *mbc, uint8_t data) 879 { 880 if (mbc_marshal_make_room(mbc, sizeof (char)) != 0) 881 return (DECODE_NO_MORE_DATA); 882 mbc_marshal_store_byte(mbc, data); 883 return (0); 884 } 885 886 static int 887 mbc_marshal_put_short(mbuf_chain_t *mbc, uint16_t data) 888 { 889 if (mbc_marshal_make_room(mbc, sizeof (short))) 890 return (DECODE_NO_MORE_DATA); 891 mbc_marshal_store_byte(mbc, data); 892 mbc_marshal_store_byte(mbc, data >> 8); 893 return (0); 894 } 895 896 static int 897 mbc_marshal_put_long(mbuf_chain_t *mbc, uint32_t data) 898 { 899 if (mbc_marshal_make_room(mbc, sizeof (int32_t))) 900 return (DECODE_NO_MORE_DATA); 901 mbc_marshal_store_byte(mbc, data); 902 mbc_marshal_store_byte(mbc, data >> 8); 903 mbc_marshal_store_byte(mbc, data >> 16); 904 mbc_marshal_store_byte(mbc, data >> 24); 905 return (0); 906 } 907 908 static int 909 mbc_marshal_put_long_long(mbuf_chain_t *mbc, uint64_t data) 910 { 911 if (mbc_marshal_make_room(mbc, sizeof (int64_t))) 912 return (DECODE_NO_MORE_DATA); 913 914 mbc_marshal_store_byte(mbc, data); 915 mbc_marshal_store_byte(mbc, data >> 8); 916 mbc_marshal_store_byte(mbc, data >> 16); 917 mbc_marshal_store_byte(mbc, data >> 24); 918 mbc_marshal_store_byte(mbc, data >> 32); 919 mbc_marshal_store_byte(mbc, data >> 40); 920 mbc_marshal_store_byte(mbc, data >> 48); 921 mbc_marshal_store_byte(mbc, data >> 56); 922 return (0); 923 } 924 925 /* 926 * When need to convert from UTF-8 (internal format) to a single 927 * byte string (external format ) when marshalling a string. 928 */ 929 static int 930 mbc_marshal_put_ascii_string(mbuf_chain_t *mbc, char *mbs, int repc) 931 { 932 mts_wchar_t wide_char; 933 int nbytes; 934 int length; 935 936 if ((length = mts_sbequiv_strlen(mbs)) == -1) 937 return (DECODE_NO_MORE_DATA); 938 939 length += sizeof (char); 940 941 if ((repc > 1) && (repc < length)) 942 length = repc; 943 if (mbc_marshal_make_room(mbc, length)) 944 return (DECODE_NO_MORE_DATA); 945 946 while (*mbs) { 947 /* 948 * We should restore oem chars here. 949 */ 950 nbytes = mts_mbtowc(&wide_char, mbs, MTS_MB_CHAR_MAX); 951 if (nbytes == -1) 952 return (DECODE_NO_MORE_DATA); 953 954 mbc_marshal_store_byte(mbc, (uint8_t)wide_char); 955 956 if (wide_char & 0xFF00) 957 mbc_marshal_store_byte(mbc, wide_char >> 8); 958 959 mbs += nbytes; 960 } 961 962 mbc_marshal_store_byte(mbc, 0); 963 return (0); 964 } 965 966 static int 967 mbc_marshal_put_unicode_string(mbuf_chain_t *mbc, char *ascii, int repc) 968 { 969 mts_wchar_t wchar; 970 int consumed; 971 int length; 972 973 if ((length = mts_wcequiv_strlen(ascii)) == -1) 974 return (DECODE_NO_MORE_DATA); 975 976 length += sizeof (mts_wchar_t); 977 978 if ((repc > 1) && (repc < length)) 979 length = repc; 980 981 if (mbc_marshal_make_room(mbc, length)) 982 return (DECODE_NO_MORE_DATA); 983 while (length > 0) { 984 consumed = mts_mbtowc(&wchar, ascii, MTS_MB_CHAR_MAX); 985 if (consumed == -1) 986 break; /* Invalid sequence */ 987 /* 988 * Note that consumed will be 0 when the null terminator 989 * is encountered and ascii will not be advanced beyond 990 * that point. Length will continue to be decremented so 991 * we won't get stuck here. 992 */ 993 ascii += consumed; 994 mbc_marshal_store_byte(mbc, wchar); 995 mbc_marshal_store_byte(mbc, wchar >> 8); 996 length -= sizeof (mts_wchar_t); 997 } 998 return (0); 999 } 1000 1001 static int 1002 mbc_marshal_put_uio(mbuf_chain_t *mbc, struct uio *uio) 1003 { 1004 mbuf_t **t; 1005 mbuf_t *m = NULL; 1006 struct iovec *iov = uio->uio_iov; 1007 int32_t i, iov_cnt = uio->uio_iovcnt; 1008 1009 iov = uio->uio_iov; 1010 t = &mbc->chain; 1011 for (i = 0; i < iov_cnt; i++) { 1012 MGET(m, M_WAIT, MT_DATA); 1013 m->m_ext.ext_buf = iov->iov_base; 1014 m->m_ext.ext_ref = smb_noop; 1015 m->m_data = m->m_ext.ext_buf; 1016 m->m_flags |= M_EXT; 1017 m->m_len = m->m_ext.ext_size = iov->iov_len; 1018 mbc->max_bytes += m->m_len; 1019 m->m_next = 0; 1020 *t = m; 1021 t = &m->m_next; 1022 iov++; 1023 } 1024 return (0); 1025 } 1026 1027 static int 1028 mbc_marshal_put_mbufs(mbuf_chain_t *mbc, mbuf_t *m) 1029 { 1030 mbuf_t *mt; 1031 mbuf_t **t; 1032 int bytes; 1033 1034 if (m != NULL) { 1035 mt = m; 1036 bytes = mt->m_len; 1037 while (mt->m_next != 0) { 1038 mt = mt->m_next; 1039 bytes += mt->m_len; 1040 } 1041 if (bytes != 0) { 1042 t = &mbc->chain; 1043 while (*t != 0) { 1044 bytes += (*t)->m_len; 1045 t = &(*t)->m_next; 1046 } 1047 *t = m; 1048 mbc->chain_offset = bytes; 1049 } else { 1050 m_freem(m); 1051 } 1052 } 1053 return (0); 1054 } 1055 1056 static int 1057 mbc_marshal_put_mbuf_chain(mbuf_chain_t *mbc, mbuf_chain_t *nmbc) 1058 { 1059 if (nmbc->chain != 0) { 1060 if (mbc_marshal_put_mbufs(mbc, nmbc->chain)) 1061 return (DECODE_NO_MORE_DATA); 1062 MBC_SETUP(nmbc, nmbc->max_bytes); 1063 } 1064 return (0); 1065 } 1066 1067 static uint8_t 1068 mbc_marshal_fetch_byte(mbuf_chain_t *mbc) 1069 { 1070 uint8_t data; 1071 mbuf_t *m = mbc->chain; 1072 int32_t offset = mbc->chain_offset; 1073 1074 while (offset >= m->m_len) { 1075 offset -= m->m_len; 1076 m = m->m_next; 1077 } 1078 data = ((uint8_t *)m->m_data)[offset]; 1079 mbc->chain_offset++; 1080 return (data); 1081 } 1082 1083 static int 1084 mbc_marshal_get_char(mbuf_chain_t *mbc, uint8_t *data) 1085 { 1086 if (MBC_ROOM_FOR(mbc, sizeof (char)) == 0) { 1087 /* Data will never be available */ 1088 return (DECODE_NO_MORE_DATA); 1089 } 1090 *data = mbc_marshal_fetch_byte(mbc); 1091 return (0); 1092 } 1093 1094 static int 1095 mbc_marshal_get_short(mbuf_chain_t *mbc, uint16_t *data) 1096 { 1097 uint16_t tmp; 1098 mbuf_t *m = mbc->chain; 1099 int32_t offset = mbc->chain_offset; 1100 1101 if (MBC_ROOM_FOR(mbc, sizeof (short)) == 0) { 1102 /* Data will never be available */ 1103 return (DECODE_NO_MORE_DATA); 1104 } 1105 1106 while (offset >= m->m_len) { 1107 offset -= m->m_len; 1108 m = m->m_next; 1109 } 1110 if ((m->m_len - offset) >= sizeof (short)) { 1111 *data = LE_IN16(m->m_data + offset); 1112 mbc->chain_offset += sizeof (short); 1113 } else { 1114 tmp = (uint16_t)mbc_marshal_fetch_byte(mbc); 1115 tmp |= ((uint16_t)mbc_marshal_fetch_byte(mbc)) << 8; 1116 *data = tmp; 1117 } 1118 return (0); 1119 } 1120 1121 static int 1122 mbc_marshal_get_long(mbuf_chain_t *mbc, uint32_t *data) 1123 { 1124 uint32_t tmp; 1125 mbuf_t *m = mbc->chain; 1126 int32_t offset = mbc->chain_offset; 1127 1128 if (MBC_ROOM_FOR(mbc, sizeof (int32_t)) == 0) { 1129 /* Data will never be available */ 1130 return (DECODE_NO_MORE_DATA); 1131 } 1132 while (offset >= m->m_len) { 1133 offset -= m->m_len; 1134 m = m->m_next; 1135 } 1136 if ((m->m_len - offset) >= sizeof (int32_t)) { 1137 *data = LE_IN32(m->m_data + offset); 1138 mbc->chain_offset += sizeof (int32_t); 1139 } else { 1140 tmp = (uint32_t)mbc_marshal_fetch_byte(mbc); 1141 tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 8; 1142 tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 16; 1143 tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 24; 1144 *data = tmp; 1145 } 1146 return (0); 1147 } 1148 1149 static uint64_t 1150 qswap(uint64_t ll) 1151 { 1152 uint64_t v; 1153 1154 v = ll >> 32; 1155 v |= ll << 32; 1156 1157 return (v); 1158 } 1159 1160 static int 1161 mbc_marshal_get_odd_long_long(mbuf_chain_t *mbc, uint64_t *data) 1162 { 1163 uint64_t tmp; 1164 mbuf_t *m = mbc->chain; 1165 int32_t offset = mbc->chain_offset; 1166 1167 if (MBC_ROOM_FOR(mbc, sizeof (int64_t)) == 0) { 1168 /* Data will never be available */ 1169 return (DECODE_NO_MORE_DATA); 1170 } 1171 while (offset >= m->m_len) { 1172 offset -= m->m_len; 1173 m = m->m_next; 1174 } 1175 1176 if ((m->m_len - offset) >= sizeof (int64_t)) { 1177 *data = qswap(LE_IN64(m->m_data + offset)); 1178 mbc->chain_offset += sizeof (int64_t); 1179 } else { 1180 tmp = (uint64_t)mbc_marshal_fetch_byte(mbc) << 32; 1181 tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 40; 1182 tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 48; 1183 tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 56; 1184 tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc); 1185 tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 8; 1186 tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 16; 1187 tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 24; 1188 1189 *(uint64_t *)data = tmp; 1190 } 1191 return (0); 1192 } 1193 1194 static int 1195 mbc_marshal_get_long_long(mbuf_chain_t *mbc, uint64_t *data) 1196 { 1197 uint64_t tmp; 1198 mbuf_t *m = mbc->chain; 1199 int32_t offset = mbc->chain_offset; 1200 1201 if (MBC_ROOM_FOR(mbc, sizeof (int64_t)) == 0) { 1202 /* Data will never be available */ 1203 return (DECODE_NO_MORE_DATA); 1204 } 1205 while (offset >= m->m_len) { 1206 offset -= m->m_len; 1207 m = m->m_next; 1208 } 1209 if ((m->m_len - offset) >= sizeof (int64_t)) { 1210 *data = LE_IN64(m->m_data + offset); 1211 mbc->chain_offset += sizeof (int64_t); 1212 } else { 1213 tmp = (uint32_t)mbc_marshal_fetch_byte(mbc); 1214 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 8; 1215 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 16; 1216 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 24; 1217 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 32; 1218 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 40; 1219 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 48; 1220 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 56; 1221 *(uint64_t *)data = tmp; 1222 } 1223 return (0); 1224 } 1225 1226 /* 1227 * mbc_marshal_get_ascii_string 1228 * 1229 * The ascii string in smb includes oem chars. Since the 1230 * system needs utf8 encodes unicode char, conversion is 1231 * required to convert the oem char to unicode and then 1232 * to encode the converted wchars to utf8 format. 1233 * Therefore, the **ascii returned will be in such format 1234 * instead of the real ASCII format. 1235 */ 1236 static int 1237 mbc_marshal_get_ascii_string( 1238 struct smb_malloc_list *ml, 1239 mbuf_chain_t *mbc, 1240 uint8_t **ascii, 1241 int max_ascii) 1242 { 1243 char *rcvbuf; 1244 char *ch; 1245 mts_wchar_t *wtmpbuf; 1246 int max; 1247 int length = 0; 1248 uint_t cpid = oem_get_smb_cpid(); 1249 1250 max = MALLOC_QUANTUM; 1251 rcvbuf = smbsr_malloc(ml, max); 1252 1253 if (max_ascii == 0) 1254 max_ascii = 0xffff; 1255 1256 ch = rcvbuf; 1257 for (;;) { 1258 while (length < max) { 1259 if (max_ascii-- <= 0) { 1260 *ch++ = 0; 1261 goto multibyte_encode; 1262 } 1263 if (MBC_ROOM_FOR(mbc, sizeof (char)) == 0) { 1264 /* Data will never be available */ 1265 return (DECODE_NO_MORE_DATA); 1266 } 1267 if ((*ch++ = mbc_marshal_fetch_byte(mbc)) == 0) 1268 goto multibyte_encode; 1269 length++; 1270 } 1271 max += MALLOC_QUANTUM; 1272 rcvbuf = smbsr_realloc(rcvbuf, max); 1273 ch = rcvbuf + length; 1274 } 1275 1276 multibyte_encode: 1277 /* 1278 * UTF-8 encode the string for internal system use. 1279 */ 1280 length = strlen(rcvbuf) + 1; 1281 wtmpbuf = smbsr_malloc(ml, length*sizeof (mts_wchar_t)); 1282 *ascii = smbsr_malloc(ml, length * MTS_MB_CHAR_MAX); 1283 1284 if (oemstounicodes(wtmpbuf, rcvbuf, length, cpid) > 0) 1285 (void) mts_wcstombs((char *)*ascii, wtmpbuf, 1286 length * MTS_MB_CHAR_MAX); 1287 else 1288 (void) mts_stombs((char *)*ascii, rcvbuf, length * 2); 1289 return (0); 1290 } 1291 1292 static int 1293 mbc_marshal_get_unicode_string(struct smb_malloc_list *ml, 1294 mbuf_chain_t *mbc, uint8_t **ascii, int max_unicode) 1295 { 1296 int max; 1297 uint16_t wchar; 1298 char *ch; 1299 int emitted; 1300 int length = 0; 1301 1302 if (max_unicode == 0) 1303 max_unicode = 0xffff; 1304 1305 max = MALLOC_QUANTUM; 1306 *ascii = smbsr_malloc(ml, max); 1307 1308 ch = (char *)*ascii; 1309 for (;;) { 1310 while ((length + MTS_MB_CHAR_MAX) < max) { 1311 if (max_unicode <= 0) 1312 goto done; 1313 max_unicode -= 2; 1314 1315 if (mbc_marshal_get_short(mbc, &wchar) != 0) 1316 return (DECODE_NO_MORE_DATA); 1317 1318 if (wchar == 0) goto done; 1319 1320 emitted = mts_wctomb(ch, wchar); 1321 length += emitted; 1322 ch += emitted; 1323 } 1324 max += MALLOC_QUANTUM; 1325 *ascii = smbsr_realloc(*ascii, max); 1326 ch = (char *)*ascii + length; 1327 } 1328 done: *ch = 0; 1329 return (0); 1330 } 1331 1332 static int /*ARGSUSED*/ 1333 mbc_marshal_get_mbufs(mbuf_chain_t *mbc, int32_t bytes, mbuf_t **m) 1334 { 1335 if (MBC_ROOM_FOR(mbc, bytes) == 0) { 1336 /* Data will never be available */ 1337 return (DECODE_NO_MORE_DATA); 1338 } 1339 return (0); 1340 } 1341 1342 static int 1343 mbc_marshal_get_mbuf_chain(mbuf_chain_t *mbc, int32_t bytes, mbuf_chain_t *nmbc) 1344 { 1345 int rc; 1346 mbuf_t *m; 1347 1348 if (bytes == 0) { 1349 /* Get all the rest */ 1350 bytes = mbc->max_bytes - mbc->chain_offset; 1351 } 1352 1353 MBC_SETUP(nmbc, mbc->max_bytes); 1354 if ((rc = mbc_marshal_get_mbufs(mbc, bytes, &m)) != 0) { 1355 if (m) 1356 m_freem(m); 1357 return (rc); 1358 } 1359 nmbc->chain = m; 1360 while (m != 0) { 1361 bytes += m->m_len; 1362 m = m->m_next; 1363 } 1364 nmbc->max_bytes = bytes; 1365 return (0); 1366 } 1367 1368 static int 1369 mbc_marshal_get_uio(mbuf_chain_t *mbc, struct uio *uio) 1370 { 1371 int i, offset; 1372 int32_t bytes = uio->uio_resid; 1373 int32_t remainder; 1374 struct iovec *iov; 1375 mbuf_t *m; 1376 1377 /* 1378 * The residual count is tested because in the case of write requests 1379 * with no data (smbtorture RAW-WRITE test will generate that type of 1380 * request) this function is called with a residual count of zero 1381 * bytes. 1382 */ 1383 if (bytes) { 1384 iov = uio->uio_iov; 1385 uio->uio_segflg = UIO_SYSSPACE; 1386 1387 if (MBC_ROOM_FOR(mbc, bytes) == 0) { 1388 /* Data will never be available */ 1389 return (DECODE_NO_MORE_DATA); 1390 } 1391 1392 m = mbc->chain; 1393 offset = mbc->chain_offset; 1394 while (offset >= m->m_len) { 1395 offset -= m->m_len; 1396 m = m->m_next; 1397 ASSERT((offset == 0) || (offset && m)); 1398 } 1399 1400 for (i = 0; (bytes > 0) && (i < uio->uio_iovcnt); i++) { 1401 iov[i].iov_base = &m->m_data[offset]; 1402 remainder = m->m_len - offset; 1403 if (remainder >= bytes) { 1404 iov[i].iov_len = bytes; 1405 mbc->chain_offset += bytes; 1406 break; 1407 } 1408 iov[i].iov_len = remainder; 1409 mbc->chain_offset += remainder; 1410 bytes -= remainder; 1411 m = m->m_next; 1412 offset = 0; 1413 } 1414 if (i == uio->uio_iovcnt) { 1415 return (DECODE_NO_MORE_DATA); 1416 } 1417 uio->uio_iovcnt = i; 1418 } 1419 return (0); 1420 } 1421 1422 static int 1423 mbc_marshal_get_skip(mbuf_chain_t *mbc, uint_t skip) 1424 { 1425 if (MBC_ROOM_FOR(mbc, skip) == 0) 1426 return (DECODE_NO_MORE_DATA); 1427 mbc->chain_offset += skip; 1428 return (0); 1429 } 1430