8592 ZFS channel programs - rollback
[unleashed.git] / usr / src / uts / common / fs / smbclnt / netsmb / smb_trantcp.c
blob4f101a4f5f71e0d711410edfd54bea8134e2acad
1 /*
2 * Copyright (c) 2000-2001 Boris Popov
3 * All rights reserved.
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.
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.
32 * $Id: smb_trantcp.c,v 1.39 2005/03/02 01:27:44 lindak Exp $
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.
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>
60 #include <net/if.h>
61 #include <net/route.h>
63 #include <netinet/in.h>
64 #include <netinet/tcp.h>
66 #include <netsmb/smb_osdep.h>
67 #include <netsmb/mchain.h>
68 #include <netsmb/netbios.h>
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>
77 * SMB messages are up to 64K.
78 * Let's leave room for two.
80 static int smb_tcpsndbuf = 0x20000;
81 static int smb_tcprcvbuf = 0x20000;
83 static int nb_disconnect(struct nbpcb *nbp);
87 * Get mblks into *mpp until the data length is at least mlen.
88 * Note that *mpp may already contain a fragment.
90 * If we ever have to wait more than 15 sec. to read a message,
91 * return ETIME. (Caller will declare the VD dead.)
93 static int
94 nb_getmsg_mlen(struct nbpcb *nbp, mblk_t **mpp, size_t mlen)
96 mblk_t *im, *tm;
97 union T_primitives *pptr;
98 size_t dlen;
99 int events, fmode, timo, waitflg;
100 int error = 0;
102 /* We should be the only reader. */
103 ASSERT(nbp->nbp_flags & NBF_RECVLOCK);
104 /* nbp->nbp_tiptr checked by caller */
107 * Get the first message (fragment) if
108 * we don't already have a left-over.
110 dlen = msgdsize(*mpp); /* *mpp==null is OK */
111 while (dlen < mlen) {
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.
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
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;
145 * Normally get M_DATA messages here,
146 * but have to check for other types.
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;
182 default:
183 NBDEBUG("M_PROTO/type=%d", pptr->type);
184 goto discon;
186 break; /* M_PROTO, M_PCPROTO */
188 default:
189 NBDEBUG("unexpected msg type=%d",
190 tm->b_datap->db_type);
191 /*FALLTHROUGH*/
192 discon:
194 * The connection is no longer usable.
195 * Drop this message and disconnect.
197 * Note: nb_disconnect only does t_snddis
198 * on the first call, but does important
199 * cleanup and state change on any call.
201 freemsg(tm);
202 (void) nb_disconnect(nbp);
203 return (ENOTCONN);
207 * If we have a data message, append it to
208 * the previous chunk(s) and update dlen
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)
218 im->b_cont = tm;
220 dlen += msgdsize(tm);
223 return (error);
227 * Send a T_DISCON_REQ (disconnect)
229 static int
230 nb_snddis(struct nbpcb *nbp)
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;
238 ASSERT(MUTEX_HELD(&nbp->nbp_lock));
240 if (tiptr == NULL)
241 return (EBADF);
243 mlen = sizeof (struct T_discon_req);
244 if (!(mp = allocb_cred_wait(mlen, STR_NOSIG, &error, cr, NOPID)))
245 return (error);
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);
254 error = tli_send(tiptr, mp, tiptr->fp->f_flag);
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.
261 return (error);
265 * Stuff the NetBIOS header into space already prepended.
267 static void
268 nb_sethdr(mblk_t *m, uint8_t type, uint32_t len)
270 uint32_t *p;
272 len &= 0x1FFFF;
273 len |= (type << 24);
275 /*LINTED*/
276 p = (uint32_t *)m->b_rptr;
277 *p = htonl(len);
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.
288 static int
289 nbssn_peekhdr(struct nbpcb *nbp, size_t *lenp, uint8_t *rpcodep)
291 uint32_t len, *hdr;
292 int error;
295 * Get the first message (fragment) if
296 * we don't already have a left-over.
298 error = nb_getmsg_mlen(nbp, &nbp->nbp_frag, sizeof (len));
299 if (error)
300 return (error);
302 if (!pullupmsg(nbp->nbp_frag, sizeof (len)))
303 return (ENOSR);
306 * Check the NetBIOS header.
307 * (NOT consumed here)
309 /*LINTED*/
310 hdr = (uint32_t *)nbp->nbp_frag->b_rptr;
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);
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);
330 len &= 0x1ffff;
331 if (len > NB_MAXPKTLEN) {
332 NBDEBUG("packet too long (%d)\n", len);
333 return (EFBIG);
335 *lenp = len;
336 return (0);
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.
347 * Calls to this are serialized at a higher level.
349 static int
350 nbssn_recv(struct nbpcb *nbp, mblk_t **mpp, int *lenp,
351 uint8_t *rpcodep)
353 mblk_t *m0;
354 uint8_t rpcode;
355 int error;
356 size_t rlen, len;
358 /* We should be the only reader. */
359 ASSERT(nbp->nbp_flags & NBF_RECVLOCK);
361 if (nbp->nbp_tiptr == NULL)
362 return (EBADF);
363 if (mpp) {
364 if (*mpp) {
365 NBDEBUG("*mpp not 0 - leak?");
367 *mpp = NULL;
369 m0 = NULL;
372 * Get the NetBIOS header (not consumed yet)
374 error = nbssn_peekhdr(nbp, &len, &rpcode);
375 if (error) {
376 if (error != ETIME)
377 NBDEBUG("peekhdr, error=%d\n", error);
378 return (error);
380 NBDEBUG("Have pkt, type=0x%x len=0x%x\n",
381 (int)rpcode, (int)len);
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.
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);
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.
401 m0 = nbp->nbp_frag;
402 m0->b_rptr += 4;
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.
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);
415 if (nbp->nbp_state != NBST_SESSION) {
417 * No session is established.
418 * Return whatever packet we got.
420 goto out;
424 * A session is established; the only packets
425 * we should see are session message and
426 * keep-alive packets. Drop anything else.
428 switch (rpcode) {
430 case NB_SSN_KEEPALIVE:
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)
436 if (len)
437 NBDEBUG("Keepalive with data %d\n", (int)len);
438 error = EAGAIN;
439 break;
441 case NB_SSN_MESSAGE:
443 * Session message. Does it have any data?
445 if (len == 0) {
447 * No data - treat as keepalive (drop).
449 error = EAGAIN;
450 break;
453 * Yes, has data. Return it.
455 error = 0;
456 break;
458 default:
460 * Drop anything else.
462 NBDEBUG("non-session packet %x\n", rpcode);
463 error = EAGAIN;
464 break;
467 out:
468 if (error) {
469 if (m0)
470 m_freem(m0);
471 return (error);
473 if (mpp)
474 *mpp = m0;
475 else
476 m_freem(m0);
477 *lenp = (int)len;
478 *rpcodep = rpcode;
479 return (0);
483 * SMB transport interface
485 * This is called only by the thread creating this endpoint,
486 * so we're single-threaded here.
488 /*ARGSUSED*/
489 static int
490 smb_nbst_create(struct smb_vc *vcp, cred_t *cr)
492 struct nbpcb *nbp;
494 nbp = kmem_zalloc(sizeof (struct nbpcb), KM_SLEEP);
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;
506 return (0);
510 * destroy a transport endpoint
512 * This is called only by the thread with the last reference
513 * to this endpoint, so we're single-threaded here.
515 static int
516 smb_nbst_done(struct smb_vc *vcp)
518 struct nbpcb *nbp = vcp->vc_tdata;
520 if (nbp == NULL)
521 return (ENOTCONN);
522 vcp->vc_tdata = NULL;
525 * Don't really need to disconnect here,
526 * because the close following will do it.
527 * But it's harmless.
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);
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.
549 static int
550 nb_loan_fp(struct nbpcb *nbp, struct file *fp, cred_t *cr)
552 TIUSER *tiptr;
553 int err;
555 err = t_kopen(fp, 0, 0, &tiptr, cr);
556 if (err != 0)
557 return (err);
559 mutex_enter(&nbp->nbp_lock);
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;
566 mutex_exit(&nbp->nbp_lock);
568 return (0);
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.
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.
588 static void
589 nb_unloan_fp(struct nbpcb *nbp)
592 mutex_enter(&nbp->nbp_lock);
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);
599 if (nbp->nbp_frag != NULL) {
600 freemsg(nbp->nbp_frag);
601 nbp->nbp_frag = NULL;
603 if (nbp->nbp_tiptr != NULL) {
604 (void) t_kclose(nbp->nbp_tiptr, 0);
605 nbp->nbp_tiptr = NULL;
607 nbp->nbp_state = NBST_CLOSED;
609 mutex_exit(&nbp->nbp_lock);
612 static int
613 smb_nbst_loan_fp(struct smb_vc *vcp, struct file *fp, cred_t *cr)
615 struct nbpcb *nbp = vcp->vc_tdata;
616 int error = 0;
619 * Un-loan the existing one, if any.
621 (void) nb_disconnect(nbp);
622 nb_unloan_fp(nbp);
625 * Loan the new one passed in.
627 if (fp != NULL) {
628 error = nb_loan_fp(nbp, fp, cr);
631 return (error);
634 /*ARGSUSED*/
635 static int
636 smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap)
638 return (ENOTSUP);
641 /*ARGSUSED*/
642 static int
643 smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap)
645 return (ENOTSUP);
648 /*ARGSUSED*/
649 static int
650 smb_nbst_disconnect(struct smb_vc *vcp)
652 struct nbpcb *nbp = vcp->vc_tdata;
654 if (nbp == NULL)
655 return (ENOTCONN);
657 return (nb_disconnect(nbp));
660 static int
661 nb_disconnect(struct nbpcb *nbp)
663 int err = 0;
665 mutex_enter(&nbp->nbp_lock);
667 if ((nbp->nbp_flags & NBF_CONNECTED) != 0) {
668 nbp->nbp_flags &= ~NBF_CONNECTED;
669 err = nb_snddis(nbp);
672 mutex_exit(&nbp->nbp_lock);
673 return (err);
677 * Add the NetBIOS session header and send.
679 * Calls to this are serialized at a higher level.
681 static int
682 nbssn_send(struct nbpcb *nbp, mblk_t *m)
684 ptrdiff_t diff;
685 uint32_t mlen;
686 int error;
688 /* We should be the only sender. */
689 ASSERT(nbp->nbp_flags & NBF_SENDLOCK);
691 if (nbp->nbp_tiptr == NULL) {
692 error = EBADF;
693 goto errout;
697 * Get the message length, which
698 * does NOT include the NetBIOS header
700 mlen = msgdsize(m);
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)
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.)
718 * Not bothering with allocb_cred_wait below
719 * because the message we're prepending to
720 * should already have a db_credp.
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;
731 /* M_PREPEND */
732 m0 = allocb_wait(4, BPRI_LO, STR_NOSIG, &error);
733 if (m0 == NULL)
734 goto errout;
736 m0->b_wptr += 4;
737 m0->b_cont = m;
738 m = m0;
741 nb_sethdr(m, NB_SSN_MESSAGE, mlen);
742 error = tli_send(nbp->nbp_tiptr, m, 0);
743 return (error);
745 errout:
746 if (m != NULL)
747 m_freem(m);
748 return (error);
752 * Always consume the message.
753 * (On error too!)
755 static int
756 smb_nbst_send(struct smb_vc *vcp, mblk_t *m)
758 struct nbpcb *nbp = vcp->vc_tdata;
759 int err;
761 mutex_enter(&nbp->nbp_lock);
762 if ((nbp->nbp_flags & NBF_CONNECTED) == 0) {
763 err = ENOTCONN;
764 goto out;
766 if (nbp->nbp_flags & NBF_SENDLOCK) {
767 NBDEBUG("multiple smb_nbst_send!\n");
768 err = EWOULDBLOCK;
769 goto out;
771 nbp->nbp_flags |= NBF_SENDLOCK;
772 mutex_exit(&nbp->nbp_lock);
774 err = nbssn_send(nbp, m);
775 m = NULL; /* nbssn_send always consumes this */
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);
783 out:
784 mutex_exit(&nbp->nbp_lock);
785 if (m != NULL)
786 m_freem(m);
787 return (err);
790 static int
791 smb_nbst_recv(struct smb_vc *vcp, mblk_t **mpp)
793 struct nbpcb *nbp = vcp->vc_tdata;
794 uint8_t rpcode;
795 int err, rplen;
797 mutex_enter(&nbp->nbp_lock);
798 if ((nbp->nbp_flags & NBF_CONNECTED) == 0) {
799 err = ENOTCONN;
800 goto out;
802 if (nbp->nbp_flags & NBF_RECVLOCK) {
803 NBDEBUG("multiple smb_nbst_recv!\n");
804 err = EWOULDBLOCK;
805 goto out;
807 nbp->nbp_flags |= NBF_RECVLOCK;
808 mutex_exit(&nbp->nbp_lock);
810 err = nbssn_recv(nbp, mpp, &rplen, &rpcode);
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);
818 out:
819 mutex_exit(&nbp->nbp_lock);
820 return (err);
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.
828 /*ARGSUSED*/
829 static int
830 smb_nbst_poll(struct smb_vc *vcp, int ticks)
832 return (ENOTSUP);
835 static int
836 smb_nbst_getparam(struct smb_vc *vcp, int param, void *data)
838 struct nbpcb *nbp = vcp->vc_tdata;
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);
863 return (0);
866 /*ARGSUSED*/
867 static int
868 smb_nbst_setparam(struct smb_vc *vcp, int param, void *data)
870 return (EINVAL);
874 * Check for fatal errors
876 /*ARGSUSED*/
877 static int
878 smb_nbst_fatal(struct smb_vc *vcp, int error)
880 switch (error) {
881 case ENOTCONN:
882 case ENETRESET:
883 case ECONNABORTED:
884 case EPIPE:
885 return (1);
887 return (0);
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}