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 2012 Nexenta Systems, Inc.  All rights reserved.
  36  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  37  * Use is subject to license terms.
  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 
 600         if (nbp->nbp_tiptr != NULL) {
 601                 (void) t_kclose(nbp->nbp_tiptr, 0);
 602                 nbp->nbp_tiptr = NULL;
 603         }
 604         nbp->nbp_state = NBST_CLOSED;
 605 
 606         mutex_exit(&nbp->nbp_lock);
 607 }
 608 
 609 static int
 610 smb_nbst_loan_fp(struct smb_vc *vcp, struct file *fp, cred_t *cr)
 611 {
 612         struct nbpcb *nbp = vcp->vc_tdata;
 613         int error = 0;
 614 
 615         /*
 616          * Un-loan the existing one, if any.
 617          */
 618         (void) nb_disconnect(nbp);
 619         nb_unloan_fp(nbp);
 620 
 621         /*
 622          * Loan the new one passed in.
 623          */
 624         if (fp != NULL) {
 625                 error = nb_loan_fp(nbp, fp, cr);
 626         }
 627 
 628         return (error);
 629 }
 630 
 631 /*ARGSUSED*/
 632 static int
 633 smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap)
 634 {
 635         return (ENOTSUP);
 636 }
 637 
 638 /*ARGSUSED*/
 639 static int
 640 smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap)
 641 {
 642         return (ENOTSUP);
 643 }
 644 
 645 /*ARGSUSED*/
 646 static int
 647 smb_nbst_disconnect(struct smb_vc *vcp)
 648 {
 649         struct nbpcb *nbp = vcp->vc_tdata;
 650 
 651         if (nbp == NULL)
 652                 return (ENOTCONN);
 653 
 654         return (nb_disconnect(nbp));
 655 }
 656 
 657 static int
 658 nb_disconnect(struct nbpcb *nbp)
 659 {
 660         int err = 0;
 661 
 662         mutex_enter(&nbp->nbp_lock);
 663 
 664         if ((nbp->nbp_flags & NBF_CONNECTED) != 0) {
 665                 nbp->nbp_flags &= ~NBF_CONNECTED;
 666 
 667                 if (nbp->nbp_frag != NULL) {
 668                         freemsg(nbp->nbp_frag);
 669                         nbp->nbp_frag = NULL;
 670                 }
 671 
 672                 err = nb_snddis(nbp);
 673         }
 674 
 675         mutex_exit(&nbp->nbp_lock);
 676         return (err);
 677 }
 678 
 679 /*
 680  * Add the NetBIOS session header and send.
 681  *
 682  * Calls to this are serialized at a higher level.
 683  */
 684 static int
 685 nbssn_send(struct nbpcb *nbp, mblk_t *m)
 686 {
 687         ptrdiff_t diff;
 688         uint32_t mlen;
 689         int error;
 690 
 691         /* We should be the only sender. */
 692         ASSERT(nbp->nbp_flags & NBF_SENDLOCK);
 693 
 694         if (nbp->nbp_tiptr == NULL) {
 695                 error = EBADF;
 696                 goto errout;
 697         }
 698 
 699         /*
 700          * Get the message length, which
 701          * does NOT include the NetBIOS header
 702          */
 703         mlen = msgdsize(m);
 704 
 705         /*
 706          * Normally, mb_init() will have left space
 707          * for us to prepend the NetBIOS header in
 708          * the data block of the first mblk.
 709          * However, we have to check in case other
 710          * code did not leave this space, or if the
 711          * message is from dupmsg (db_ref > 1)
 712          *
 713          * If don't find room in the first data block,
 714          * we have to allocb a new message and link it
 715          * on the front of the chain.  We try not to
 716          * do this becuase it's less efficient.  Also,
 717          * some network drivers will apparently send
 718          * each mblk in the chain as separate frames.
 719          * (That's arguably a driver bug.)
 720          *
 721          * Not bothering with allocb_cred_wait below
 722          * because the message we're prepending to
 723          * should already have a db_credp.
 724          */
 725 
 726         diff = MBLKHEAD(m);
 727         if (diff == 4 && DB_REF(m) == 1) {
 728                 /* We can use the first dblk. */
 729                 m->b_rptr -= 4;
 730         } else {
 731                 /* Link a new mblk on the head. */
 732                 mblk_t *m0;
 733 
 734                 /* M_PREPEND */
 735                 m0 = allocb_wait(4, BPRI_LO, STR_NOSIG, &error);
 736                 if (m0 == NULL)
 737                         goto errout;
 738 
 739                 m0->b_wptr += 4;
 740                 m0->b_cont = m;
 741                 m = m0;
 742         }
 743 
 744         nb_sethdr(m, NB_SSN_MESSAGE, mlen);
 745         error = tli_send(nbp->nbp_tiptr, m, 0);
 746         return (error);
 747 
 748 errout:
 749         if (m != NULL)
 750                 m_freem(m);
 751         return (error);
 752 }
 753 
 754 /*
 755  * Always consume the message.
 756  * (On error too!)
 757  */
 758 static int
 759 smb_nbst_send(struct smb_vc *vcp, mblk_t *m)
 760 {
 761         struct nbpcb *nbp = vcp->vc_tdata;
 762         int err;
 763 
 764         mutex_enter(&nbp->nbp_lock);
 765         if ((nbp->nbp_flags & NBF_CONNECTED) == 0) {
 766                 err = ENOTCONN;
 767                 goto out;
 768         }
 769         if (nbp->nbp_flags & NBF_SENDLOCK) {
 770                 NBDEBUG("multiple smb_nbst_send!\n");
 771                 err = EWOULDBLOCK;
 772                 goto out;
 773         }
 774         nbp->nbp_flags |= NBF_SENDLOCK;
 775         mutex_exit(&nbp->nbp_lock);
 776 
 777         err = nbssn_send(nbp, m);
 778         m = NULL; /* nbssn_send always consumes this */
 779 
 780         mutex_enter(&nbp->nbp_lock);
 781         nbp->nbp_flags &= ~NBF_SENDLOCK;
 782         if (nbp->nbp_flags & NBF_LOCKWAIT) {
 783                 nbp->nbp_flags &= ~NBF_LOCKWAIT;
 784                 cv_broadcast(&nbp->nbp_cv);
 785         }
 786 out:
 787         mutex_exit(&nbp->nbp_lock);
 788         if (m != NULL)
 789                 m_freem(m);
 790         return (err);
 791 }
 792 
 793 static int
 794 smb_nbst_recv(struct smb_vc *vcp, mblk_t **mpp)
 795 {
 796         struct nbpcb *nbp = vcp->vc_tdata;
 797         uint8_t rpcode;
 798         int err, rplen;
 799 
 800         mutex_enter(&nbp->nbp_lock);
 801         if ((nbp->nbp_flags & NBF_CONNECTED) == 0) {
 802                 err = ENOTCONN;
 803                 goto out;
 804         }
 805         if (nbp->nbp_flags & NBF_RECVLOCK) {
 806                 NBDEBUG("multiple smb_nbst_recv!\n");
 807                 err = EWOULDBLOCK;
 808                 goto out;
 809         }
 810         nbp->nbp_flags |= NBF_RECVLOCK;
 811         mutex_exit(&nbp->nbp_lock);
 812 
 813         err = nbssn_recv(nbp, mpp, &rplen, &rpcode);
 814 
 815         mutex_enter(&nbp->nbp_lock);
 816         nbp->nbp_flags &= ~NBF_RECVLOCK;
 817         if (nbp->nbp_flags & NBF_LOCKWAIT) {
 818                 nbp->nbp_flags &= ~NBF_LOCKWAIT;
 819                 cv_broadcast(&nbp->nbp_cv);
 820         }
 821 out:
 822         mutex_exit(&nbp->nbp_lock);
 823         return (err);
 824 }
 825 
 826 /*
 827  * Wait for up to "ticks" clock ticks for input on vcp.
 828  * Returns zero if input is available, otherwise ETIME
 829  * indicating time expired, or other error codes.
 830  */
 831 /*ARGSUSED*/
 832 static int
 833 smb_nbst_poll(struct smb_vc *vcp, int ticks)
 834 {
 835         return (ENOTSUP);
 836 }
 837 
 838 static int
 839 smb_nbst_getparam(struct smb_vc *vcp, int param, void *data)
 840 {
 841         struct nbpcb *nbp = vcp->vc_tdata;
 842 
 843         switch (param) {
 844         case SMBTP_SNDSZ:
 845                 *(int *)data = nbp->nbp_sndbuf;
 846                 break;
 847         case SMBTP_RCVSZ:
 848                 *(int *)data = nbp->nbp_rcvbuf;
 849                 break;
 850         case SMBTP_TIMEOUT:
 851                 *(struct timespec *)data = nbp->nbp_timo;
 852                 break;
 853 #ifdef SMBTP_SELECTID
 854         case SMBTP_SELECTID:
 855                 *(void **)data = nbp->nbp_selectid;
 856                 break;
 857 #endif
 858 #ifdef SMBTP_UPCALL
 859         case SMBTP_UPCALL:
 860                 *(void **)data = nbp->nbp_upcall;
 861                 break;
 862 #endif
 863         default:
 864                 return (EINVAL);
 865         }
 866         return (0);
 867 }
 868 
 869 /*ARGSUSED*/
 870 static int
 871 smb_nbst_setparam(struct smb_vc *vcp, int param, void *data)
 872 {
 873         return (EINVAL);
 874 }
 875 
 876 /*
 877  * Check for fatal errors
 878  */
 879 /*ARGSUSED*/
 880 static int
 881 smb_nbst_fatal(struct smb_vc *vcp, int error)
 882 {
 883         switch (error) {
 884         case ENOTCONN:
 885         case ENETRESET:
 886         case ECONNABORTED:
 887         case EPIPE:
 888                 return (1);
 889         }
 890         return (0);
 891 }
 892 
 893 
 894 struct smb_tran_desc smb_tran_nbtcp_desc = {
 895         SMBT_NBTCP,
 896         smb_nbst_create,
 897         smb_nbst_done,
 898         smb_nbst_bind,
 899         smb_nbst_connect,
 900         smb_nbst_disconnect,
 901         smb_nbst_send,
 902         smb_nbst_recv,
 903         smb_nbst_poll,
 904         smb_nbst_loan_fp,
 905         smb_nbst_getparam,
 906         smb_nbst_setparam,
 907         smb_nbst_fatal,
 908         {NULL, NULL}
 909 };