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 2010 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  *
  25  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  26  */
  27 
  28 /*
  29  * SMB mbuf marshaling encode/decode.
  30  */
  31 
  32 #include <smbsrv/smb_kproto.h>
  33 
  34 
  35 #define MALLOC_QUANTUM  80
  36 
  37 #define DECODE_NO_ERROR         0
  38 #define DECODE_NO_MORE_DATA     1
  39 #define DECODE_ALLOCATION_ERROR 2
  40 #define DECODE_CONVERSION_ERROR 3
  41 
  42 static int mbc_marshal_make_room(mbuf_chain_t *, int32_t);
  43 static void mbc_marshal_store_byte(mbuf_chain_t *, uint8_t);
  44 static int mbc_marshal_put_char(mbuf_chain_t *mbc, uint8_t);
  45 static int mbc_marshal_put_short(mbuf_chain_t *mbc, uint16_t);
  46 static int mbc_marshal_put_long(mbuf_chain_t *mbc, uint32_t);
  47 static int mbc_marshal_put_long_long(mbuf_chain_t *mbc, uint64_t);
  48 static int mbc_marshal_put_oem_string(mbuf_chain_t *, char *, int);
  49 static int mbc_marshal_put_unicode_string(mbuf_chain_t *, char *, int);
  50 static int mbc_marshal_put_uio(mbuf_chain_t *, struct uio *);
  51 static int mbc_marshal_put_mbufs(mbuf_chain_t *mbc, mbuf_t *m);
  52 static int mbc_marshal_put_mbuf_chain(mbuf_chain_t *mbc, mbuf_chain_t *nmbc);
  53 static uint8_t mbc_marshal_fetch_byte(mbuf_chain_t *mbc);
  54 static int mbc_marshal_get_char(mbuf_chain_t *mbc, uint8_t *data);
  55 static int mbc_marshal_get_short(mbuf_chain_t *mbc, uint16_t *data);
  56 static int mbc_marshal_get_long(mbuf_chain_t *mbc, uint32_t *data);
  57 static uint64_t qswap(uint64_t ll);
  58 static int mbc_marshal_get_odd_long_long(mbuf_chain_t *mbc, uint64_t *data);
  59 static int mbc_marshal_get_long_long(mbuf_chain_t *mbc, uint64_t *data);
  60 static int mbc_marshal_get_oem_string(smb_request_t *, mbuf_chain_t *,
  61     char **, int);
  62 static int mbc_marshal_get_unicode_string(smb_request_t *, mbuf_chain_t *,
  63     char **, int);
  64 static int mbc_marshal_get_mbufs(mbuf_chain_t *, int32_t, mbuf_t **);
  65 static int mbc_marshal_get_mbuf_chain(mbuf_chain_t *, int32_t, mbuf_chain_t *);
  66 static int mbc_marshal_get_uio(mbuf_chain_t *, struct uio *);
  67 static int mbc_marshal_get_skip(mbuf_chain_t *, uint_t);
  68 
  69 /*
  70  * smb_mbc_vdecodef
  71  *
  72  * This function reads the contents of the mbc chain passed in under the list
  73  * of arguments passed in.
  74  *
  75  * The format string provides a description of the parameters passed in as well
  76  * as an action to be taken by smb_mbc_vdecodef().
  77  *
  78  *      %       Pointer to an SMB request structure (smb_request_t *). There
  79  *              should be only one of these in the string.
  80  *
  81  *      C       Pointer to an mbuf chain. Copy to that mbuf chain the number of
  82  *              bytes specified (number preceding C).
  83  *
  84  *      m       Pointer to an mbuf. Copy to that mbuf the number of bytes
  85  *              specified (number preceding m).
  86  *
  87  *      M       Read the 32 bit value at the current location of the mbuf chain
  88  *              and check if it matches the signature of an SMB1 request (SMBx).
  89  *
  90  *      N       Read the 32 bit value at the current location of the mbuf chain
  91  *              and check if it matches the signature of an SMB2 request (SMBx).
  92  *
  93  *      b       Pointer to a buffer. Copy to that buffer the number of bytes
  94  *              specified (number preceding b).
  95  *
  96  *      c       Same as 'b'.
  97  *
  98  *      w       Pointer to a word (16bit value). Copy the next 16bit value into
  99  *              that location.
 100  *
 101  *      l       Pointer to a long (32bit value). Copy the next 32bit value into
 102  *              that location.
 103  *
 104  *      q       Pointer to a quad (64bit value). Copy the next 64bit value into
 105  *              that location.
 106  *
 107  *      Q       Same as above with a call to qswap().
 108  *
 109  *      B       Pointer to a vardata_block structure. That structure is used to
 110  *              retrieve data from the mbuf chain (an iovec type structure is
 111  *              embedded in a vardata_block).
 112  *
 113  *      D       Pointer to a vardata_block structure. That structure is used to
 114  *              retrieve data from the mbuf chain, however, two fields of the
 115  *              vardata_block structure (tag and len) are first initialized
 116  *              using the mbuf chain itself.
 117  *
 118  *      V       Same as 'D'.
 119  *
 120  *      L
 121  *
 122  *      A
 123  *
 124  *      P       Same as 'A'
 125  *
 126  *      S       Same as 'A'
 127  *
 128  *      u       Pointer to a string pointer. Allocate memory and retrieve the
 129  *              string at the current location in the mbuf chain. Store the
 130  *              address to the buffer allocated at the address specified by
 131  *              the pointer. In addition if an sr was passed and it indicates
 132  *              that the string is an unicode string, convert it.
 133  *
 134  *      s       Same as 'u' without convertion.
 135  *
 136  *      U       Same as 'u'. The string to retrieve is unicode.
 137  *
 138  *      y       Pointer to a 32bit value. Read the dos time at the current mbuf
 139  *              chain location, convert it to unix time and store it at the
 140  *              location indicated by the pointer.
 141  *
 142  *      Y       Same as 'y' bt the dos time coded in the mbuf chain is inverted.
 143  *
 144  *      .       Skip the number of bytes indicated by the number preceding '.'.
 145  *
 146  *      ,       Same as '.' but take in account it is an unicode string.
 147  */
 148 int
 149 smb_mbc_vdecodef(mbuf_chain_t *mbc, const char *fmt, va_list ap)
 150 {
 151         uint8_t         c;
 152         uint8_t         cval;
 153         uint8_t         *cvalp;
 154         char            **charpp;
 155         uint16_t        wval;
 156         uint16_t        *wvalp;
 157         uint32_t        *lvalp;
 158         uint64_t        *llvalp;
 159         smb_vdb_t       *vdp;
 160         smb_request_t   *sr = NULL;
 161         uint32_t        lval;
 162         int             unicode = 0;
 163         int             repc;
 164         boolean_t       repc_specified;
 165 
 166         while ((c = *fmt++) != 0) {
 167                 repc_specified = B_FALSE;
 168                 repc = 1;
 169 
 170                 if ('0' <= c && c <= '9') {
 171                         repc = 0;
 172                         do {
 173                                 repc = repc * 10 + c - '0';
 174                                 c = *fmt++;
 175                         } while ('0' <= c && c <= '9');
 176                         repc_specified = B_TRUE;
 177                 } else if (c == '#') {
 178                         repc = va_arg(ap, int);
 179                         c = *fmt++;
 180                         repc_specified = B_TRUE;
 181                 }
 182 
 183                 switch (c) {
 184                 case '%':
 185                         sr = va_arg(ap, struct smb_request *);
 186                         if (sr->session->dialect >= SMB_VERS_2_BASE) {
 187                                 unicode = 1;
 188                                 break;
 189                         }
 190                         unicode = sr->smb_flg2 & SMB_FLAGS2_UNICODE;
 191                         break;
 192 
 193                 case 'C':       /* Mbuf_chain */
 194                         if (mbc_marshal_get_mbuf_chain(mbc, repc,
 195                             va_arg(ap, mbuf_chain_t *)) != 0)
 196                                 return (-1);
 197                         break;
 198 
 199                 case 'm':       /* struct_mbuf */
 200                         if (mbc_marshal_get_mbufs(mbc, repc,
 201                             va_arg(ap, mbuf_t **)) != 0)
 202                                 return (-1);
 203                         break;
 204 
 205                 case 'M':
 206                         if (mbc_marshal_get_long(mbc, &lval) != 0)
 207                                 return (-1);
 208                         if (lval != 0x424D53FF) /* 0xFF S M B */
 209                                 return (-1);
 210                         break;
 211 
 212                 case 'N':
 213                         if (mbc_marshal_get_long(mbc, &lval) != 0)
 214                                 return (-1);
 215                         if (lval != 0x424D53FE) /* 0xFE S M B */
 216                                 return (-1);
 217                         break;
 218 
 219                 case 'b':
 220                 case 'c':
 221                         cvalp = va_arg(ap, uint8_t *);
 222                         if (MBC_ROOM_FOR(mbc, repc) == 0)
 223                                 /* Data will never be available */
 224                                 return (-1);
 225 
 226                         while (repc-- > 0)
 227                                 *cvalp++ = mbc_marshal_fetch_byte(mbc);
 228                         break;
 229 
 230                 case 'w':
 231                         wvalp = va_arg(ap, uint16_t *);
 232                         while (repc-- > 0)
 233                                 if (mbc_marshal_get_short(mbc, wvalp++) != 0)
 234                                         return (-1);
 235                         break;
 236 
 237                 case 'l':
 238                         lvalp = va_arg(ap, uint32_t *);
 239                         while (repc-- > 0)
 240                                 if (mbc_marshal_get_long(mbc, lvalp++) != 0)
 241                                         return (-1);
 242                         break;
 243 
 244                 case 'q':
 245                         llvalp = va_arg(ap, uint64_t *);
 246                         while (repc-- > 0)
 247                                 if (mbc_marshal_get_long_long(
 248                                     mbc, llvalp++) != 0)
 249                                         return (-1);
 250                         break;
 251 
 252                 case 'Q':
 253                         llvalp = va_arg(ap, uint64_t *);
 254                         while (repc-- > 0)
 255                                 if (mbc_marshal_get_odd_long_long(
 256                                     mbc, llvalp++) != 0)
 257                                         return (-1);
 258                         break;
 259 
 260                 case 'B':
 261                         vdp = va_arg(ap, struct vardata_block *);
 262                         vdp->vdb_tag = 0;
 263                         vdp->vdb_len = repc;
 264                         vdp->vdb_uio.uio_iov = &vdp->vdb_iovec[0];
 265                         vdp->vdb_uio.uio_iovcnt = MAX_IOVEC;
 266                         vdp->vdb_uio.uio_extflg = UIO_COPY_DEFAULT;
 267                         vdp->vdb_uio.uio_resid = repc;
 268                         if (mbc_marshal_get_uio(mbc, &vdp->vdb_uio) != 0)
 269                                 return (-1);
 270                         break;
 271 
 272                 case 'D':
 273                 case 'V':
 274                         vdp = va_arg(ap, struct vardata_block *);
 275                         if (mbc_marshal_get_char(mbc, &vdp->vdb_tag) != 0)
 276                                 return (-1);
 277                         if (mbc_marshal_get_short(mbc, &wval) != 0)
 278                                 return (-1);
 279                         vdp->vdb_len = (uint32_t)wval;
 280                         vdp->vdb_uio.uio_iov = &vdp->vdb_iovec[0];
 281                         vdp->vdb_uio.uio_iovcnt = MAX_IOVEC;
 282                         vdp->vdb_uio.uio_extflg = UIO_COPY_DEFAULT;
 283                         vdp->vdb_uio.uio_resid = vdp->vdb_len;
 284                         if (vdp->vdb_len != 0) {
 285                                 if (mbc_marshal_get_uio(mbc,
 286                                     &vdp->vdb_uio) != 0)
 287                                         return (-1);
 288                         }
 289                         break;
 290 
 291                 case 'L':
 292                         if (mbc_marshal_get_char(mbc, &cval) != 0)
 293                                 return (-1);
 294                         if (cval != 2)
 295                                 return (-1);
 296                         goto oem_conversion;
 297 
 298                 case 'A':
 299                 case 'S':
 300                         if (mbc_marshal_get_char(mbc, &cval) != 0)
 301                                 return (-1);
 302                         if (((c == 'A' || c == 'S') && cval != 4) ||
 303                             (c == 'L' && cval != 2))
 304                                 return (-1);
 305                         /* FALLTHROUGH */
 306 
 307                 case 'u': /* Convert from unicode if flags are set */
 308                         if (unicode)
 309                                 goto unicode_translation;
 310                         /* FALLTHROUGH */
 311 
 312                 case 's':       /* get OEM string */
 313 oem_conversion:
 314                         ASSERT(sr != NULL);
 315                         charpp = va_arg(ap, char **);
 316                         if (!repc_specified)
 317                                 repc = 0;
 318                         if (mbc_marshal_get_oem_string(sr,
 319                             mbc, charpp, repc) != 0)
 320                                 return (-1);
 321                         break;
 322 
 323                 case 'U':       /* get UTF-16 string */
 324 unicode_translation:
 325                         ASSERT(sr != 0);
 326                         charpp = va_arg(ap, char **);
 327                         if (!repc_specified)
 328                                 repc = 0;
 329                         if (mbc_marshal_get_unicode_string(sr,
 330                             mbc, charpp, repc) != 0)
 331                                 return (-1);
 332                         break;
 333 
 334                 case 'Y': /* dos time to unix time tt/dd */
 335                         lvalp = va_arg(ap, uint32_t *);
 336                         while (repc-- > 0) {
 337                                 short   d, t;
 338 
 339                                 if (mbc_marshal_get_short(mbc,
 340                                     (uint16_t *)&t) != 0)
 341                                         return (-1);
 342                                 if (mbc_marshal_get_short(mbc,
 343                                     (uint16_t *)&d) != 0)
 344                                         return (-1);
 345                                 *lvalp++ = smb_time_dos_to_unix(d, t);
 346                         }
 347                         break;
 348 
 349                 case 'y': /* dos time to unix time dd/tt */
 350                         lvalp = va_arg(ap, uint32_t *);
 351                         while (repc-- > 0) {
 352                                 short   d, t;
 353 
 354                                 if (mbc_marshal_get_short(mbc,
 355                                     (uint16_t *)&d) != 0)
 356                                         return (-1);
 357                                 if (mbc_marshal_get_short(mbc,
 358                                     (uint16_t *)&t) != 0)
 359                                         return (-1);
 360                                 *lvalp++ = smb_time_dos_to_unix(d, t);
 361                         }
 362                         break;
 363 
 364                 case ',':
 365                         if (unicode)
 366                                 repc *= 2;
 367                         /* FALLTHROUGH */
 368 
 369                 case '.':
 370                         if (mbc_marshal_get_skip(mbc, repc) != 0)
 371                                 return (-1);
 372                         break;
 373 
 374                 default:
 375                         ASSERT(0);
 376                         return (-1);
 377                 }
 378         }
 379         return (0);
 380 }
 381 
 382 /*
 383  * smb_mbc_decodef
 384  *
 385  * This function reads the contents of the mbc chain passed in under the
 386  * control of the format fmt.
 387  *
 388  * (for a description of the format string see smb_mbc_vencodef()).
 389  */
 390 int
 391 smb_mbc_decodef(mbuf_chain_t *mbc, const char *fmt, ...)
 392 {
 393         int     xx;
 394         va_list ap;
 395 
 396         va_start(ap, fmt);
 397         xx = smb_mbc_vdecodef(mbc, fmt, ap);
 398         va_end(ap);
 399         return (xx);
 400 }
 401 
 402 /*
 403  * smb_mbc_peek
 404  *
 405  * This function reads the contents of the mbc passed in at the specified offset
 406  * under the control of the format fmt. The offset of the chain passed in is not
 407  * modified.
 408  *
 409  * (for a description of the format string see smb_mbc_vdecodef()).
 410  */
 411 int
 412 smb_mbc_peek(mbuf_chain_t *mbc, int offset, const char *fmt, ...)
 413 {
 414         mbuf_chain_t    tmp;
 415         va_list         ap;
 416         int             xx;
 417 
 418         va_start(ap, fmt);
 419 
 420         (void) MBC_SHADOW_CHAIN(&tmp, mbc, offset, mbc->max_bytes - offset);
 421         xx = smb_mbc_vdecodef(&tmp, fmt, ap);
 422         va_end(ap);
 423         return (xx);
 424 }
 425 
 426 /*
 427  * smb_mbc_vencodef
 428  *
 429  * This function builds a stream of bytes in the mbc chain passed in under the
 430  * control of the list of arguments passed in.
 431  *
 432  * The format string provides a description of the parameters passed in as well
 433  * as an action to be taken by smb_mbc_vencodef().
 434  *
 435  *      \b      Restore the mbuf chain offset to its initial value.
 436  *
 437  *      %       Pointer to an SMB request structure (smb_request_t *). There
 438  *              should be only one of these in the string. If an sr in present
 439  *              it will be used to determine if unicode conversion should be
 440  *              applied to the strings.
 441  *
 442  *      C       Pointer to an mbuf chain. Copy that mbuf chain into the
 443  *              destination mbuf chain.
 444  *
 445  *      D       Pointer to a vardata_block structure. Copy the data described
 446  *              by that structure into the mbuf chain. The tag field is hard
 447  *              coded to '1'.
 448  *
 449  *      M       Write the SMB1 request signature ('SMBX') into the mbuf chain.
 450  *
 451  *      N       Write the SMB2 request signature ('SMBX') into the mbuf chain.
 452  *
 453  *      T       Pointer to a timestruc_t. Convert the content of the structure
 454  *              into NT time and store the result of the conversion in the
 455  *              mbuf chain.
 456  *
 457  *      V       Same as 'D' but the tag field is hard coded to '5'.
 458  *
 459  *      b       Byte. Store the byte or the nymber of bytes specified into the
 460  *              the mbuf chain. A format string like this "2b" would require 2
 461  *              bytes to be passed in.
 462  *
 463  *      m       Pointer to an mbuf. Copy the contents of the mbuf into the mbuf
 464  *              chain.
 465  *
 466  *      c       Pointer to a buffer. Copy the buffer into the mbuf chain. The
 467  *              size of the buffer is indicated by the number preceding 'c'.
 468  *
 469  *      w       Word (16bit value). Store the word or the number of words
 470  *              specified into the the mbuf chain. A format string like this
 471  *              "2w" would require 2 words to be passed in.
 472  *
 473  *      l       Long (32bit value). Store the long or the number of longs
 474  *              specified into the the mbuf chain. A format string like this
 475  *              "2l" would require 2 longs to be passed in.
 476  *
 477  *      q       Quad (64bit value). Store the quad or the number of quads
 478  *              specified into the the mbuf chain. A format string like this
 479  *              "2q" would require 2 quads to be passed in.
 480  *
 481  *      L       Pointer to a string. Store the string passed in into the mbuf
 482  *              chain preceded with a tag value of '2'.
 483  *
 484  *      S       Pointer to a string. Store the string passed in into the mbuf
 485  *              chain preceded with a tag value of '4'. Applied a unicode
 486  *              conversion is appropriate.
 487  *
 488  *      A       Same as 'S'
 489  *
 490  *      P       Pointer to a string. Store the string passed in into the mbuf
 491  *              chain preceded with a tag value of '5'. Applied a unicode
 492  *              conversion is appropriate.
 493  *
 494  *      u       Pointer to a string. Store the string passed in into the mbuf
 495  *              chain. Applied a unicode conversion is appropriate.
 496  *
 497  *      s       Pointer to a string. Store the string passed in into the mbuf
 498  *              chain.
 499  *
 500  *      Y       Date/Time.  Store the Date/Time or the number of Date/Time(s)
 501  *              specified into the the mbuf chain. A format string like this
 502  *              "2Y" would require 2 Date/Time values. The Date/Time is
 503  *              converted to DOS before storing.
 504  *
 505  *      y       Same as 'Y'. The order of Date and Time is reversed.
 506  *
 507  *      ,       Character. Store the character or number of character specified
 508  *              into the mbuf chain.  A format string like this "2c" would
 509  *              require 2 characters to be passed in. A unicode conversion is
 510  *              applied if appropriate.
 511  *
 512  *      .       Same as '`' without unicode conversion.
 513  *
 514  *      U       Align the offset of the mbuf chain on a 16bit boundary.
 515  */
 516 int
 517 smb_mbc_vencodef(mbuf_chain_t *mbc, const char *fmt, va_list ap)
 518 {
 519         char            *charp;
 520         uint8_t         *cvalp;
 521         timestruc_t     *tvp;
 522         smb_vdb_t       *vdp;
 523         smb_request_t   *sr = NULL;
 524         uint64_t        llval;
 525         int64_t         nt_time;
 526         uint32_t        lval;
 527         uint_t          tag;
 528         int             unicode = 0;
 529         int             repc;
 530         boolean_t       repc_specified;
 531         uint16_t        wval;
 532         uint8_t         cval;
 533         uint8_t         c;
 534 
 535         while ((c = *fmt++) != 0) {
 536                 repc_specified = B_FALSE;
 537                 repc = 1;
 538 
 539                 if ('0' <= c && c <= '9') {
 540                         repc = 0;
 541                         do {
 542                                 repc = repc * 10 + c - '0';
 543                                 c = *fmt++;
 544                         } while ('0' <= c && c <= '9');
 545                         repc_specified = B_TRUE;
 546                 } else if (c == '#') {
 547                         repc = va_arg(ap, int);
 548                         c = *fmt++;
 549                         repc_specified = B_TRUE;
 550                 }
 551 
 552                 switch (c) {
 553                 case '%':
 554                         sr = va_arg(ap, struct smb_request *);
 555                         if (sr->session->dialect >= SMB_VERS_2_BASE) {
 556                                 unicode = 1;
 557                                 break;
 558                         }
 559                         unicode = sr->smb_flg2 & SMB_FLAGS2_UNICODE;
 560                         break;
 561 
 562                 case 'C':       /* Mbuf_chain */
 563                         if (mbc_marshal_put_mbuf_chain(mbc,
 564                             va_arg(ap, mbuf_chain_t *)) != 0)
 565                                 return (DECODE_NO_MORE_DATA);
 566                         break;
 567 
 568                 case 'D':
 569                         vdp = va_arg(ap, struct vardata_block *);
 570 
 571                         if (mbc_marshal_put_char(mbc, 1) != 0)
 572                                 return (DECODE_NO_MORE_DATA);
 573                         if (mbc_marshal_put_short(mbc, vdp->vdb_len) != 0)
 574                                 return (DECODE_NO_MORE_DATA);
 575                         if (mbc_marshal_put_uio(mbc, &vdp->vdb_uio) != 0)
 576                                 return (DECODE_NO_MORE_DATA);
 577                         break;
 578 
 579                 case 'M':
 580                         /* 0xFF S M B */
 581                         if (mbc_marshal_put_long(mbc, 0x424D53FF))
 582                                 return (DECODE_NO_MORE_DATA);
 583                         break;
 584 
 585                 case 'N':
 586                         /* 0xFE S M B */
 587                         if (mbc_marshal_put_long(mbc, 0x424D53FE))
 588                                 return (DECODE_NO_MORE_DATA);
 589                         break;
 590 
 591                 case 'T':
 592                         tvp = va_arg(ap, timestruc_t *);
 593                         nt_time = smb_time_unix_to_nt(tvp);
 594                         if (mbc_marshal_put_long_long(mbc, nt_time) != 0)
 595                                 return (DECODE_NO_MORE_DATA);
 596                         break;
 597 
 598                 case 'V':
 599                         vdp = va_arg(ap, struct vardata_block *);
 600 
 601                         if (mbc_marshal_put_char(mbc, 5) != 0)
 602                                 return (DECODE_NO_MORE_DATA);
 603                         if (mbc_marshal_put_short(mbc, vdp->vdb_len) != 0)
 604                                 return (DECODE_NO_MORE_DATA);
 605                         if (mbc_marshal_put_uio(mbc, &vdp->vdb_uio) != 0)
 606                                 return (DECODE_NO_MORE_DATA);
 607                         break;
 608 
 609                 case 'b':
 610                         while (repc-- > 0) {
 611                                 cval = va_arg(ap, int);
 612                                 if (mbc_marshal_put_char(mbc, cval) != 0)
 613                                         return (DECODE_NO_MORE_DATA);
 614                         }
 615                         break;
 616 
 617                 case 'm':       /* struct_mbuf */
 618                         if (mbc_marshal_put_mbufs(mbc,
 619                             va_arg(ap, mbuf_t *)) != 0)
 620                                 return (DECODE_NO_MORE_DATA);
 621                         break;
 622 
 623                 case 'c':
 624                         cvalp = va_arg(ap, uint8_t *);
 625                         while (repc-- > 0) {
 626                                 if (mbc_marshal_put_char(mbc,
 627                                     *cvalp++) != 0)
 628                                         return (DECODE_NO_MORE_DATA);
 629                         }
 630                         break;
 631 
 632                 case 'w':
 633                         while (repc-- > 0) {
 634                                 wval = va_arg(ap, int);
 635                                 if (mbc_marshal_put_short(mbc, wval) != 0)
 636                                         return (DECODE_NO_MORE_DATA);
 637                         }
 638                         break;
 639 
 640                 case 'l':
 641                         while (repc-- > 0) {
 642                                 lval = va_arg(ap, uint32_t);
 643                                 if (mbc_marshal_put_long(mbc, lval) != 0)
 644                                         return (DECODE_NO_MORE_DATA);
 645                         }
 646                         break;
 647 
 648                 case 'q':
 649                         while (repc-- > 0) {
 650                                 llval = va_arg(ap, uint64_t);
 651                                 if (mbc_marshal_put_long_long(mbc, llval) != 0)
 652                                         return (DECODE_NO_MORE_DATA);
 653                         }
 654                         break;
 655 
 656 
 657                 case 'L':
 658                         tag = 2;
 659                         goto oem_conversion;
 660 
 661                 case 'S':
 662                 case 'A':
 663                         tag = 4;
 664                         goto tagged_str;
 665 
 666                 case 'P':
 667                         tag = 3;
 668                         goto tagged_str;
 669 
 670                 tagged_str:
 671                         if (mbc_marshal_put_char(mbc, tag) != 0)
 672                                 return (DECODE_NO_MORE_DATA);
 673                         /* FALLTHROUGH */
 674 
 675                 case 'u':       /* Convert from unicode if flags are set */
 676                         if (unicode)
 677                                 goto unicode_translation;
 678                         /* FALLTHROUGH */
 679 
 680                 case 's':       /* put OEM string */
 681 oem_conversion:
 682                         charp = va_arg(ap, char *);
 683                         if (!repc_specified)
 684                                 repc = 0;
 685                         if (mbc_marshal_put_oem_string(mbc,
 686                             charp, repc) != 0)
 687                                 return (DECODE_NO_MORE_DATA);
 688                         break;
 689 
 690                 case 'U':       /* put UTF-16 string */
 691 unicode_translation:
 692                         charp = va_arg(ap, char *);
 693                         if (!repc_specified)
 694                                 repc = 0;
 695                         if (mbc_marshal_put_unicode_string(mbc,
 696                             charp, repc) != 0)
 697                                 return (DECODE_NO_MORE_DATA);
 698                         break;
 699 
 700                 case 'Y':               /* int32_t, encode dos date/time */
 701                         while (repc-- > 0) {
 702                                 uint16_t        d, t;
 703 
 704                                 lval = va_arg(ap, uint32_t);
 705                                 smb_time_unix_to_dos(lval,
 706                                     (short *)&d, (short *)&t);
 707                                 if (mbc_marshal_put_short(mbc, t) != 0)
 708                                         return (DECODE_NO_MORE_DATA);
 709                                 if (mbc_marshal_put_short(mbc, d) != 0)
 710                                         return (DECODE_NO_MORE_DATA);
 711                         }
 712                         break;
 713 
 714                 case 'y':               /* int32_t, encode dos date/time */
 715                         while (repc-- > 0) {
 716                                 uint16_t        d, t;
 717 
 718                                 lval = va_arg(ap, uint32_t);
 719                                 smb_time_unix_to_dos(lval,
 720                                     (short *)&d, (short *)&t);
 721                                 if (mbc_marshal_put_short(mbc, d) != 0)
 722                                         return (DECODE_NO_MORE_DATA);
 723                                 if (mbc_marshal_put_short(mbc, t) != 0)
 724                                         return (DECODE_NO_MORE_DATA);
 725                         }
 726                         break;
 727 
 728                 case ',':
 729                         if (unicode)
 730                                 repc *= 2;
 731                         /* FALLTHROUGH */
 732 
 733                 case '.':
 734                         while (repc-- > 0)
 735                                 if (mbc_marshal_put_char(mbc, 0) != 0)
 736                                         return (DECODE_NO_MORE_DATA);
 737                         break;
 738 
 739                 default:
 740                         ASSERT(0);
 741                         return (-1);
 742                 }
 743         }
 744         return (0);
 745 }
 746 
 747 /*
 748  * smb_mbc_encodef
 749  *
 750  * This function builds a stream of bytes in the mbc chain passed in under the
 751  * control of the format fmt.
 752  *
 753  * (for a description of the format string see smb_mbc_vencodef()).
 754  */
 755 int
 756 smb_mbc_encodef(mbuf_chain_t *mbc, const char *fmt, ...)
 757 {
 758         int     rc;
 759         va_list ap;
 760 
 761         va_start(ap, fmt);
 762         rc = smb_mbc_vencodef(mbc, fmt, ap);
 763         va_end(ap);
 764         return (rc);
 765 }
 766 
 767 /*
 768  * smb_mbc_poke
 769  *
 770  * This function writes a stream of bytes in the mbc passed in at the specified
 771  * offset under the control of the format fmt. The offset of the chain passed in
 772  * is not modified.
 773  *
 774  * (for a description of the format string see smb_mbc_vencodef()).
 775  */
 776 int
 777 smb_mbc_poke(mbuf_chain_t *mbc, int offset, const char *fmt, ...)
 778 {
 779         int             len, rc;
 780         mbuf_chain_t    tmp;
 781         va_list         ap;
 782 
 783         if ((len = mbc->max_bytes - offset) < 0)
 784                 return (DECODE_NO_MORE_DATA);
 785         rc = MBC_SHADOW_CHAIN(&tmp, mbc, offset, len);
 786         if (rc)
 787                 return (DECODE_NO_MORE_DATA);
 788 
 789         va_start(ap, fmt);
 790         rc = smb_mbc_vencodef(&tmp, fmt, ap);
 791         va_end(ap);
 792 
 793         return (rc);
 794 }
 795 
 796 /*
 797  * Copy data from the src mbuf chain to the dst mbuf chain,
 798  * at the given offset in the src and current offset in dst,
 799  * for copy_len bytes.  Does NOT update src->chain_offset.
 800  */
 801 int
 802 smb_mbc_copy(mbuf_chain_t *dst_mbc, const mbuf_chain_t *src_mbc,
 803         int copy_offset, int copy_len)
 804 {
 805         mbuf_t  *src_m;
 806         int offset, len;
 807         int rc;
 808 
 809         if (copy_len <= 0)
 810                 return (0);
 811         if (copy_offset < 0)
 812                 return (EINVAL);
 813         if ((copy_offset + copy_len) > src_mbc->max_bytes)
 814                 return (EMSGSIZE);
 815 
 816         /*
 817          * Advance to the src mbuf where we start copying.
 818          */
 819         offset = copy_offset;
 820         src_m = src_mbc->chain;
 821         while (src_m && offset >= src_m->m_len) {
 822                 offset -= src_m->m_len;
 823                 src_m = src_m->m_next;
 824         }
 825         if (src_m == NULL)
 826                 return (EFAULT);
 827 
 828         /*
 829          * Copy the first part, which may start somewhere past
 830          * the beginning of the current mbuf.
 831          */
 832         len = src_m->m_len - offset;
 833         if (len > copy_len)
 834                 len = copy_len;
 835         rc = smb_mbc_put_mem(dst_mbc, src_m->m_data + offset, len);
 836         if (rc != 0)
 837                 return (rc);
 838         copy_len -= len;
 839 
 840         /*
 841          * Copy remaining mbufs...
 842          */
 843         while (copy_len > 0) {
 844                 src_m = src_m->m_next;
 845                 if (src_m == NULL)
 846                         break;
 847                 len = src_m->m_len;
 848                 if (len > copy_len)
 849                         len = copy_len;
 850                 rc = smb_mbc_put_mem(dst_mbc, src_m->m_data, len);
 851                 copy_len -= len;
 852         }
 853 
 854         return (0);
 855 }
 856 
 857 /*
 858  * Copy data from the passed memory buffer into the mbuf chain
 859  * at the current offset.
 860  */
 861 int
 862 smb_mbc_put_mem(mbuf_chain_t *mbc, void *vmem, int mem_len)
 863 {
 864         caddr_t mem = vmem;
 865         mbuf_t  *m;
 866         int32_t offset, tlen;
 867         int rc;
 868 
 869         if (mem_len <= 0)
 870                 return (0);
 871 
 872         if ((rc = mbc_marshal_make_room(mbc, mem_len)) != 0)
 873                 return (rc);
 874 
 875         /*
 876          * Advance to the dst mbuf where we start copying.
 877          * Allocations were done by _make_room().
 878          */
 879         offset = mbc->chain_offset;
 880         m = mbc->chain;
 881         while (offset >= m->m_len) {
 882                 ASSERT(m->m_len > 0);
 883                 offset -= m->m_len;
 884                 m = m->m_next;
 885         }
 886 
 887         /*
 888          * Copy the first part, which may start somewhere past
 889          * the beginning of the current mbuf.
 890          */
 891         tlen = m->m_len - offset;
 892         if (tlen > mem_len)
 893                 tlen = mem_len;
 894         bcopy(mem, m->m_data + offset, tlen);
 895         mbc->chain_offset += tlen;
 896         mem += tlen;
 897         mem_len -= tlen;
 898 
 899         /*
 900          * Copy remaining mem into mbufs.  These all start
 901          * at the beginning of each mbuf, and the last may
 902          * end somewhere short of m_len.
 903          */
 904         while (mem_len > 0) {
 905                 m = m->m_next;
 906                 tlen = m->m_len;
 907                 if (tlen > mem_len)
 908                         tlen = mem_len;
 909                 bcopy(mem, m->m_data, tlen);
 910                 mbc->chain_offset += tlen;
 911                 mem += tlen;
 912                 mem_len -= tlen;
 913         }
 914 
 915         return (0);
 916 }
 917 
 918 /*
 919  * Put padding sufficient to align to A, where
 920  * A is some power of 2 greater than zero.
 921  */
 922 int
 923 smb_mbc_put_align(mbuf_chain_t *mbc, int align)
 924 {
 925         int mask = align - 1;
 926         int padsz;
 927 
 928         ASSERT(align > 0 && (align & mask) == 0);
 929         if ((mbc->chain_offset & mask) == 0)
 930                 return (0);
 931         padsz = align - (mbc->chain_offset & mask);
 932         return (smb_mbc_encodef(mbc, "#.", padsz));
 933 }
 934 
 935 /*
 936  * Put data into mbuf chain allocating as needed.
 937  * Adds room to end of mbuf chain if needed.
 938  */
 939 static int
 940 mbc_marshal_make_room(mbuf_chain_t *mbc, int32_t bytes_needed)
 941 {
 942         mbuf_t  *m;
 943         mbuf_t  *l;
 944         int32_t bytes_available;
 945 
 946         bytes_needed += mbc->chain_offset;
 947         if (bytes_needed > mbc->max_bytes)
 948                 return (EMSGSIZE);
 949 
 950         if ((m = mbc->chain) == 0) {
 951                 MGET(m, M_WAIT, MT_DATA);
 952                 m->m_len = 0;
 953                 MCLGET(m, M_WAIT);
 954                 mbc->chain = m;
 955                 /* xxxx */
 956                 /* ^    */
 957         }
 958 
 959         /* ---- ----- --xx ---xxx */
 960         /* ^                      */
 961 
 962         l = 0;
 963         while ((m != 0) && (bytes_needed >= m->m_len)) {
 964                 l = m;
 965                 bytes_needed -= m->m_len;
 966                 m = m->m_next;
 967         }
 968 
 969         if ((bytes_needed == 0) || (m != 0)) {
 970                 /* We have enough room already */
 971                 return (0);
 972         }
 973 
 974         /* ---- ----- --xx ---xxx */
 975         /*                       ^ */
 976         /* Back up to start of last mbuf */
 977         m = l;
 978         bytes_needed += m->m_len;
 979 
 980         /* ---- ----- --xx ---xxx */
 981         /*                 ^      */
 982 
 983         bytes_available = (m->m_flags & M_EXT) ?
 984             m->m_ext.ext_size : MLEN;
 985 
 986         /* ---- ----- --xx ---xxx */
 987         /*                 ^      */
 988         while ((bytes_needed != 0) && (bytes_needed > bytes_available)) {
 989                 m->m_len = bytes_available;
 990                 bytes_needed -= m->m_len;
 991                 /* ---- ----- --xx ------ */
 992                 /*                 ^      */
 993 
 994                 MGET(m->m_next, M_WAIT, MT_DATA);
 995                 m = m->m_next;
 996                 m->m_len = 0;
 997                 MCLGET(m, M_WAIT);
 998 
 999                 ASSERT((m->m_flags & M_EXT) != 0);
1000                 bytes_available = m->m_ext.ext_size;
1001 
1002                 /* ---- ----- --xx ------ xxxx */
1003                 /*                        ^    */
1004         }
1005 
1006         /* ---- ----- --xx ------ xxxx */
1007         /*                        ^    */
1008         /* Expand last tail as needed */
1009         if (m->m_len <= bytes_needed) {
1010                 m->m_len = bytes_needed;
1011                 /* ---- ----- --xx ------ --xx */
1012                 /*                         ^   */
1013         }
1014 
1015         return (0);
1016 }
1017 
1018 static void
1019 mbc_marshal_store_byte(mbuf_chain_t *mbc, uint8_t data)
1020 {
1021         mbuf_t  *m = mbc->chain;
1022         int32_t cur_offset = mbc->chain_offset;
1023 
1024         /*
1025          * Scan forward looking for the last data currently in chain.
1026          */
1027         while (cur_offset >= m->m_len) {
1028                 cur_offset -= m->m_len;
1029                 m = m->m_next;
1030         }
1031         ((char *)m->m_data)[cur_offset] = data;
1032         mbc->chain_offset++;
1033 }
1034 
1035 static int
1036 mbc_marshal_put_char(mbuf_chain_t *mbc, uint8_t data)
1037 {
1038         if (mbc_marshal_make_room(mbc, sizeof (char)) != 0)
1039                 return (DECODE_NO_MORE_DATA);
1040         mbc_marshal_store_byte(mbc, data);
1041         return (0);
1042 }
1043 
1044 static int
1045 mbc_marshal_put_short(mbuf_chain_t *mbc, uint16_t data)
1046 {
1047         if (mbc_marshal_make_room(mbc, sizeof (short)))
1048                 return (DECODE_NO_MORE_DATA);
1049         mbc_marshal_store_byte(mbc, data);
1050         mbc_marshal_store_byte(mbc, data >> 8);
1051         return (0);
1052 }
1053 
1054 static int
1055 mbc_marshal_put_long(mbuf_chain_t *mbc, uint32_t data)
1056 {
1057         if (mbc_marshal_make_room(mbc, sizeof (int32_t)))
1058                 return (DECODE_NO_MORE_DATA);
1059         mbc_marshal_store_byte(mbc, data);
1060         mbc_marshal_store_byte(mbc, data >> 8);
1061         mbc_marshal_store_byte(mbc, data >> 16);
1062         mbc_marshal_store_byte(mbc, data >> 24);
1063         return (0);
1064 }
1065 
1066 static int
1067 mbc_marshal_put_long_long(mbuf_chain_t *mbc, uint64_t data)
1068 {
1069         if (mbc_marshal_make_room(mbc, sizeof (int64_t)))
1070                 return (DECODE_NO_MORE_DATA);
1071 
1072         mbc_marshal_store_byte(mbc, data);
1073         mbc_marshal_store_byte(mbc, data >> 8);
1074         mbc_marshal_store_byte(mbc, data >> 16);
1075         mbc_marshal_store_byte(mbc, data >> 24);
1076         mbc_marshal_store_byte(mbc, data >> 32);
1077         mbc_marshal_store_byte(mbc, data >> 40);
1078         mbc_marshal_store_byte(mbc, data >> 48);
1079         mbc_marshal_store_byte(mbc, data >> 56);
1080         return (0);
1081 }
1082 
1083 /*
1084  * Marshal a UTF-8 string (str) into mbc, converting to OEM codeset.
1085  * Also write a null unless the repc count limits the length we put.
1086  * When (repc > 0) the length we marshal must be exactly repc, and
1087  * truncate or pad the mbc data as necessary.
1088  * See also: msgbuf_put_oem_string
1089  */
1090 static int
1091 mbc_marshal_put_oem_string(mbuf_chain_t *mbc, char *mbs, int repc)
1092 {
1093         uint8_t         *oembuf = NULL;
1094         uint8_t         *s;
1095         int             oemlen;
1096         int             rlen;
1097         int             rc;
1098 
1099         /*
1100          * Compute length of converted OEM string,
1101          * NOT including null terminator
1102          */
1103         if ((oemlen = smb_sbequiv_strlen(mbs)) == -1)
1104                 return (DECODE_NO_MORE_DATA);
1105 
1106         /*
1107          * If repc not specified, put whole string + NULL,
1108          * otherwise will truncate or pad as needed.
1109          */
1110         if (repc <= 0)
1111                 repc = oemlen + 1;
1112         if (mbc_marshal_make_room(mbc, repc))
1113                 return (DECODE_NO_MORE_DATA);
1114 
1115         /*
1116          * Convert into a temporary buffer
1117          * Free oembuf before return.
1118          */
1119         oembuf = smb_mem_zalloc(oemlen + 1);
1120         ASSERT(oembuf != NULL);
1121         rlen = smb_mbstooem(oembuf, mbs, oemlen);
1122         if (rlen < 0) {
1123                 rc = DECODE_NO_MORE_DATA;
1124                 goto out;
1125         }
1126         if (rlen > oemlen)
1127                 rlen = oemlen;
1128         oembuf[rlen] = '\0';
1129 
1130         /*
1131          * Copy the converted string into the message,
1132          * truncated or paded as required.
1133          */
1134         s = oembuf;
1135         while (repc > 0) {
1136                 mbc_marshal_store_byte(mbc, *s);
1137                 if (*s != '\0')
1138                         s++;
1139                 repc--;
1140         }
1141         rc = 0;
1142 
1143 out:
1144         if (oembuf != NULL)
1145                 smb_mem_free(oembuf);
1146         return (rc);
1147 }
1148 
1149 /*
1150  * Marshal a UTF-8 string (str) into mbc, converting to UTF-16.
1151  * Also write a null unless the repc count limits the length.
1152  * When (repc > 0) the length we marshal must be exactly repc,
1153  * and truncate or pad the mbc data as necessary.
1154  * See also: msgbuf_put_unicode_string
1155  */
1156 static int
1157 mbc_marshal_put_unicode_string(mbuf_chain_t *mbc, char *mbs, int repc)
1158 {
1159         smb_wchar_t     *wcsbuf = NULL;
1160         smb_wchar_t     *wp;
1161         size_t          wcslen, wcsbytes;
1162         size_t          rlen;
1163         int             rc;
1164 
1165         /* align to word boundary */
1166         if (mbc->chain_offset & 1) {
1167                 if (mbc_marshal_make_room(mbc, 1))
1168                         return (DECODE_NO_MORE_DATA);
1169                 mbc_marshal_store_byte(mbc, 0);
1170         }
1171 
1172         /*
1173          * Compute length of converted UTF-16 string,
1174          * NOT including null terminator (in bytes).
1175          */
1176         wcsbytes = smb_wcequiv_strlen(mbs);
1177         if (wcsbytes == (size_t)-1)
1178                 return (DECODE_NO_MORE_DATA);
1179 
1180         /*
1181          * If repc not specified, put whole string + NULL,
1182          * otherwise will truncate or pad as needed.
1183          */
1184         if (repc <= 0)
1185                 repc = wcsbytes + 2;
1186         if (mbc_marshal_make_room(mbc, repc))
1187                 return (DECODE_NO_MORE_DATA);
1188 
1189         /*
1190          * Convert into a temporary buffer
1191          * Free wcsbuf before return.
1192          */
1193         wcslen = wcsbytes / 2;
1194         wcsbuf = smb_mem_zalloc(wcsbytes + 2);
1195         ASSERT(wcsbuf != NULL);
1196         rlen = smb_mbstowcs(wcsbuf, mbs, wcslen);
1197         if (rlen == (size_t)-1) {
1198                 rc = DECODE_NO_MORE_DATA;
1199                 goto out;
1200         }
1201         if (rlen > wcslen)
1202                 rlen = wcslen;
1203         wcsbuf[rlen] = 0;
1204 
1205         /*
1206          * Copy the converted string into the message,
1207          * truncated or paded as required.  Preserve
1208          * little-endian order while copying.
1209          */
1210         wp = wcsbuf;
1211         while (repc > 1) {
1212                 smb_wchar_t wchar = LE_IN16(wp);
1213                 mbc_marshal_store_byte(mbc, wchar);
1214                 mbc_marshal_store_byte(mbc, wchar >> 8);
1215                 if (wchar != 0)
1216                         wp++;
1217                 repc -= sizeof (smb_wchar_t);
1218         }
1219         if (repc > 0)
1220                 mbc_marshal_store_byte(mbc, 0);
1221 
1222         rc = 0;
1223 out:
1224         if (wcsbuf != NULL)
1225                 smb_mem_free(wcsbuf);
1226         return (rc);
1227 }
1228 
1229 static int /*ARGSUSED*/
1230 uiorefnoop(caddr_t p, int size, int adj)
1231 {
1232         return (0);
1233 }
1234 
1235 static int
1236 mbc_marshal_put_uio(mbuf_chain_t *mbc, struct uio *uio)
1237 {
1238         mbuf_t          **t;
1239         mbuf_t          *m = NULL;
1240         struct iovec    *iov = uio->uio_iov;
1241         int32_t         i, iov_cnt = uio->uio_iovcnt;
1242 
1243         iov = uio->uio_iov;
1244         t = &mbc->chain;
1245         for (i = 0; i < iov_cnt; i++) {
1246                 MGET(m, M_WAIT, MT_DATA);
1247                 m->m_ext.ext_buf = iov->iov_base;
1248                 m->m_ext.ext_ref = uiorefnoop;
1249                 m->m_data = m->m_ext.ext_buf;
1250                 m->m_flags |= M_EXT;
1251                 m->m_len = m->m_ext.ext_size = iov->iov_len;
1252                 mbc->max_bytes += m->m_len;
1253                 m->m_next = 0;
1254                 *t = m;
1255                 t = &m->m_next;
1256                 iov++;
1257         }
1258         return (0);
1259 }
1260 
1261 static int
1262 mbc_marshal_put_mbufs(mbuf_chain_t *mbc, mbuf_t *m)
1263 {
1264         mbuf_t  *mt;
1265         mbuf_t  **t;
1266         int     bytes;
1267 
1268         if (m != NULL) {
1269                 mt = m;
1270                 bytes = mt->m_len;
1271                 while (mt->m_next != 0) {
1272                         mt = mt->m_next;
1273                         bytes += mt->m_len;
1274                 }
1275                 if (bytes != 0) {
1276                         t = &mbc->chain;
1277                         while (*t != 0) {
1278                                 bytes += (*t)->m_len;
1279                                 t = &(*t)->m_next;
1280                         }
1281                         *t = m;
1282                         mbc->chain_offset = bytes;
1283                 } else {
1284                         m_freem(m);
1285                 }
1286         }
1287         return (0);
1288 }
1289 
1290 static int
1291 mbc_marshal_put_mbuf_chain(mbuf_chain_t *mbc, mbuf_chain_t *nmbc)
1292 {
1293         if (nmbc->chain != 0) {
1294                 if (mbc_marshal_put_mbufs(mbc, nmbc->chain))
1295                         return (DECODE_NO_MORE_DATA);
1296                 MBC_SETUP(nmbc, nmbc->max_bytes);
1297         }
1298         return (0);
1299 }
1300 
1301 static uint8_t
1302 mbc_marshal_fetch_byte(mbuf_chain_t *mbc)
1303 {
1304         uint8_t data;
1305         mbuf_t  *m = mbc->chain;
1306         int32_t offset = mbc->chain_offset;
1307 
1308         while (offset >= m->m_len) {
1309                 offset -= m->m_len;
1310                 m = m->m_next;
1311         }
1312         data = ((uint8_t *)m->m_data)[offset];
1313         mbc->chain_offset++;
1314         return (data);
1315 }
1316 
1317 static int
1318 mbc_marshal_get_char(mbuf_chain_t *mbc, uint8_t *data)
1319 {
1320         if (MBC_ROOM_FOR(mbc, sizeof (char)) == 0) {
1321                 /* Data will never be available */
1322                 return (DECODE_NO_MORE_DATA);
1323         }
1324         *data = mbc_marshal_fetch_byte(mbc);
1325         return (0);
1326 }
1327 
1328 static int
1329 mbc_marshal_get_short(mbuf_chain_t *mbc, uint16_t *data)
1330 {
1331         uint16_t        tmp;
1332         mbuf_t          *m = mbc->chain;
1333         int32_t         offset = mbc->chain_offset;
1334 
1335         if (MBC_ROOM_FOR(mbc, sizeof (short)) == 0) {
1336                 /* Data will never be available */
1337                 return (DECODE_NO_MORE_DATA);
1338         }
1339 
1340         while (offset >= m->m_len) {
1341                 offset -= m->m_len;
1342                 m = m->m_next;
1343         }
1344         if ((m->m_len - offset) >= sizeof (short)) {
1345                 *data = LE_IN16(m->m_data + offset);
1346                 mbc->chain_offset += sizeof (short);
1347         } else {
1348                 tmp = (uint16_t)mbc_marshal_fetch_byte(mbc);
1349                 tmp |= ((uint16_t)mbc_marshal_fetch_byte(mbc)) << 8;
1350                 *data = tmp;
1351         }
1352         return (0);
1353 }
1354 
1355 static int
1356 mbc_marshal_get_long(mbuf_chain_t *mbc, uint32_t *data)
1357 {
1358         uint32_t        tmp;
1359         mbuf_t          *m = mbc->chain;
1360         int32_t         offset = mbc->chain_offset;
1361 
1362         if (MBC_ROOM_FOR(mbc, sizeof (int32_t)) == 0) {
1363                 /* Data will never be available */
1364                 return (DECODE_NO_MORE_DATA);
1365         }
1366         while (offset >= m->m_len) {
1367                 offset -= m->m_len;
1368                 m = m->m_next;
1369         }
1370         if ((m->m_len - offset) >= sizeof (int32_t)) {
1371                 *data = LE_IN32(m->m_data + offset);
1372                 mbc->chain_offset += sizeof (int32_t);
1373         } else {
1374                 tmp = (uint32_t)mbc_marshal_fetch_byte(mbc);
1375                 tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 8;
1376                 tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 16;
1377                 tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 24;
1378                 *data = tmp;
1379         }
1380         return (0);
1381 }
1382 
1383 static uint64_t
1384 qswap(uint64_t ll)
1385 {
1386         uint64_t v;
1387 
1388         v = ll >> 32;
1389         v |= ll << 32;
1390 
1391         return (v);
1392 }
1393 
1394 static int
1395 mbc_marshal_get_odd_long_long(mbuf_chain_t *mbc, uint64_t *data)
1396 {
1397         uint64_t        tmp;
1398         mbuf_t          *m = mbc->chain;
1399         int32_t         offset = mbc->chain_offset;
1400 
1401         if (MBC_ROOM_FOR(mbc, sizeof (int64_t)) == 0) {
1402                 /* Data will never be available */
1403                 return (DECODE_NO_MORE_DATA);
1404         }
1405         while (offset >= m->m_len) {
1406                 offset -= m->m_len;
1407                 m = m->m_next;
1408         }
1409 
1410         if ((m->m_len - offset) >= sizeof (int64_t)) {
1411                 *data = qswap(LE_IN64(m->m_data + offset));
1412                 mbc->chain_offset += sizeof (int64_t);
1413         } else {
1414                 tmp = (uint64_t)mbc_marshal_fetch_byte(mbc) << 32;
1415                 tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 40;
1416                 tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 48;
1417                 tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 56;
1418                 tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc);
1419                 tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 8;
1420                 tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 16;
1421                 tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 24;
1422 
1423                 *(uint64_t *)data = tmp;
1424         }
1425         return (0);
1426 }
1427 
1428 static int
1429 mbc_marshal_get_long_long(mbuf_chain_t *mbc, uint64_t *data)
1430 {
1431         uint64_t        tmp;
1432         mbuf_t          *m = mbc->chain;
1433         int32_t         offset = mbc->chain_offset;
1434 
1435         if (MBC_ROOM_FOR(mbc, sizeof (int64_t)) == 0) {
1436                 /* Data will never be available */
1437                 return (DECODE_NO_MORE_DATA);
1438         }
1439         while (offset >= m->m_len) {
1440                 offset -= m->m_len;
1441                 m = m->m_next;
1442         }
1443         if ((m->m_len - offset) >= sizeof (int64_t)) {
1444                 *data = LE_IN64(m->m_data + offset);
1445                 mbc->chain_offset += sizeof (int64_t);
1446         } else {
1447                 tmp = (uint32_t)mbc_marshal_fetch_byte(mbc);
1448                 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 8;
1449                 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 16;
1450                 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 24;
1451                 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 32;
1452                 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 40;
1453                 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 48;
1454                 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 56;
1455                 *(uint64_t *)data = tmp;
1456         }
1457         return (0);
1458 }
1459 
1460 /*
1461  * mbc_marshal_get_oem_string
1462  *
1463  * Decode an OEM string, returning its UTF-8 form in strpp,
1464  * allocated using smb_srm_zalloc (automatically freed).
1465  * If max_bytes != 0, consume at most max_bytes of the mbc.
1466  * See also: msgbuf_get_oem_string
1467  */
1468 static int
1469 mbc_marshal_get_oem_string(smb_request_t *sr,
1470     mbuf_chain_t *mbc, char **strpp, int max_bytes)
1471 {
1472         char            *mbs;
1473         uint8_t         *oembuf = NULL;
1474         int             oemlen, oemmax;
1475         int             mbsmax;
1476         int             rlen;
1477         int             rc;
1478 
1479         if (max_bytes == 0)
1480                 max_bytes = 0xffff;
1481 
1482         /*
1483          * Get the OtW data into a temporary buffer.
1484          * Free oembuf before return.
1485          */
1486         oemlen = 0;
1487         oemmax = MALLOC_QUANTUM;
1488         oembuf = smb_mem_alloc(oemmax);
1489         for (;;) {
1490                 uint8_t ch;
1491 
1492                 if (oemlen >= max_bytes)
1493                         break;
1494                 if ((oemlen + 2) >= oemmax) {
1495                         oemmax += MALLOC_QUANTUM;
1496                         oembuf = smb_mem_realloc(oembuf, oemmax);
1497                 }
1498                 if (mbc_marshal_get_char(mbc, &ch) != 0) {
1499                         rc = DECODE_NO_MORE_DATA;
1500                         goto out;
1501                 }
1502                 if (ch == 0)
1503                         break;
1504                 oembuf[oemlen++] = ch;
1505         }
1506         oembuf[oemlen] = '\0';
1507 
1508         /*
1509          * Get the buffer we'll return and convert to UTF-8.
1510          * May take as much as double the space.
1511          */
1512         mbsmax = oemlen * 2;
1513         mbs = smb_srm_zalloc(sr, mbsmax + 1);
1514         ASSERT(mbs != NULL);
1515         rlen = smb_oemtombs(mbs, oembuf, mbsmax);
1516         if (rlen < 0) {
1517                 rc = DECODE_NO_MORE_DATA;
1518                 goto out;
1519         }
1520         if (rlen > mbsmax)
1521                 rlen = mbsmax;
1522         mbs[rlen] = '\0';
1523         *strpp = mbs;
1524         rc = 0;
1525 
1526 out:
1527         if (oembuf != NULL)
1528                 smb_mem_free(oembuf);
1529         return (rc);
1530 }
1531 
1532 /*
1533  * mbc_marshal_get_unicode_string
1534  *
1535  * Decode a UTF-16 string, returning its UTF-8 form in strpp,
1536  * allocated using smb_srm_zalloc (automatically freed).
1537  * If max_bytes != 0, consume at most max_bytes of the mbc.
1538  * See also: msgbuf_get_unicode_string
1539  */
1540 static int
1541 mbc_marshal_get_unicode_string(smb_request_t *sr,
1542     mbuf_chain_t *mbc, char **strpp, int max_bytes)
1543 {
1544         char            *mbs;
1545         uint16_t        *wcsbuf = NULL;
1546         int             wcslen;         // wchar count
1547         int             wcsmax;         // byte count
1548         size_t          mbsmax;
1549         size_t          rlen;
1550         int             rc;
1551 
1552         if (max_bytes == 0)
1553                 max_bytes = 0xffff;
1554 
1555         /*
1556          * Unicode strings are always word aligned.
1557          */
1558         if (mbc->chain_offset & 1) {
1559                 if (MBC_ROOM_FOR(mbc, sizeof (char)) == 0)
1560                         return (DECODE_NO_MORE_DATA);
1561                 mbc->chain_offset++;
1562         }
1563 
1564         /*
1565          * Get the OtW data into a temporary buffer.
1566          * Free wcsbuf before return.
1567          */
1568         wcslen = 0;
1569         wcsmax = MALLOC_QUANTUM;
1570         wcsbuf = smb_mem_alloc(wcsmax);
1571         for (;;) {
1572                 uint16_t        wchar;
1573 
1574                 if ((wcslen * 2) >= max_bytes)
1575                         break;
1576                 if (((wcslen * 2) + 4) >= wcsmax) {
1577                         wcsmax += MALLOC_QUANTUM;
1578                         wcsbuf = smb_mem_realloc(wcsbuf, wcsmax);
1579                 }
1580                 if (mbc_marshal_get_short(mbc, &wchar) != 0) {
1581                         rc = DECODE_NO_MORE_DATA;
1582                         goto out;
1583                 }
1584                 if (wchar == 0)
1585                         break;
1586                 /* Keep in little-endian form. */
1587                 LE_OUT16(wcsbuf + wcslen, wchar);
1588                 wcslen++;
1589         }
1590         wcsbuf[wcslen] = 0;
1591 
1592         /*
1593          * Get the buffer we'll return and convert to UTF-8.
1594          * May take as much 4X number of wide chars.
1595          */
1596         mbsmax = wcslen * MTS_MB_CUR_MAX;
1597         mbs = smb_srm_zalloc(sr, mbsmax + 1);
1598         ASSERT(mbs != NULL);
1599         rlen = smb_wcstombs(mbs, wcsbuf, mbsmax);
1600         if (rlen == (size_t)-1) {
1601                 rc = DECODE_NO_MORE_DATA;
1602                 goto out;
1603         }
1604         if (rlen > mbsmax)
1605                 rlen = mbsmax;
1606         mbs[rlen] = '\0';
1607         *strpp = mbs;
1608         rc = 0;
1609 
1610 out:
1611         if (wcsbuf != NULL)
1612                 smb_mem_free(wcsbuf);
1613         return (rc);
1614 }
1615 
1616 static int /*ARGSUSED*/
1617 mbc_marshal_get_mbufs(mbuf_chain_t *mbc, int32_t bytes, mbuf_t **m)
1618 {
1619         *m = NULL;
1620         if (MBC_ROOM_FOR(mbc, bytes) == 0) {
1621                 /* Data will never be available */
1622                 return (DECODE_NO_MORE_DATA);
1623         }
1624         /* not yet implemented */
1625         return (-1);
1626 }
1627 
1628 static int
1629 mbc_marshal_get_mbuf_chain(mbuf_chain_t *mbc, int32_t bytes, mbuf_chain_t *nmbc)
1630 {
1631         int     rc;
1632         mbuf_t  *m;
1633 
1634         if (bytes == 0) {
1635                 /* Get all the rest */
1636                 bytes = mbc->max_bytes - mbc->chain_offset;
1637         }
1638 
1639         MBC_SETUP(nmbc, mbc->max_bytes);
1640         if ((rc = mbc_marshal_get_mbufs(mbc, bytes, &m)) != 0) {
1641                 if (m)
1642                         m_freem(m);
1643                 return (rc);
1644         }
1645         nmbc->chain = m;
1646         while (m != 0) {
1647                 bytes += m->m_len;
1648                 m = m->m_next;
1649         }
1650         nmbc->max_bytes = bytes;
1651         return (0);
1652 }
1653 
1654 static int
1655 mbc_marshal_get_uio(mbuf_chain_t *mbc, struct uio *uio)
1656 {
1657         int             i, offset;
1658         int32_t         bytes = uio->uio_resid;
1659         int32_t         remainder;
1660         struct iovec    *iov;
1661         mbuf_t          *m;
1662 
1663         /*
1664          * The residual count is tested because in the case of write requests
1665          * with no data (smbtorture RAW-WRITE test will generate that type of
1666          * request) this function is called with a residual count of zero
1667          * bytes.
1668          */
1669         if (bytes != 0) {
1670                 iov = uio->uio_iov;
1671                 uio->uio_segflg = UIO_SYSSPACE;
1672                 uio->uio_extflg = UIO_COPY_DEFAULT;
1673 
1674                 if (MBC_ROOM_FOR(mbc, bytes) == 0) {
1675                         /* Data will never be available */
1676                         return (DECODE_NO_MORE_DATA);
1677                 }
1678 
1679                 m = mbc->chain;
1680                 offset = mbc->chain_offset;
1681                 while (offset >= m->m_len) {
1682                         offset -= m->m_len;
1683                         m = m->m_next;
1684                         ASSERT((offset == 0) || (offset && m));
1685                 }
1686 
1687                 for (i = 0; (bytes > 0) && (i < uio->uio_iovcnt); i++) {
1688                         iov[i].iov_base = &m->m_data[offset];
1689                         remainder = m->m_len - offset;
1690                         if (remainder >= bytes) {
1691                                 iov[i].iov_len = bytes;
1692                                 mbc->chain_offset += bytes;
1693                                 uio->uio_iovcnt = i + 1;
1694                                 return (0);
1695                         }
1696                         iov[i].iov_len = remainder;
1697                         mbc->chain_offset += remainder;
1698                         bytes -= remainder;
1699                         m = m->m_next;
1700                         offset = 0;
1701                 }
1702                 return (DECODE_NO_MORE_DATA);
1703         }
1704         return (0);
1705 }
1706 
1707 static int
1708 mbc_marshal_get_skip(mbuf_chain_t *mbc, uint_t skip)
1709 {
1710         if (MBC_ROOM_FOR(mbc, skip) == 0)
1711                 return (DECODE_NO_MORE_DATA);
1712         mbc->chain_offset += skip;
1713         return (0);
1714 }