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