1 /*
   2  * Copyright (c) 2000-2001 Boris Popov
   3  * All rights reserved.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  * 1. Redistributions of source code must retain the above copyright
   9  *    notice, this list of conditions and the following disclaimer.
  10  * 2. Redistributions in binary form must reproduce the above copyright
  11  *    notice, this list of conditions and the following disclaimer in the
  12  *    documentation and/or other materials provided with the distribution.
  13  * 3. All advertising materials mentioning features or use of this software
  14  *    must display the following acknowledgement:
  15  *    This product includes software developed by Boris Popov.
  16  * 4. Neither the name of the author nor the names of any co-contributors
  17  *    may be used to endorse or promote products derived from this software
  18  *    without specific prior written permission.
  19  *
  20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30  * SUCH DAMAGE.
  31  *
  32  * $Id: smb_trantcp.c,v 1.39 2005/03/02 01:27:44 lindak Exp $
  33  */
  34 /*
  35  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  36  * Use is subject to license terms.
  37  *
  38  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  39  */
  40 
  41 #include <sys/param.h>
  42 #include <sys/systm.h>
  43 #include <sys/autoconf.h>
  44 #include <sys/sysmacros.h>
  45 #include <sys/sunddi.h>
  46 #include <sys/kmem.h>
  47 #include <sys/proc.h>
  48 #include <sys/protosw.h>
  49 #include <sys/socket.h>
  50 #include <sys/poll.h>
  51 #include <sys/stream.h>
  52 #include <sys/strsubr.h>
  53 #include <sys/strsun.h>
  54 #include <sys/stropts.h>
  55 #include <sys/cmn_err.h>
  56 #include <sys/tihdr.h>
  57 #include <sys/tiuser.h>
  58 #include <sys/t_kuser.h>
  59 #include <sys/priv.h>
  60 
  61 #include <net/if.h>
  62 #include <net/route.h>
  63 
  64 #include <netinet/in.h>
  65 #include <netinet/tcp.h>
  66 
  67 #include <netsmb/smb_osdep.h>
  68 #include <netsmb/mchain.h>
  69 #include <netsmb/netbios.h>
  70 
  71 #include <netsmb/smb.h>
  72 #include <netsmb/smb_conn.h>
  73 #include <netsmb/smb_subr.h>
  74 #include <netsmb/smb_tran.h>
  75 #include <netsmb/smb_trantcp.h>
  76 
  77 static int  nb_disconnect(struct nbpcb *nbp);
  78 
  79 
  80 /*
  81  * Get mblks into *mpp until the data length is at least mlen.
  82  * Note that *mpp may already contain a fragment.
  83  *
  84  * If we ever have to wait more than 15 sec. to read a message,
  85  * return ETIME.  (Caller will declare the VD dead.)
  86  */
  87 static int
  88 nb_getmsg_mlen(struct nbpcb *nbp, mblk_t **mpp, size_t mlen)
  89 {
  90         mblk_t *im, *tm;
  91         union T_primitives      *pptr;
  92         size_t dlen;
  93         int events, fmode, timo, waitflg;
  94         int error = 0;
  95 
  96         /* We should be the only reader. */
  97         ASSERT(nbp->nbp_flags & NBF_RECVLOCK);
  98         /* nbp->nbp_tiptr checked by caller */
  99 
 100         /*
 101          * Get the first message (fragment) if
 102          * we don't already have a left-over.
 103          */
 104         dlen = msgdsize(*mpp); /* *mpp==null is OK */
 105         while (dlen < mlen) {
 106 
 107                 /*
 108                  * I think we still want this to return ETIME
 109                  * if nothing arrives for SMB_NBTIMO (15) sec.
 110                  * so we can report "server not responding".
 111                  * We _could_ just block here now that our
 112                  * IOD is just a reader.
 113                  */
 114 #if 1
 115                 /* Wait with timeout... */
 116                 events = 0;
 117                 waitflg = READWAIT;
 118                 timo = SEC_TO_TICK(SMB_NBTIMO);
 119                 error = t_kspoll(nbp->nbp_tiptr, timo, waitflg, &events);
 120                 if (!error && !events)
 121                         error = ETIME;
 122                 if (error)
 123                         break;
 124                 /* file mode for recv is: */
 125                 fmode = FNDELAY; /* non-blocking */
 126 #else
 127                 fmode = 0; /* normal (blocking) */
 128 #endif
 129 
 130                 /* Get some more... */
 131                 tm = NULL;
 132                 error = tli_recv(nbp->nbp_tiptr, &tm, fmode);
 133                 if (error == EAGAIN)
 134                         continue;
 135                 if (error)
 136                         break;
 137 
 138                 /*
 139                  * Normally get M_DATA messages here,
 140                  * but have to check for other types.
 141                  */
 142                 switch (tm->b_datap->db_type) {
 143                 case M_DATA:
 144                         break;
 145                 case M_PROTO:
 146                 case M_PCPROTO:
 147                         /*LINTED*/
 148                         pptr = (union T_primitives *)tm->b_rptr;
 149                         switch (pptr->type) {
 150                         case T_DATA_IND:
 151                                 /* remove 1st mblk, keep the rest. */
 152                                 im = tm->b_cont;
 153                                 tm->b_cont = NULL;
 154                                 freeb(tm);
 155                                 tm = im;
 156                                 break;
 157                         case T_DISCON_IND:
 158                                 /* Peer disconnected. */
 159                                 NBDEBUG("T_DISCON_IND: reason=%d",
 160                                     (int)pptr->discon_ind.DISCON_reason);
 161                                 goto discon;
 162                         case T_ORDREL_IND:
 163                                 /* Peer disconnecting. */
 164                                 NBDEBUG("T_ORDREL_IND");
 165                                 goto discon;
 166                         case T_OK_ACK:
 167                                 switch (pptr->ok_ack.CORRECT_prim) {
 168                                 case T_DISCON_REQ:
 169                                         NBDEBUG("T_OK_ACK/T_DISCON_REQ");
 170                                         goto discon;
 171                                 default:
 172                                         NBDEBUG("T_OK_ACK/prim=%d",
 173                                             (int)pptr->ok_ack.CORRECT_prim);
 174                                         goto discon;
 175                                 }
 176                         default:
 177                                 NBDEBUG("M_PROTO/type=%d", (int)pptr->type);
 178                                 goto discon;
 179                         }
 180                         break; /* M_PROTO, M_PCPROTO */
 181 
 182                 default:
 183                         NBDEBUG("unexpected msg type=%d",
 184                             tm->b_datap->db_type);
 185                         /*FALLTHROUGH*/
 186 discon:
 187                         /*
 188                          * The connection is no longer usable.
 189                          * Drop this message and disconnect.
 190                          *
 191                          * Note: nb_disconnect only does t_snddis
 192                          * on the first call, but does important
 193                          * cleanup and state change on any call.
 194                          */
 195                         freemsg(tm);
 196                         (void) nb_disconnect(nbp);
 197                         return (ENOTCONN);
 198                 }
 199 
 200                 /*
 201                  * If we have a data message, append it to
 202                  * the previous chunk(s) and update dlen
 203                  */
 204                 if (!tm)
 205                         continue;
 206                 if (*mpp == NULL) {
 207                         *mpp = tm;
 208                 } else {
 209                         /* Append */
 210                         for (im = *mpp; im->b_cont; im = im->b_cont)
 211                                 ;
 212                         im->b_cont = tm;
 213                 }
 214                 dlen += msgdsize(tm);
 215         }
 216 
 217         return (error);
 218 }
 219 
 220 /*
 221  * Send a T_DISCON_REQ (disconnect)
 222  */
 223 static int
 224 nb_snddis(struct nbpcb *nbp)
 225 {
 226         TIUSER *tiptr = nbp->nbp_tiptr;
 227         cred_t *cr = nbp->nbp_cred;
 228         mblk_t *mp;
 229         struct T_discon_req *dreq;
 230         int error, mlen;
 231 
 232         ASSERT(MUTEX_HELD(&nbp->nbp_lock));
 233 
 234         if (tiptr == NULL)
 235                 return (EBADF);
 236 
 237         mlen = sizeof (struct T_discon_req);
 238         if (!(mp = allocb_cred_wait(mlen, STR_NOSIG, &error, cr, NOPID)))
 239                 return (error);
 240 
 241         mp->b_datap->db_type = M_PROTO;
 242         /*LINTED*/
 243         dreq = (struct T_discon_req *)mp->b_wptr;
 244         dreq->PRIM_type = T_DISCON_REQ;
 245         dreq->SEQ_number = -1;
 246         mp->b_wptr += sizeof (struct T_discon_req);
 247 
 248         error = tli_send(tiptr, mp, tiptr->fp->f_flag);
 249         /*
 250          * There is an OK/ACK response expected, which is
 251          * either handled by our receiver thread, or just
 252          * discarded if we're closing this endpoint.
 253          */
 254 
 255         return (error);
 256 }
 257 
 258 /*
 259  * Stuff the NetBIOS header into space already prepended.
 260  */
 261 static void
 262 nb_sethdr(mblk_t *m, uint8_t type, uint32_t len)
 263 {
 264         uint32_t *p;
 265 
 266         len &= 0x1FFFF;
 267         len |= (type << 24);
 268 
 269         /*LINTED*/
 270         p = (uint32_t *)m->b_rptr;
 271         *p = htonl(len);
 272 }
 273 
 274 /*
 275  * Wait for up to 15 sec. for the next packet.
 276  * Often return ETIME and do nothing else.
 277  * When a packet header is available, check
 278  * the header and get the length, but don't
 279  * consume it.  No side effects here except
 280  * for the pullupmsg call.
 281  */
 282 static int
 283 nbssn_peekhdr(struct nbpcb *nbp, size_t *lenp,  uint8_t *rpcodep)
 284 {
 285         uint32_t len, *hdr;
 286         int error;
 287 
 288         /*
 289          * Get the first message (fragment) if
 290          * we don't already have a left-over.
 291          */
 292         error = nb_getmsg_mlen(nbp, &nbp->nbp_frag, sizeof (len));
 293         if (error)
 294                 return (error);
 295 
 296         if (!pullupmsg(nbp->nbp_frag, sizeof (len)))
 297                 return (ENOSR);
 298 
 299         /*
 300          * Check the NetBIOS header.
 301          * (NOT consumed here)
 302          */
 303         /*LINTED*/
 304         hdr = (uint32_t *)nbp->nbp_frag->b_rptr;
 305 
 306         len = ntohl(*hdr);
 307         if ((len >> 16) & 0xFE) {
 308                 NBDEBUG("bad nb header received 0x%x (MBZ flag set)\n", len);
 309                 return (EPIPE);
 310         }
 311         *rpcodep = (len >> 24) & 0xFF;
 312         switch (*rpcodep) {
 313         case NB_SSN_MESSAGE:
 314         case NB_SSN_REQUEST:
 315         case NB_SSN_POSRESP:
 316         case NB_SSN_NEGRESP:
 317         case NB_SSN_RTGRESP:
 318         case NB_SSN_KEEPALIVE:
 319                 break;
 320         default:
 321                 NBDEBUG("bad nb header received 0x%x (bogus type)\n", len);
 322                 return (EPIPE);
 323         }
 324         len &= 0x1ffff;
 325         if (len > NB_MAXPKTLEN) {
 326                 NBDEBUG("packet too long (%d)\n", len);
 327                 return (EFBIG);
 328         }
 329         *lenp = len;
 330         return (0);
 331 }
 332 
 333 /*
 334  * Receive a NetBIOS message.  This may block to wait for the entire
 335  * message to arrive.  The caller knows there is (or should be) a
 336  * message to be read.  When we receive and drop a keepalive or
 337  * zero-length message, return EAGAIN so the caller knows that
 338  * something was received.  This avoids false triggering of the
 339  * "server not responding" state machine.
 340  *
 341  * Calls to this are serialized at a higher level.
 342  */
 343 static int
 344 nbssn_recv(struct nbpcb *nbp, mblk_t **mpp, int *lenp,
 345     uint8_t *rpcodep)
 346 {
 347         mblk_t *m0;
 348         uint8_t rpcode;
 349         int error;
 350         size_t rlen, len;
 351 
 352         /* We should be the only reader. */
 353         ASSERT(nbp->nbp_flags & NBF_RECVLOCK);
 354 
 355         if (nbp->nbp_tiptr == NULL)
 356                 return (EBADF);
 357         if (mpp) {
 358                 if (*mpp) {
 359                         NBDEBUG("*mpp not 0 - leak?");
 360                 }
 361                 *mpp = NULL;
 362         }
 363         m0 = NULL;
 364 
 365         /*
 366          * Get the NetBIOS header (not consumed yet)
 367          */
 368         error = nbssn_peekhdr(nbp, &len, &rpcode);
 369         if (error) {
 370                 if (error != ETIME)
 371                         NBDEBUG("peekhdr, error=%d\n", error);
 372                 return (error);
 373         }
 374         NBDEBUG("Have pkt, type=0x%x len=0x%x\n",
 375             (int)rpcode, (int)len);
 376 
 377         /*
 378          * Block here waiting for the whole packet to arrive.
 379          * If we get a timeout, return without side effects.
 380          * The data length we wait for here includes both the
 381          * NetBIOS header and the payload.
 382          */
 383         error = nb_getmsg_mlen(nbp, &nbp->nbp_frag, len + 4);
 384         if (error) {
 385                 NBDEBUG("getmsg(body), error=%d\n", error);
 386                 return (error);
 387         }
 388 
 389         /*
 390          * We now have an entire NetBIOS message.
 391          * Trim off the NetBIOS header and consume it.
 392          * Note: _peekhdr has done pullupmsg for us,
 393          * so we know it's safe to advance b_rptr.
 394          */
 395         m0 = nbp->nbp_frag;
 396         m0->b_rptr += 4;
 397 
 398         /*
 399          * There may be more data after the message
 400          * we're about to return, in which case we
 401          * split it and leave the remainder.
 402          */
 403         rlen = msgdsize(m0);
 404         ASSERT(rlen >= len);
 405         nbp->nbp_frag = NULL;
 406         if (rlen > len)
 407                 nbp->nbp_frag = m_split(m0, len, 1);
 408 
 409         if (nbp->nbp_state != NBST_SESSION) {
 410                 /*
 411                  * No session is established.
 412                  * Return whatever packet we got.
 413                  */
 414                 goto out;
 415         }
 416 
 417         /*
 418          * A session is established; the only packets
 419          * we should see are session message and
 420          * keep-alive packets.  Drop anything else.
 421          */
 422         switch (rpcode) {
 423 
 424         case NB_SSN_KEEPALIVE:
 425                 /*
 426                  * It's a keepalive.  Discard any data in it
 427                  * (there's not supposed to be any, but that
 428                  * doesn't mean some server won't send some)
 429                  */
 430                 if (len)
 431                         NBDEBUG("Keepalive with data %d\n", (int)len);
 432                 error = EAGAIN;
 433                 break;
 434 
 435         case NB_SSN_MESSAGE:
 436                 /*
 437                  * Session message.  Does it have any data?
 438                  */
 439                 if (len == 0) {
 440                         /*
 441                          * No data - treat as keepalive (drop).
 442                          */
 443                         error = EAGAIN;
 444                         break;
 445                 }
 446                 /*
 447                  * Yes, has data.  Return it.
 448                  */
 449                 error = 0;
 450                 break;
 451 
 452         default:
 453                 /*
 454                  * Drop anything else.
 455                  */
 456                 NBDEBUG("non-session packet %x\n", rpcode);
 457                 error = EAGAIN;
 458                 break;
 459         }
 460 
 461 out:
 462         if (error) {
 463                 if (m0)
 464                         m_freem(m0);
 465                 return (error);
 466         }
 467         if (mpp)
 468                 *mpp = m0;
 469         else
 470                 m_freem(m0);
 471         *lenp = (int)len;
 472         *rpcodep = rpcode;
 473         return (0);
 474 }
 475 
 476 /*
 477  * SMB transport interface
 478  *
 479  * This is called only by the thread creating this endpoint,
 480  * so we're single-threaded here.
 481  */
 482 static int
 483 smb_nbst_create(struct smb_vc *vcp, cred_t *cr)
 484 {
 485         TIUSER *tiptr = NULL;
 486         struct nbpcb *nbp = NULL;
 487         dev_t dev;
 488         int rc;
 489         ushort_t fmode;
 490 
 491         switch (vcp->vc_srvaddr.sa.sa_family) {
 492         case AF_INET:
 493                 dev = nsmb_dev_tcp;
 494                 break;
 495         case AF_INET6:
 496                 dev = nsmb_dev_tcp6;
 497                 break;
 498         default:
 499                 return (EAFNOSUPPORT);
 500         }
 501 
 502         fmode = FREAD|FWRITE;
 503         rc = t_kopen(NULL, dev, fmode, &tiptr, cr);
 504         if (rc != 0) {
 505                 cmn_err(CE_NOTE, "t_kopen failed, rc=%d", rc);
 506                 return (rc);
 507         }
 508         ASSERT(tiptr != NULL);
 509 
 510         nbp = kmem_zalloc(sizeof (struct nbpcb), KM_SLEEP);
 511 
 512         nbp->nbp_timo.tv_sec = SMB_NBTIMO;
 513         nbp->nbp_state = NBST_IDLE;
 514         nbp->nbp_vc = vcp;
 515         nbp->nbp_tiptr = tiptr;
 516         nbp->nbp_fmode = fmode;
 517         nbp->nbp_cred = cr;
 518         crhold(cr);
 519         mutex_init(&nbp->nbp_lock, NULL, MUTEX_DRIVER, NULL);
 520 
 521         vcp->vc_tdata = nbp;
 522 
 523         return (0);
 524 }
 525 
 526 /*
 527  * destroy a transport endpoint
 528  *
 529  * This is called only by the thread with the last reference
 530  * to this endpoint, so we're single-threaded here.
 531  */
 532 static int
 533 smb_nbst_done(struct smb_vc *vcp)
 534 {
 535         struct nbpcb *nbp = vcp->vc_tdata;
 536 
 537         if (nbp == NULL)
 538                 return (ENOTCONN);
 539         vcp->vc_tdata = NULL;
 540 
 541         /*
 542          * Don't really need to disconnect here,
 543          * because the close following will do it.
 544          * But it's harmless.
 545          */
 546         if (nbp->nbp_flags & NBF_CONNECTED)
 547                 (void) nb_disconnect(nbp);
 548         if (nbp->nbp_tiptr)
 549                 (void) t_kclose(nbp->nbp_tiptr, 0);
 550         if (nbp->nbp_laddr)
 551                 smb_free_sockaddr((struct sockaddr *)nbp->nbp_laddr);
 552         if (nbp->nbp_paddr)
 553                 smb_free_sockaddr((struct sockaddr *)nbp->nbp_paddr);
 554         if (nbp->nbp_cred)
 555                 crfree(nbp->nbp_cred);
 556         mutex_destroy(&nbp->nbp_lock);
 557         kmem_free(nbp, sizeof (*nbp));
 558         return (0);
 559 }
 560 
 561 static int
 562 smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap)
 563 {
 564         struct nbpcb *nbp = vcp->vc_tdata;
 565         TIUSER *tiptr = nbp->nbp_tiptr;
 566         int err;
 567 
 568         /* Only default bind supported. */
 569         if (sap != NULL)
 570                 return (ENOTSUP);
 571 
 572         err = t_kbind(tiptr, NULL, NULL);
 573 
 574         return (err);
 575 }
 576 
 577 static int
 578 smb_nbst_unbind(struct smb_vc *vcp)
 579 {
 580         struct nbpcb *nbp = vcp->vc_tdata;
 581         TIUSER *tiptr = nbp->nbp_tiptr;
 582         int err;
 583 
 584         err = t_kunbind(tiptr);
 585 
 586         return (err);
 587 }
 588 
 589 static int
 590 smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap)
 591 {
 592         struct t_call   call;
 593         struct nbpcb    *nbp = vcp->vc_tdata;
 594         TIUSER          *tiptr = nbp->nbp_tiptr;
 595         int alen, err;
 596 
 597         /* Need the address length */
 598         switch (sap->sa_family) {
 599         case AF_INET:
 600                 alen = sizeof (struct sockaddr_in);
 601                 break;
 602         case AF_INET6:
 603                 alen = sizeof (struct sockaddr_in6);
 604                 break;
 605         default:
 606                 return (EAFNOSUPPORT);
 607         }
 608 
 609         /* sockaddr goes in the "addr" netbuf */
 610         bzero(&call, sizeof (call));
 611         call.addr.buf = (char *)sap;
 612         call.addr.len = alen;
 613         call.addr.maxlen = alen;
 614 
 615         err = t_kconnect(tiptr, &call, NULL);
 616         if (err != 0)
 617                 return (err);
 618 
 619         mutex_enter(&nbp->nbp_lock);
 620 
 621         nbp->nbp_flags |= NBF_CONNECTED;
 622         nbp->nbp_state = NBST_SESSION;
 623 
 624         mutex_exit(&nbp->nbp_lock);
 625 
 626         return (0);
 627 }
 628 
 629 static int
 630 smb_nbst_disconnect(struct smb_vc *vcp)
 631 {
 632         struct nbpcb *nbp = vcp->vc_tdata;
 633 
 634         if (nbp == NULL)
 635                 return (ENOTCONN);
 636 
 637         return (nb_disconnect(nbp));
 638 }
 639 
 640 static int
 641 nb_disconnect(struct nbpcb *nbp)
 642 {
 643         int err = 0;
 644 
 645         mutex_enter(&nbp->nbp_lock);
 646 
 647         if ((nbp->nbp_flags & NBF_CONNECTED) != 0) {
 648                 nbp->nbp_flags &= ~NBF_CONNECTED;
 649                 err = nb_snddis(nbp);
 650         }
 651 
 652         mutex_exit(&nbp->nbp_lock);
 653         return (err);
 654 }
 655 
 656 /*
 657  * Add the NetBIOS session header and send.
 658  *
 659  * Calls to this are serialized at a higher level.
 660  */
 661 static int
 662 nbssn_send(struct nbpcb *nbp, mblk_t *m)
 663 {
 664         ptrdiff_t diff;
 665         uint32_t mlen;
 666         int error;
 667 
 668         /* We should be the only sender. */
 669         ASSERT(nbp->nbp_flags & NBF_SENDLOCK);
 670 
 671         if (nbp->nbp_tiptr == NULL) {
 672                 error = EBADF;
 673                 goto errout;
 674         }
 675 
 676         /*
 677          * Get the message length, which
 678          * does NOT include the NetBIOS header
 679          */
 680         mlen = msgdsize(m);
 681 
 682         /*
 683          * Normally, mb_init() will have left space
 684          * for us to prepend the NetBIOS header in
 685          * the data block of the first mblk.
 686          * However, we have to check in case other
 687          * code did not leave this space, or if the
 688          * message is from dupmsg (db_ref > 1)
 689          *
 690          * If don't find room in the first data block,
 691          * we have to allocb a new message and link it
 692          * on the front of the chain.  We try not to
 693          * do this becuase it's less efficient.  Also,
 694          * some network drivers will apparently send
 695          * each mblk in the chain as separate frames.
 696          * (That's arguably a driver bug.)
 697          *
 698          * Not bothering with allocb_cred_wait below
 699          * because the message we're prepending to
 700          * should already have a db_credp.
 701          */
 702 
 703         diff = MBLKHEAD(m);
 704         if (diff == 4 && DB_REF(m) == 1) {
 705                 /* We can use the first dblk. */
 706                 m->b_rptr -= 4;
 707         } else {
 708                 /* Link a new mblk on the head. */
 709                 mblk_t *m0;
 710 
 711                 /* M_PREPEND */
 712                 m0 = allocb_wait(4, BPRI_LO, STR_NOSIG, &error);
 713                 if (m0 == NULL)
 714                         goto errout;
 715 
 716                 m0->b_wptr += 4;
 717                 m0->b_cont = m;
 718                 m = m0;
 719         }
 720 
 721         nb_sethdr(m, NB_SSN_MESSAGE, mlen);
 722         error = tli_send(nbp->nbp_tiptr, m, 0);
 723         return (error);
 724 
 725 errout:
 726         if (m != NULL)
 727                 m_freem(m);
 728         return (error);
 729 }
 730 
 731 /*
 732  * Always consume the message.
 733  * (On error too!)
 734  */
 735 static int
 736 smb_nbst_send(struct smb_vc *vcp, mblk_t *m)
 737 {
 738         struct nbpcb *nbp = vcp->vc_tdata;
 739         int err;
 740 
 741         mutex_enter(&nbp->nbp_lock);
 742         if ((nbp->nbp_flags & NBF_CONNECTED) == 0) {
 743                 err = ENOTCONN;
 744                 goto out;
 745         }
 746         if (nbp->nbp_flags & NBF_SENDLOCK) {
 747                 NBDEBUG("multiple smb_nbst_send!\n");
 748                 err = EWOULDBLOCK;
 749                 goto out;
 750         }
 751         nbp->nbp_flags |= NBF_SENDLOCK;
 752         mutex_exit(&nbp->nbp_lock);
 753 
 754         err = nbssn_send(nbp, m);
 755         m = NULL; /* nbssn_send always consumes this */
 756 
 757         mutex_enter(&nbp->nbp_lock);
 758         nbp->nbp_flags &= ~NBF_SENDLOCK;
 759         if (nbp->nbp_flags & NBF_LOCKWAIT) {
 760                 nbp->nbp_flags &= ~NBF_LOCKWAIT;
 761                 cv_broadcast(&nbp->nbp_cv);
 762         }
 763 out:
 764         mutex_exit(&nbp->nbp_lock);
 765         if (m != NULL)
 766                 m_freem(m);
 767         return (err);
 768 }
 769 
 770 static int
 771 smb_nbst_recv(struct smb_vc *vcp, mblk_t **mpp)
 772 {
 773         struct nbpcb *nbp = vcp->vc_tdata;
 774         uint8_t rpcode;
 775         int err, rplen;
 776 
 777         mutex_enter(&nbp->nbp_lock);
 778         if ((nbp->nbp_flags & NBF_CONNECTED) == 0) {
 779                 err = ENOTCONN;
 780                 goto out;
 781         }
 782         if (nbp->nbp_flags & NBF_RECVLOCK) {
 783                 NBDEBUG("multiple smb_nbst_recv!\n");
 784                 err = EWOULDBLOCK;
 785                 goto out;
 786         }
 787         nbp->nbp_flags |= NBF_RECVLOCK;
 788         mutex_exit(&nbp->nbp_lock);
 789 
 790         err = nbssn_recv(nbp, mpp, &rplen, &rpcode);
 791 
 792         mutex_enter(&nbp->nbp_lock);
 793         nbp->nbp_flags &= ~NBF_RECVLOCK;
 794         if (nbp->nbp_flags & NBF_LOCKWAIT) {
 795                 nbp->nbp_flags &= ~NBF_LOCKWAIT;
 796                 cv_broadcast(&nbp->nbp_cv);
 797         }
 798 out:
 799         mutex_exit(&nbp->nbp_lock);
 800         return (err);
 801 }
 802 
 803 /*
 804  * Wait for up to "ticks" clock ticks for input on vcp.
 805  * Returns zero if input is available, otherwise ETIME
 806  * indicating time expired, or other error codes.
 807  */
 808 /*ARGSUSED*/
 809 static int
 810 smb_nbst_poll(struct smb_vc *vcp, int ticks)
 811 {
 812         return (ENOTSUP);
 813 }
 814 
 815 /*ARGSUSED*/
 816 static int
 817 smb_nbst_getparam(struct smb_vc *vcp, int param, void *data)
 818 {
 819         return (EINVAL);
 820 }
 821 
 822 static int
 823 smb_nbst_setparam(struct smb_vc *vcp, int param, void *data)
 824 {
 825         struct t_optmgmt oreq, ores;
 826         struct {
 827                 struct T_opthdr oh;
 828                 int ival;
 829         } opts;
 830         struct nbpcb *nbp = vcp->vc_tdata;
 831         int level, name, err;
 832 
 833         switch (param) {
 834         case SMBTP_TCP_NODELAY:
 835                 level = IPPROTO_TCP;
 836                 name = TCP_NODELAY;
 837                 break;
 838 
 839         case SMBTP_TCP_CON_TMO: /* int mSec */
 840                 level = IPPROTO_TCP;
 841                 name = TCP_CONN_ABORT_THRESHOLD;
 842                 break;
 843 
 844         case SMBTP_KEEPALIVE:   // SO_KEEPALIVE
 845         case SMBTP_SNDBUF:      // SO_SNDBUF
 846         case SMBTP_RCVBUF:      // SO_RCVBUF
 847         case SMBTP_RCVTIMEO:    // SO_RCVTIMEO
 848                 level = SOL_SOCKET;
 849                 name = param;
 850                 break;
 851 
 852         default:
 853                 return (EINVAL);
 854         }
 855 
 856         /* opt header */
 857         opts.oh.len = sizeof (opts);
 858         opts.oh.level = level;
 859         opts.oh.name = name;
 860         opts.oh.status = 0;
 861         opts.ival = *(int *)data;
 862 
 863         oreq.flags = T_NEGOTIATE;
 864         oreq.opt.buf = (void *)&opts;
 865         oreq.opt.len = sizeof (opts);
 866         oreq.opt.maxlen = oreq.opt.len;
 867 
 868         ores.flags = 0;
 869         ores.opt.buf = NULL;
 870         ores.opt.len = 0;
 871         ores.opt.maxlen = 0;
 872 
 873         err = t_koptmgmt(nbp->nbp_tiptr, &oreq, &ores);
 874         if (err != 0) {
 875                 cmn_err(CE_NOTE, "t_opgmgnt, err = %d", err);
 876                 return (EPROTO);
 877         }
 878 
 879         if ((ores.flags & T_SUCCESS) == 0) {
 880                 cmn_err(CE_NOTE, "smb_nbst_setparam: "
 881                     "flags 0x%x, status 0x%x",
 882                     (int)ores.flags, (int)opts.oh.status);
 883                 return (EPROTO);
 884         }
 885 
 886         return (0);
 887 }
 888 
 889 /*
 890  * Check for fatal errors
 891  */
 892 /*ARGSUSED*/
 893 static int
 894 smb_nbst_fatal(struct smb_vc *vcp, int error)
 895 {
 896         switch (error) {
 897         case ENOTCONN:
 898         case ENETRESET:
 899         case ECONNABORTED:
 900         case EPIPE:
 901                 return (1);
 902         }
 903         return (0);
 904 }
 905 
 906 
 907 struct smb_tran_desc smb_tran_nbtcp_desc = {
 908         SMBT_NBTCP,
 909         smb_nbst_create,
 910         smb_nbst_done,
 911         smb_nbst_bind,
 912         smb_nbst_unbind,
 913         smb_nbst_connect,
 914         smb_nbst_disconnect,
 915         smb_nbst_send,
 916         smb_nbst_recv,
 917         smb_nbst_poll,
 918         smb_nbst_getparam,
 919         smb_nbst_setparam,
 920         smb_nbst_fatal,
 921         {NULL, NULL}
 922 };