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 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  *
  25  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
  26  */
  27 
  28 /*
  29  * Msgbuf buffer management implementation. The smb_msgbuf interface is
  30  * typically used to encode or decode SMB data using sprintf/scanf
  31  * style operations. It contains special handling for the SMB header.
  32  * It can also be used for general purpose encoding and decoding.
  33  */
  34 
  35 #include <sys/types.h>
  36 #include <sys/varargs.h>
  37 #include <sys/byteorder.h>
  38 #if !defined(_KERNEL) && !defined(_FAKE_KERNEL)
  39 #include <stdlib.h>
  40 #include <syslog.h>
  41 #include <string.h>
  42 #include <strings.h>
  43 #else
  44 #include <sys/sunddi.h>
  45 #include <sys/kmem.h>
  46 #endif
  47 #include <smbsrv/string.h>
  48 #include <smbsrv/msgbuf.h>
  49 #include <smbsrv/smb.h>
  50 
  51 static int buf_decode(smb_msgbuf_t *, char *, va_list ap);
  52 static int buf_encode(smb_msgbuf_t *, char *, va_list ap);
  53 static void *smb_msgbuf_malloc(smb_msgbuf_t *, size_t);
  54 static int smb_msgbuf_chkerc(char *text, int erc);
  55 
  56 /*
  57  * Returns the offset or number of bytes used within the buffer.
  58  */
  59 size_t
  60 smb_msgbuf_used(smb_msgbuf_t *mb)
  61 {
  62         /*LINTED E_PTRDIFF_OVERFLOW*/
  63         return (mb->scan - mb->base);
  64 }
  65 
  66 /*
  67  * Returns the actual buffer size.
  68  */
  69 size_t
  70 smb_msgbuf_size(smb_msgbuf_t *mb)
  71 {
  72         return (mb->max);
  73 }
  74 
  75 uint8_t *
  76 smb_msgbuf_base(smb_msgbuf_t *mb)
  77 {
  78         return (mb->base);
  79 }
  80 
  81 /*
  82  * Ensure that the scan is aligned on a word (16-bit) boundary.
  83  */
  84 void
  85 smb_msgbuf_word_align(smb_msgbuf_t *mb)
  86 {
  87         mb->scan = (uint8_t *)((uintptr_t)(mb->scan + 1) & ~1);
  88 }
  89 
  90 /*
  91  * Ensure that the scan is aligned on a dword (32-bit) boundary.
  92  */
  93 void
  94 smb_msgbuf_dword_align(smb_msgbuf_t *mb)
  95 {
  96         mb->scan = (uint8_t *)((uintptr_t)(mb->scan + 3) & ~3);
  97 }
  98 
  99 /*
 100  * Checks whether or not the buffer has space for the amount of data
 101  * specified. Returns 1 if there is space, otherwise returns 0.
 102  */
 103 int
 104 smb_msgbuf_has_space(smb_msgbuf_t *mb, size_t size)
 105 {
 106         if (size > mb->max || (mb->scan + size) > mb->end)
 107                 return (0);
 108 
 109         return (1);
 110 }
 111 
 112 /*
 113  * Set flags the smb_msgbuf.
 114  */
 115 void
 116 smb_msgbuf_fset(smb_msgbuf_t *mb, uint32_t flags)
 117 {
 118         mb->flags |= flags;
 119 }
 120 
 121 /*
 122  * Clear flags the smb_msgbuf.
 123  */
 124 void
 125 smb_msgbuf_fclear(smb_msgbuf_t *mb, uint32_t flags)
 126 {
 127         mb->flags &= ~flags;
 128 }
 129 
 130 /*
 131  * smb_msgbuf_init
 132  *
 133  * Initialize a smb_msgbuf_t structure based on the buffer and size
 134  * specified. Both scan and base initially point to the beginning
 135  * of the buffer and end points to the limit of the buffer. As
 136  * data is added scan should be incremented to point to the next
 137  * offset at which data will be written. Max and count are set
 138  * to the actual buffer size.
 139  */
 140 void
 141 smb_msgbuf_init(smb_msgbuf_t *mb, uint8_t *buf, size_t size, uint32_t flags)
 142 {
 143         mb->scan = mb->base = buf;
 144         mb->max = mb->count = size;
 145         mb->end = &buf[size];
 146         mb->flags = flags;
 147         mb->mlist.next = 0;
 148 }
 149 
 150 
 151 /*
 152  * smb_msgbuf_term
 153  *
 154  * Destruct a smb_msgbuf_t. Free any memory hanging off the mlist.
 155  */
 156 void
 157 smb_msgbuf_term(smb_msgbuf_t *mb)
 158 {
 159         smb_msgbuf_mlist_t *item = mb->mlist.next;
 160         smb_msgbuf_mlist_t *tmp;
 161 
 162         while (item) {
 163                 tmp = item;
 164                 item = item->next;
 165 #if !defined(_KERNEL) && !defined(_FAKE_KERNEL)
 166                 free(tmp);
 167 #else
 168                 kmem_free(tmp, tmp->size);
 169 #endif
 170         }
 171 }
 172 
 173 
 174 /*
 175  * smb_msgbuf_decode
 176  *
 177  * Decode a smb_msgbuf buffer as indicated by the format string into
 178  * the variable arg list. This is similar to a scanf operation.
 179  *
 180  * On success, returns the number of bytes encoded. Otherwise
 181  * returns a -ve error code.
 182  */
 183 int
 184 smb_msgbuf_decode(smb_msgbuf_t *mb, char *fmt, ...)
 185 {
 186         int rc;
 187         uint8_t *orig_scan;
 188         va_list ap;
 189 
 190         va_start(ap, fmt);
 191         orig_scan = mb->scan;
 192         rc = buf_decode(mb, fmt, ap);
 193         va_end(ap);
 194 
 195         if (rc != SMB_MSGBUF_SUCCESS) {
 196                 (void) smb_msgbuf_chkerc("smb_msgbuf_decode", rc);
 197                 mb->scan = orig_scan;
 198                 return (rc);
 199         }
 200 
 201         /*LINTED E_PTRDIFF_OVERFLOW*/
 202         return (mb->scan - orig_scan);
 203 }
 204 
 205 
 206 /*
 207  * buf_decode
 208  *
 209  * Private decode function, where the real work of decoding the smb_msgbuf
 210  * is done. This function should only be called via smb_msgbuf_decode to
 211  * ensure correct behaviour and error handling.
 212  */
 213 static int
 214 buf_decode(smb_msgbuf_t *mb, char *fmt, va_list ap)
 215 {
 216         uint32_t ival;
 217         uint8_t c;
 218         uint8_t *bvalp;
 219         uint16_t *wvalp;
 220         uint32_t *lvalp;
 221         uint64_t *llvalp;
 222         char *cvalp;
 223         char **cvalpp;
 224         smb_wchar_t wchar;
 225         boolean_t repc_specified;
 226         int repc;
 227         int rc;
 228 
 229         while ((c = *fmt++) != 0) {
 230                 repc_specified = B_FALSE;
 231                 repc = 1;
 232 
 233                 if (c == ' ' || c == '\t')
 234                         continue;
 235 
 236                 if (c == '(') {
 237                         while (((c = *fmt++) != 0) && c != ')')
 238                                 ;
 239 
 240                         if (!c)
 241                                 return (SMB_MSGBUF_SUCCESS);
 242 
 243                         continue;
 244                 }
 245 
 246                 if ('0' <= c && c <= '9') {
 247                         repc = 0;
 248                         do {
 249                                 repc = repc * 10 + c - '0';
 250                                 c = *fmt++;
 251                         } while ('0' <= c && c <= '9');
 252                         repc_specified = B_TRUE;
 253                 } else if (c == '#') {
 254                         repc = va_arg(ap, int);
 255                         c = *fmt++;
 256                         repc_specified = B_TRUE;
 257                 }
 258 
 259                 switch (c) {
 260                 case '.':
 261                         if (smb_msgbuf_has_space(mb, repc) == 0)
 262                                 return (SMB_MSGBUF_UNDERFLOW);
 263 
 264                         mb->scan += repc;
 265                         break;
 266 
 267                 case 'c': /* get char */
 268                         if (smb_msgbuf_has_space(mb, repc) == 0)
 269                                 return (SMB_MSGBUF_UNDERFLOW);
 270 
 271                         bvalp = va_arg(ap, uint8_t *);
 272                         bcopy(mb->scan, bvalp, repc);
 273                         mb->scan += repc;
 274                         break;
 275 
 276                 case 'b': /* get byte */
 277                         if (smb_msgbuf_has_space(mb, repc) == 0)
 278                                 return (SMB_MSGBUF_UNDERFLOW);
 279 
 280                         bvalp = va_arg(ap, uint8_t *);
 281                         while (repc-- > 0) {
 282                                 *bvalp++ = *mb->scan++;
 283                         }
 284                         break;
 285 
 286                 case 'w': /* get word */
 287                         rc = smb_msgbuf_has_space(mb, repc * sizeof (uint16_t));
 288                         if (rc == 0)
 289                                 return (SMB_MSGBUF_UNDERFLOW);
 290 
 291                         wvalp = va_arg(ap, uint16_t *);
 292                         while (repc-- > 0) {
 293                                 *wvalp++ = LE_IN16(mb->scan);
 294                                 mb->scan += sizeof (uint16_t);
 295                         }
 296                         break;
 297 
 298                 case 'l': /* get long */
 299                         rc = smb_msgbuf_has_space(mb, repc * sizeof (int32_t));
 300                         if (rc == 0)
 301                                 return (SMB_MSGBUF_UNDERFLOW);
 302 
 303                         lvalp = va_arg(ap, uint32_t *);
 304                         while (repc-- > 0) {
 305                                 *lvalp++ = LE_IN32(mb->scan);
 306                                 mb->scan += sizeof (int32_t);
 307                         }
 308                         break;
 309 
 310                 case 'q': /* get quad */
 311                         rc = smb_msgbuf_has_space(mb, repc * sizeof (int64_t));
 312                         if (rc == 0)
 313                                 return (SMB_MSGBUF_UNDERFLOW);
 314 
 315                         llvalp = va_arg(ap, uint64_t *);
 316                         while (repc-- > 0) {
 317                                 *llvalp++ = LE_IN64(mb->scan);
 318                                 mb->scan += sizeof (int64_t);
 319                         }
 320                         break;
 321 
 322                 case 'u': /* Convert from unicode if flags are set */
 323                         if (mb->flags & SMB_MSGBUF_UNICODE)
 324                                 goto unicode_translation;
 325                         /*FALLTHROUGH*/
 326 
 327                 case 's': /* get string */
 328                         if (!repc_specified)
 329                                 repc = strlen((const char *)mb->scan) + 1;
 330                         if (smb_msgbuf_has_space(mb, repc) == 0)
 331                                 return (SMB_MSGBUF_UNDERFLOW);
 332                         if ((cvalp = smb_msgbuf_malloc(mb, repc * 2)) == 0)
 333                                 return (SMB_MSGBUF_UNDERFLOW);
 334                         cvalpp = va_arg(ap, char **);
 335                         *cvalpp = cvalp;
 336                         /* Translate OEM to mbs */
 337                         while (repc > 0) {
 338                                 wchar = *mb->scan++;
 339                                 repc--;
 340                                 if (wchar == 0)
 341                                         break;
 342                                 ival = smb_wctomb(cvalp, wchar);
 343                                 cvalp += ival;
 344                         }
 345                         *cvalp = '\0';
 346                         if (repc > 0)
 347                                 mb->scan += repc;
 348                         break;
 349 
 350                 case 'U': /* get unicode string */
 351 unicode_translation:
 352                         /*
 353                          * Unicode strings are always word aligned.
 354                          * The malloc'd area is larger than the
 355                          * original string because the UTF-8 chars
 356                          * may be longer than the wide-chars.
 357                          */
 358                         smb_msgbuf_word_align(mb);
 359                         if (!repc_specified) {
 360                                 /*
 361                                  * Count bytes, including the null.
 362                                  */
 363                                 uint8_t *tmp_scan = mb->scan;
 364                                 repc = 2; /* the null */
 365                                 while ((wchar = LE_IN16(tmp_scan)) != 0) {
 366                                         tmp_scan += 2;
 367                                         repc += 2;
 368                                 }
 369                         }
 370                         if (smb_msgbuf_has_space(mb, repc) == 0)
 371                                 return (SMB_MSGBUF_UNDERFLOW);
 372                         /*
 373                          * Get space for translated string
 374                          * Allocates worst-case size.
 375                          */
 376                         if ((cvalp = smb_msgbuf_malloc(mb, repc * 2)) == 0)
 377                                 return (SMB_MSGBUF_UNDERFLOW);
 378                         cvalpp = va_arg(ap, char **);
 379                         *cvalpp = cvalp;
 380                         /*
 381                          * Translate unicode to mbs, stopping after
 382                          * null or repc limit.
 383                          */
 384                         while (repc >= 2) {
 385                                 wchar = LE_IN16(mb->scan);
 386                                 mb->scan += 2;
 387                                 repc -= 2;
 388                                 if (wchar == 0)
 389                                         break;
 390                                 ival = smb_wctomb(cvalp, wchar);
 391                                 cvalp += ival;
 392                         }
 393                         *cvalp = '\0';
 394                         if (repc > 0)
 395                                 mb->scan += repc;
 396                         break;
 397 
 398                 case 'M':
 399                         if (smb_msgbuf_has_space(mb, 4) == 0)
 400                                 return (SMB_MSGBUF_UNDERFLOW);
 401 
 402                         if (mb->scan[0] != 0xFF ||
 403                             mb->scan[1] != 'S' ||
 404                             mb->scan[2] != 'M' ||
 405                             mb->scan[3] != 'B') {
 406                                 return (SMB_MSGBUF_INVALID_HEADER);
 407                         }
 408                         mb->scan += 4;
 409                         break;
 410 
 411                 default:
 412                         return (SMB_MSGBUF_INVALID_FORMAT);
 413                 }
 414         }
 415 
 416         return (SMB_MSGBUF_SUCCESS);
 417 }
 418 
 419 
 420 /*
 421  * smb_msgbuf_encode
 422  *
 423  * Encode a smb_msgbuf buffer as indicated by the format string using
 424  * the variable arg list. This is similar to a sprintf operation.
 425  *
 426  * On success, returns the number of bytes encoded. Otherwise
 427  * returns a -ve error code.
 428  */
 429 int
 430 smb_msgbuf_encode(smb_msgbuf_t *mb, char *fmt, ...)
 431 {
 432         int rc;
 433         uint8_t *orig_scan;
 434         va_list ap;
 435 
 436         va_start(ap, fmt);
 437         orig_scan = mb->scan;
 438         rc = buf_encode(mb, fmt, ap);
 439         va_end(ap);
 440 
 441         if (rc != SMB_MSGBUF_SUCCESS) {
 442                 (void) smb_msgbuf_chkerc("smb_msgbuf_encode", rc);
 443                 mb->scan = orig_scan;
 444                 return (rc);
 445         }
 446 
 447         /*LINTED E_PTRDIFF_OVERFLOW*/
 448         return (mb->scan - orig_scan);
 449 }
 450 
 451 
 452 /*
 453  * buf_encode
 454  *
 455  * Private encode function, where the real work of encoding the smb_msgbuf
 456  * is done. This function should only be called via smb_msgbuf_encode to
 457  * ensure correct behaviour and error handling.
 458  */
 459 static int
 460 buf_encode(smb_msgbuf_t *mb, char *fmt, va_list ap)
 461 {
 462         uint8_t cval;
 463         uint16_t wval;
 464         uint32_t lval;
 465         uint64_t llval;
 466         uint8_t *bvalp;
 467         char *cvalp;
 468         uint8_t c;
 469         smb_wchar_t wchar;
 470         int count;
 471         boolean_t repc_specified;
 472         int repc;
 473         int rc;
 474 
 475         while ((c = *fmt++) != 0) {
 476                 repc_specified = B_FALSE;
 477                 repc = 1;
 478 
 479                 if (c == ' ' || c == '\t')
 480                         continue;
 481 
 482                 if (c == '(') {
 483                         while (((c = *fmt++) != 0) && c != ')')
 484                                 ;
 485 
 486                         if (!c)
 487                                 return (SMB_MSGBUF_SUCCESS);
 488 
 489                         continue;
 490                 }
 491 
 492                 if ('0' <= c && c <= '9') {
 493                         repc = 0;
 494                         do {
 495                                 repc = repc * 10 + c - '0';
 496                                 c = *fmt++;
 497                         } while ('0' <= c && c <= '9');
 498                         repc_specified = B_TRUE;
 499                 } else if (c == '#') {
 500                         repc = va_arg(ap, int);
 501                         c = *fmt++;
 502                         repc_specified = B_TRUE;
 503                 }
 504 
 505                 switch (c) {
 506                 case '.':
 507                         if (smb_msgbuf_has_space(mb, repc) == 0)
 508                                 return (SMB_MSGBUF_OVERFLOW);
 509 
 510                         while (repc-- > 0)
 511                                 *mb->scan++ = 0;
 512                         break;
 513 
 514                 case 'c': /* put char */
 515                         if (smb_msgbuf_has_space(mb, repc) == 0)
 516                                 return (SMB_MSGBUF_OVERFLOW);
 517 
 518                         bvalp = va_arg(ap, uint8_t *);
 519                         bcopy(bvalp, mb->scan, repc);
 520                         mb->scan += repc;
 521                         break;
 522 
 523                 case 'b': /* put byte */
 524                         if (smb_msgbuf_has_space(mb, repc) == 0)
 525                                 return (SMB_MSGBUF_OVERFLOW);
 526 
 527                         while (repc-- > 0) {
 528                                 cval = va_arg(ap, int);
 529                                 *mb->scan++ = cval;
 530                         }
 531                         break;
 532 
 533                 case 'w': /* put word */
 534                         rc = smb_msgbuf_has_space(mb, repc * sizeof (uint16_t));
 535                         if (rc == 0)
 536                                 return (SMB_MSGBUF_OVERFLOW);
 537 
 538                         while (repc-- > 0) {
 539                                 wval = va_arg(ap, int);
 540                                 LE_OUT16(mb->scan, wval);
 541                                 mb->scan += sizeof (uint16_t);
 542                         }
 543                         break;
 544 
 545                 case 'l': /* put long */
 546                         rc = smb_msgbuf_has_space(mb, repc * sizeof (int32_t));
 547                         if (rc == 0)
 548                                 return (SMB_MSGBUF_OVERFLOW);
 549 
 550                         while (repc-- > 0) {
 551                                 lval = va_arg(ap, uint32_t);
 552                                 LE_OUT32(mb->scan, lval);
 553                                 mb->scan += sizeof (int32_t);
 554                         }
 555                         break;
 556 
 557                 case 'q': /* put quad */
 558                         rc = smb_msgbuf_has_space(mb, repc * sizeof (int64_t));
 559                         if (rc == 0)
 560                                 return (SMB_MSGBUF_OVERFLOW);
 561 
 562                         while (repc-- > 0) {
 563                                 llval = va_arg(ap, uint64_t);
 564                                 LE_OUT64(mb->scan, llval);
 565                                 mb->scan += sizeof (uint64_t);
 566                         }
 567                         break;
 568 
 569                 case 'u': /* conditional unicode */
 570                         if (mb->flags & SMB_MSGBUF_UNICODE)
 571                                 goto unicode_translation;
 572                         /* FALLTHROUGH */
 573 
 574                 case 's': /* put string */
 575                         cvalp = va_arg(ap, char *);
 576                         if (!repc_specified) {
 577                                 repc = smb_sbequiv_strlen(cvalp);
 578                                 if (repc == -1)
 579                                         return (SMB_MSGBUF_OVERFLOW);
 580                                 if (!(mb->flags & SMB_MSGBUF_NOTERM))
 581                                         repc++;
 582                         }
 583                         if (smb_msgbuf_has_space(mb, repc) == 0)
 584                                 return (SMB_MSGBUF_OVERFLOW);
 585                         while (repc > 0) {
 586                                 count = smb_mbtowc(&wchar, cvalp,
 587                                     MTS_MB_CHAR_MAX);
 588                                 if (count < 0)
 589                                         return (SMB_MSGBUF_DATA_ERROR);
 590                                 cvalp += count;
 591                                 if (wchar == 0)
 592                                         break;
 593                                 *mb->scan++ = (uint8_t)wchar;
 594                                 repc--;
 595                                 if (wchar & 0xff00) {
 596                                         *mb->scan++ = wchar >> 8;
 597                                         repc--;
 598                                 }
 599                         }
 600                         if (*cvalp == '\0' && repc > 0 &&
 601                             (mb->flags & SMB_MSGBUF_NOTERM) == 0) {
 602                                 *mb->scan++ = 0;
 603                                 repc--;
 604                         }
 605                         while (repc > 0) {
 606                                 *mb->scan++ = 0;
 607                                 repc--;
 608                         }
 609                         break;
 610 
 611                 case 'U': /* put unicode string */
 612 unicode_translation:
 613                         /*
 614                          * Unicode strings are always word aligned.
 615                          */
 616                         smb_msgbuf_word_align(mb);
 617                         cvalp = va_arg(ap, char *);
 618                         if (!repc_specified) {
 619                                 repc = smb_wcequiv_strlen(cvalp);
 620                                 if (!(mb->flags & SMB_MSGBUF_NOTERM))
 621                                         repc += 2;
 622                         }
 623                         if (!smb_msgbuf_has_space(mb, repc))
 624                                 return (SMB_MSGBUF_OVERFLOW);
 625                         while (repc >= 2) {
 626                                 count = smb_mbtowc(&wchar, cvalp,
 627                                     MTS_MB_CHAR_MAX);
 628                                 if (count < 0)
 629                                         return (SMB_MSGBUF_DATA_ERROR);
 630                                 cvalp += count;
 631                                 if (wchar == 0)
 632                                         break;
 633 
 634                                 LE_OUT16(mb->scan, wchar);
 635                                 mb->scan += 2;
 636                                 repc -= 2;
 637                         }
 638                         if (*cvalp == '\0' && repc >= 2 &&
 639                             (mb->flags & SMB_MSGBUF_NOTERM) == 0) {
 640                                 LE_OUT16(mb->scan, 0);
 641                                 mb->scan += 2;
 642                                 repc -= 2;
 643                         }
 644                         while (repc > 0) {
 645                                 *mb->scan++ = 0;
 646                                 repc--;
 647                         }
 648                         break;
 649 
 650                 case 'M':
 651                         if (smb_msgbuf_has_space(mb, 4) == 0)
 652                                 return (SMB_MSGBUF_OVERFLOW);
 653 
 654                         *mb->scan++ = 0xFF;
 655                         *mb->scan++ = 'S';
 656                         *mb->scan++ = 'M';
 657                         *mb->scan++ = 'B';
 658                         break;
 659 
 660                 default:
 661                         return (SMB_MSGBUF_INVALID_FORMAT);
 662                 }
 663         }
 664 
 665         return (SMB_MSGBUF_SUCCESS);
 666 }
 667 
 668 
 669 /*
 670  * smb_msgbuf_malloc
 671  *
 672  * Allocate some memory for use with this smb_msgbuf. We increase the
 673  * requested size to hold the list pointer and return a pointer
 674  * to the area for use by the caller.
 675  */
 676 static void *
 677 smb_msgbuf_malloc(smb_msgbuf_t *mb, size_t size)
 678 {
 679         smb_msgbuf_mlist_t *item;
 680 
 681         size += sizeof (smb_msgbuf_mlist_t);
 682 
 683 #if !defined(_KERNEL) && !defined(_FAKE_KERNEL)
 684         if ((item = malloc(size)) == NULL)
 685                 return (NULL);
 686 #else
 687         item = kmem_alloc(size, KM_SLEEP);
 688 #endif
 689         item->next = mb->mlist.next;
 690         item->size = size;
 691         mb->mlist.next = item;
 692 
 693         /*
 694          * The caller gets a pointer to the address
 695          * immediately after the smb_msgbuf_mlist_t.
 696          */
 697         return ((void *)(item + 1));
 698 }
 699 
 700 
 701 /*
 702  * smb_msgbuf_chkerc
 703  *
 704  * Diagnostic function to write an appropriate message to the system log.
 705  */
 706 static int
 707 smb_msgbuf_chkerc(char *text, int erc)
 708 {
 709         static struct {
 710                 int erc;
 711                 char *name;
 712         } etable[] = {
 713                 { SMB_MSGBUF_SUCCESS,           "success" },
 714                 { SMB_MSGBUF_UNDERFLOW,         "overflow/underflow" },
 715                 { SMB_MSGBUF_INVALID_FORMAT,    "invalid format" },
 716                 { SMB_MSGBUF_INVALID_HEADER,    "invalid header" },
 717                 { SMB_MSGBUF_DATA_ERROR,        "data error" }
 718         };
 719 
 720         int i;
 721 
 722         for (i = 0; i < sizeof (etable)/sizeof (etable[0]); ++i) {
 723                 if (etable[i].erc == erc) {
 724                         if (text == 0)
 725                                 text = "smb_msgbuf_chkerc";
 726                         break;
 727                 }
 728         }
 729         return (erc);
 730 }