Home | History | Annotate | Download | only in netsmb
      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 
     39 #include <sys/param.h>
     40 #include <sys/systm.h>
     41 #include <sys/autoconf.h>
     42 #include <sys/sysmacros.h>
     43 #include <sys/sunddi.h>
     44 #include <sys/kmem.h>
     45 #include <sys/proc.h>
     46 #include <sys/protosw.h>
     47 #include <sys/socket.h>
     48 #include <sys/poll.h>
     49 #include <sys/stream.h>
     50 #include <sys/strsubr.h>
     51 #include <sys/strsun.h>
     52 #include <sys/stropts.h>
     53 #include <sys/cmn_err.h>
     54 #include <sys/tihdr.h>
     55 #include <sys/tiuser.h>
     56 #include <sys/t_kuser.h>
     57 #include <sys/priv.h>
     58 
     59 #include <net/if.h>
     60 #include <net/route.h>
     61 
     62 #include <netinet/in.h>
     63 #include <netinet/tcp.h>
     64 
     65 #include <netsmb/smb_osdep.h>
     66 #include <netsmb/mchain.h>
     67 #include <netsmb/netbios.h>
     68 
     69 #include <netsmb/smb.h>
     70 #include <netsmb/smb_conn.h>
     71 #include <netsmb/smb_subr.h>
     72 #include <netsmb/smb_tran.h>
     73 #include <netsmb/smb_trantcp.h>
     74 
     75 /*
     76  * SMB messages are up to 64K.
     77  * Let's leave room for two.
     78  */
     79 static int smb_tcpsndbuf = 0x20000;
     80 static int smb_tcprcvbuf = 0x20000;
     81 
     82 static int  nbssn_recv(struct nbpcb *nbp, mblk_t **mpp, int *lenp,
     83 	uint8_t *rpcodep);
     84 static int  nb_disconnect(struct nbpcb *nbp);
     85 
     86 
     87 /*
     88  * Get mblks into *mpp until the data length is at least mlen.
     89  * Note that *mpp may already contain a fragment.
     90  *
     91  * If we ever have to wait more than 15 sec. to read a message,
     92  * return ETIME.  (Caller will declare the VD dead.)
     93  */
     94 static int
     95 nb_getmsg_mlen(struct nbpcb *nbp, mblk_t **mpp, size_t mlen)
     96 {
     97 	mblk_t *im, *tm;
     98 	union T_primitives	*pptr;
     99 	size_t dlen;
    100 	int events, fmode, timo, waitflg;
    101 	int error = 0;
    102 
    103 	/*
    104 	 * Get the first message (fragment) if
    105 	 * we don't already have a left-over.
    106 	 */
    107 	dlen = msgdsize(*mpp); /* *mpp==null is OK */
    108 	while (dlen < mlen) {
    109 
    110 		/*
    111 		 * I think we still want this to return ETIME
    112 		 * if nothing arrives for SMB_NBTIMO (15) sec.
    113 		 * so we can report "server not responding".
    114 		 * We _could_ just block here now that our
    115 		 * IOD is just a reader.
    116 		 */
    117 #if 1
    118 		/* Wait with timeout... */
    119 		events = 0;
    120 		waitflg = READWAIT;
    121 		timo = SEC_TO_TICK(SMB_NBTIMO);
    122 		error = t_kspoll(nbp->nbp_tiptr, timo, waitflg, &events);
    123 		if (!error && !events)
    124 			error = ETIME;
    125 		if (error)
    126 			break;
    127 		/* file mode for recv is: */
    128 		fmode = FNDELAY; /* non-blocking */
    129 #else
    130 		fmode = 0; /* normal (blocking) */
    131 #endif
    132 
    133 		/* Get some more... */
    134 		tm = NULL;
    135 		error = tli_recv(nbp->nbp_tiptr, &tm, fmode);
    136 		if (error == EAGAIN)
    137 			continue;
    138 		if (error)
    139 			break;
    140 
    141 		/*
    142 		 * Normally get M_DATA messages here,
    143 		 * but have to check for other types.
    144 		 */
    145 		switch (tm->b_datap->db_type) {
    146 		case M_DATA:
    147 			break;
    148 		case M_PROTO:
    149 		case M_PCPROTO:
    150 			/*LINTED*/
    151 			pptr = (union T_primitives *)tm->b_rptr;
    152 			switch (pptr->type) {
    153 			case T_DATA_IND:
    154 				/* remove 1st mblk, keep the rest. */
    155 				im = tm->b_cont;
    156 				tm->b_cont = NULL;
    157 				freeb(tm);
    158 				tm = im;
    159 				break;
    160 			case T_DISCON_IND:
    161 				/* Peer disconnected. */
    162 				NBDEBUG("T_DISCON_IND: reason=%d",
    163 				    pptr->discon_ind.DISCON_reason);
    164 				goto discon;
    165 			case T_ORDREL_IND:
    166 				/* Peer disconnecting. */
    167 				NBDEBUG("T_ORDREL_IND");
    168 				goto discon;
    169 			case T_OK_ACK:
    170 				switch (pptr->ok_ack.CORRECT_prim) {
    171 				case T_DISCON_REQ:
    172 					NBDEBUG("T_OK_ACK/T_DISCON_REQ");
    173 					goto discon;
    174 				default:
    175 					NBDEBUG("T_OK_ACK/prim=%d",
    176 					    pptr->ok_ack.CORRECT_prim);
    177 					goto discon;
    178 				}
    179 			default:
    180 				NBDEBUG("M_PROTO/type=%d", pptr->type);
    181 				goto discon;
    182 			}
    183 			break; /* M_PROTO, M_PCPROTO */
    184 
    185 		default:
    186 			NBDEBUG("unexpected msg type=%d",
    187 			    tm->b_datap->db_type);
    188 			/*FALLTHROUGH*/
    189 discon:
    190 			/*
    191 			 * The connection is no longer usable.
    192 			 * Drop this message and disconnect.
    193 			 *
    194 			 * Note: nb_disconnect only does t_snddis
    195 			 * on the first call, but does important
    196 			 * cleanup and state change on any call.
    197 			 */
    198 			freemsg(tm);
    199 			(void) nb_disconnect(nbp);
    200 			return (ENOTCONN);
    201 		}
    202 
    203 		/*
    204 		 * If we have a data message, append it to
    205 		 * the previous chunk(s) and update dlen
    206 		 */
    207 		if (!tm)
    208 			continue;
    209 		if (*mpp == NULL) {
    210 			*mpp = tm;
    211 		} else {
    212 			/* Append */
    213 			for (im = *mpp; im->b_cont; im = im->b_cont)
    214 				;
    215 			im->b_cont = tm;
    216 		}
    217 		dlen += msgdsize(tm);
    218 	}
    219 
    220 	return (error);
    221 }
    222 
    223 /*
    224  * Send a T_DISCON_REQ (disconnect)
    225  */
    226 static int
    227 nb_snddis(TIUSER *tiptr)
    228 {
    229 	cred_t *cr;
    230 	mblk_t *mp;
    231 	struct T_discon_req *dreq;
    232 	int error, fmode, mlen;
    233 
    234 	cr = ddi_get_cred();
    235 	mlen = sizeof (struct T_discon_req);
    236 	if (!(mp = allocb_cred_wait(mlen, STR_NOSIG, &error, cr, NOPID)))
    237 		return (error);
    238 
    239 	mp->b_datap->db_type = M_PROTO;
    240 	/*LINTED*/
    241 	dreq = (struct T_discon_req *)mp->b_wptr;
    242 	dreq->PRIM_type = T_DISCON_REQ;
    243 	dreq->SEQ_number = -1;
    244 	mp->b_wptr += sizeof (struct T_discon_req);
    245 
    246 	fmode = tiptr->fp->f_flag;
    247 	if ((error = tli_send(tiptr, mp, fmode)) != 0)
    248 		return (error);
    249 
    250 	fmode = 0; /* need to block */
    251 	error = get_ok_ack(tiptr, T_DISCON_REQ, fmode);
    252 
    253 	return (error);
    254 }
    255 
    256 /*
    257  * Stuff the NetBIOS header into space already prepended.
    258  */
    259 static void
    260 nb_sethdr(mblk_t *m, uint8_t type, uint32_t len)
    261 {
    262 	uint32_t *p;
    263 
    264 	len &= 0x1FFFF;
    265 	len |= (type << 24);
    266 
    267 	/*LINTED*/
    268 	p = (uint32_t *)m->b_rptr;
    269 	*p = htonl(len);
    270 }
    271 
    272 /*
    273  * Wait for up to 15 sec. for the next packet.
    274  * Often return ETIME and do nothing else.
    275  * When a packet header is available, check
    276  * the header and get the length, but don't
    277  * consume it.  No side effects here except
    278  * for the pullupmsg call.
    279  */
    280 static int
    281 nbssn_peekhdr(struct nbpcb *nbp, size_t *lenp,	uint8_t *rpcodep)
    282 {
    283 	uint32_t len, *hdr;
    284 	int error;
    285 
    286 	/*
    287 	 * Get the first message (fragment) if
    288 	 * we don't already have a left-over.
    289 	 */
    290 	error = nb_getmsg_mlen(nbp, &nbp->nbp_frag, sizeof (len));
    291 	if (error)
    292 		return (error);
    293 
    294 	if (!pullupmsg(nbp->nbp_frag, sizeof (len)))
    295 		return (ENOSR);
    296 
    297 	/*
    298 	 * Check the NetBIOS header.
    299 	 * (NOT consumed here)
    300 	 */
    301 	/*LINTED*/
    302 	hdr = (uint32_t *)nbp->nbp_frag->b_rptr;
    303 
    304 	len = ntohl(*hdr);
    305 	if ((len >> 16) & 0xFE) {
    306 		NBDEBUG("bad nb header received 0x%x (MBZ flag set)\n", len);
    307 		return (EPIPE);
    308 	}
    309 	*rpcodep = (len >> 24) & 0xFF;
    310 	switch (*rpcodep) {
    311 	case NB_SSN_MESSAGE:
    312 	case NB_SSN_REQUEST:
    313 	case NB_SSN_POSRESP:
    314 	case NB_SSN_NEGRESP:
    315 	case NB_SSN_RTGRESP:
    316 	case NB_SSN_KEEPALIVE:
    317 		break;
    318 	default:
    319 		NBDEBUG("bad nb header received 0x%x (bogus type)\n", len);
    320 		return (EPIPE);
    321 	}
    322 	len &= 0x1ffff;
    323 	if (len > NB_MAXPKTLEN) {
    324 		NBDEBUG("packet too long (%d)\n", len);
    325 		return (EFBIG);
    326 	}
    327 	*lenp = len;
    328 	return (0);
    329 }
    330 
    331 /*
    332  * Receive a NetBIOS message.  This may block to wait for the entire
    333  * message to arrive.  The caller knows there is (or should be) a
    334  * message to be read.  When we receive and drop a keepalive or
    335  * zero-length message, return EAGAIN so the caller knows that
    336  * something was received.  This avoids false triggering of the
    337  * "server not responding" state machine.
    338  */
    339 /*ARGSUSED*/
    340 static int
    341 nbssn_recv(struct nbpcb *nbp, mblk_t **mpp, int *lenp,
    342     uint8_t *rpcodep)
    343 {
    344 	TIUSER *tiptr = nbp->nbp_tiptr;
    345 	mblk_t *m0;
    346 	uint8_t rpcode;
    347 	int error;
    348 	size_t rlen, len;
    349 
    350 	/* We should be the only reader. */
    351 	ASSERT(nbp->nbp_flags & NBF_RECVLOCK);
    352 	if ((nbp->nbp_flags & NBF_CONNECTED) == 0)
    353 		return (ENOTCONN);
    354 
    355 	if (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 /*ARGSUSED*/
    480 static int
    481 smb_nbst_create(struct smb_vc *vcp, cred_t *cr)
    482 {
    483 	struct nbpcb *nbp;
    484 
    485 	nbp = kmem_zalloc(sizeof (struct nbpcb), KM_SLEEP);
    486 
    487 	nbp->nbp_timo.tv_sec = SMB_NBTIMO;
    488 	nbp->nbp_state = NBST_CLOSED; /* really IDLE */
    489 	nbp->nbp_vc = vcp;
    490 	nbp->nbp_sndbuf = smb_tcpsndbuf;
    491 	nbp->nbp_rcvbuf = smb_tcprcvbuf;
    492 	mutex_init(&nbp->nbp_lock, NULL, MUTEX_DRIVER, NULL);
    493 	vcp->vc_tdata = nbp;
    494 
    495 	return (0);
    496 }
    497 
    498 /*ARGSUSED*/
    499 static int
    500 smb_nbst_done(struct smb_vc *vcp)
    501 {
    502 	struct nbpcb *nbp = vcp->vc_tdata;
    503 
    504 	if (nbp == NULL)
    505 		return (ENOTCONN);
    506 	vcp->vc_tdata = NULL;
    507 
    508 	/*
    509 	 * Don't really need to disconnect here,
    510 	 * because the close following will do it.
    511 	 * But it's harmless.
    512 	 */
    513 	if (nbp->nbp_flags & NBF_CONNECTED)
    514 		(void) nb_disconnect(nbp);
    515 	if (nbp->nbp_tiptr)
    516 		(void) t_kclose(nbp->nbp_tiptr, 0);
    517 	if (nbp->nbp_laddr)
    518 		smb_free_sockaddr((struct sockaddr *)nbp->nbp_laddr);
    519 	if (nbp->nbp_paddr)
    520 		smb_free_sockaddr((struct sockaddr *)nbp->nbp_paddr);
    521 	mutex_destroy(&nbp->nbp_lock);
    522 	kmem_free(nbp, sizeof (*nbp));
    523 	return (0);
    524 }
    525 
    526 static int
    527 smb_nbst_loan_fp(struct smb_vc *vcp, struct file *fp, cred_t *cr)
    528 {
    529 	struct nbpcb *nbp = vcp->vc_tdata;
    530 	TIUSER *tiptr;
    531 	int error = 0;
    532 
    533 	mutex_enter(&nbp->nbp_lock);
    534 
    535 	/*
    536 	 * Un-loan the existing one, if any.
    537 	 */
    538 	if (nbp->nbp_tiptr != NULL) {
    539 		(void) t_kclose(nbp->nbp_tiptr, 0);
    540 		nbp->nbp_tiptr = NULL;
    541 		nbp->nbp_flags &= ~NBF_CONNECTED;
    542 		nbp->nbp_state = NBST_CLOSED;
    543 	}
    544 
    545 	/*
    546 	 * Loan the new one passed in.
    547 	 */
    548 	if (fp != NULL && 0 == (error =
    549 	    t_kopen(fp, 0, 0, &tiptr, cr))) {
    550 		nbp->nbp_tiptr = tiptr;
    551 		nbp->nbp_fmode = tiptr->fp->f_flag;
    552 		nbp->nbp_flags |= NBF_CONNECTED;
    553 		nbp->nbp_state = NBST_SESSION;
    554 	}
    555 
    556 	mutex_exit(&nbp->nbp_lock);
    557 
    558 	return (error);
    559 }
    560 
    561 /*ARGSUSED*/
    562 static int
    563 smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap)
    564 {
    565 	return (ENOTSUP);
    566 }
    567 
    568 /*ARGSUSED*/
    569 static int
    570 smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap)
    571 {
    572 	return (ENOTSUP);
    573 }
    574 
    575 /*ARGSUSED*/
    576 static int
    577 smb_nbst_disconnect(struct smb_vc *vcp)
    578 {
    579 	struct nbpcb *nbp = vcp->vc_tdata;
    580 
    581 	if (nbp == NULL)
    582 		return (ENOTCONN);
    583 
    584 	return (nb_disconnect(nbp));
    585 }
    586 
    587 static int
    588 nb_disconnect(struct nbpcb *nbp)
    589 {
    590 	TIUSER *tiptr;
    591 	int save_flags;
    592 	int err = 0;
    593 
    594 	tiptr = nbp->nbp_tiptr;
    595 	if (tiptr == NULL)
    596 		return (EBADF);
    597 
    598 	mutex_enter(&nbp->nbp_lock);
    599 	save_flags = nbp->nbp_flags;
    600 	nbp->nbp_flags &= ~NBF_CONNECTED;
    601 	if (nbp->nbp_frag) {
    602 		freemsg(nbp->nbp_frag);
    603 		nbp->nbp_frag = NULL;
    604 	}
    605 	mutex_exit(&nbp->nbp_lock);
    606 
    607 	if (save_flags & NBF_CONNECTED)
    608 		err = nb_snddis(tiptr);
    609 
    610 	if (nbp->nbp_state != NBST_RETARGET) {
    611 		nbp->nbp_state = NBST_CLOSED;
    612 	}
    613 
    614 	return (err);
    615 }
    616 
    617 /*
    618  * Always consume the message.
    619  * (On error too!)
    620  */
    621 /*ARGSUSED*/
    622 static int
    623 smb_nbst_send(struct smb_vc *vcp, mblk_t *m)
    624 {
    625 	struct nbpcb *nbp = vcp->vc_tdata;
    626 	ptrdiff_t diff;
    627 	uint32_t mlen;
    628 	int error;
    629 
    630 	if (nbp == NULL || nbp->nbp_tiptr == NULL) {
    631 		error = EBADF;
    632 		goto errout;
    633 	}
    634 
    635 	/*
    636 	 * Get the message length, which
    637 	 * does NOT include the NetBIOS header
    638 	 */
    639 	mlen = msgdsize(m);
    640 
    641 	/*
    642 	 * Normally, mb_init() will have left space
    643 	 * for us to prepend the NetBIOS header in
    644 	 * the data block of the first mblk.
    645 	 * However, we have to check in case other
    646 	 * code did not leave this space, or if the
    647 	 * message is from dupmsg (db_ref > 1)
    648 	 *
    649 	 * If don't find room in the first data block,
    650 	 * we have to allocb a new message and link it
    651 	 * on the front of the chain.  We try not to
    652 	 * do this becuase it's less efficient.  Also,
    653 	 * some network drivers will apparently send
    654 	 * each mblk in the chain as separate frames.
    655 	 * (That's arguably a driver bug.)
    656 	 *
    657 	 * Not bothering with allocb_cred_wait below
    658 	 * because the message we're prepending to
    659 	 * should already have a db_credp.
    660 	 */
    661 
    662 	diff = MBLKHEAD(m);
    663 	if (diff == 4 && DB_REF(m) == 1) {
    664 		/* We can use the first dblk. */
    665 		m->b_rptr -= 4;
    666 	} else {
    667 		/* Link a new mblk on the head. */
    668 		mblk_t *m0;
    669 
    670 		/* M_PREPEND */
    671 		m0 = allocb_wait(4, BPRI_LO, STR_NOSIG, &error);
    672 		if (!m0)
    673 			goto errout;
    674 
    675 		m0->b_wptr += 4;
    676 		m0->b_cont = m;
    677 		m = m0;
    678 	}
    679 
    680 	nb_sethdr(m, NB_SSN_MESSAGE, mlen);
    681 	error = tli_send(nbp->nbp_tiptr, m, 0);
    682 	return (error);
    683 
    684 errout:
    685 	if (m)
    686 		m_freem(m);
    687 	return (error);
    688 }
    689 
    690 static int
    691 smb_nbst_recv(struct smb_vc *vcp, mblk_t **mpp)
    692 {
    693 	struct nbpcb *nbp = vcp->vc_tdata;
    694 	uint8_t rpcode;
    695 	int error, rplen;
    696 
    697 	mutex_enter(&nbp->nbp_lock);
    698 	if (nbp->nbp_flags & NBF_RECVLOCK) {
    699 		NBDEBUG("attempt to reenter session layer!\n");
    700 		mutex_exit(&nbp->nbp_lock);
    701 		return (EWOULDBLOCK);
    702 	}
    703 	nbp->nbp_flags |= NBF_RECVLOCK;
    704 	mutex_exit(&nbp->nbp_lock);
    705 	error = nbssn_recv(nbp, mpp, &rplen, &rpcode);
    706 	mutex_enter(&nbp->nbp_lock);
    707 	nbp->nbp_flags &= ~NBF_RECVLOCK;
    708 	mutex_exit(&nbp->nbp_lock);
    709 	return (error);
    710 }
    711 
    712 /*
    713  * Wait for up to "ticks" clock ticks for input on vcp.
    714  * Returns zero if input is available, otherwise ETIME
    715  * indicating time expired, or other error codes.
    716  */
    717 /*ARGSUSED*/
    718 static int
    719 smb_nbst_poll(struct smb_vc *vcp, int ticks)
    720 {
    721 	int error;
    722 	int events = 0;
    723 	int waitflg = READWAIT;
    724 	struct nbpcb *nbp = vcp->vc_tdata;
    725 
    726 	error = t_kspoll(nbp->nbp_tiptr, ticks, waitflg, &events);
    727 	if (!error && !events)
    728 		error = ETIME;
    729 
    730 	return (error);
    731 }
    732 
    733 static int
    734 smb_nbst_getparam(struct smb_vc *vcp, int param, void *data)
    735 {
    736 	struct nbpcb *nbp = vcp->vc_tdata;
    737 
    738 	switch (param) {
    739 	case SMBTP_SNDSZ:
    740 		*(int *)data = nbp->nbp_sndbuf;
    741 		break;
    742 	case SMBTP_RCVSZ:
    743 		*(int *)data = nbp->nbp_rcvbuf;
    744 		break;
    745 	case SMBTP_TIMEOUT:
    746 		*(struct timespec *)data = nbp->nbp_timo;
    747 		break;
    748 #ifdef SMBTP_SELECTID
    749 	case SMBTP_SELECTID:
    750 		*(void **)data = nbp->nbp_selectid;
    751 		break;
    752 #endif
    753 #ifdef SMBTP_UPCALL
    754 	case SMBTP_UPCALL:
    755 		*(void **)data = nbp->nbp_upcall;
    756 		break;
    757 #endif
    758 	default:
    759 		return (EINVAL);
    760 	}
    761 	return (0);
    762 }
    763 
    764 /*ARGSUSED*/
    765 static int
    766 smb_nbst_setparam(struct smb_vc *vcp, int param, void *data)
    767 {
    768 	return (EINVAL);
    769 }
    770 
    771 /*
    772  * Check for fatal errors
    773  */
    774 /*ARGSUSED*/
    775 static int
    776 smb_nbst_fatal(struct smb_vc *vcp, int error)
    777 {
    778 	switch (error) {
    779 	case ENOTCONN:
    780 	case ENETRESET:
    781 	case ECONNABORTED:
    782 	case EPIPE:
    783 		return (1);
    784 	}
    785 	return (0);
    786 }
    787 
    788 
    789 struct smb_tran_desc smb_tran_nbtcp_desc = {
    790 	SMBT_NBTCP,
    791 	smb_nbst_create,
    792 	smb_nbst_done,
    793 	smb_nbst_bind,
    794 	smb_nbst_connect,
    795 	smb_nbst_disconnect,
    796 	smb_nbst_send,
    797 	smb_nbst_recv,
    798 	smb_nbst_poll,
    799 	smb_nbst_loan_fp,
    800 	smb_nbst_getparam,
    801 	smb_nbst_setparam,
    802 	smb_nbst_fatal,
    803 	{NULL, NULL}
    804 };
    805