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