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