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
nb_getmsg_mlen(struct nbpcb * nbp,mblk_t ** mpp,size_t mlen)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
nb_snddis(TIUSER * tiptr)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
nb_sethdr(mblk_t * m,uint8_t type,uint32_t len)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
nbssn_peekhdr(struct nbpcb * nbp,size_t * lenp,uint8_t * rpcodep)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
nbssn_recv(struct nbpcb * nbp,mblk_t ** mpp,int * lenp,uint8_t * rpcodep)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
smb_nbst_create(struct smb_vc * vcp,cred_t * cr)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
smb_nbst_done(struct smb_vc * vcp)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
smb_nbst_loan_fp(struct smb_vc * vcp,struct file * fp,cred_t * cr)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
smb_nbst_bind(struct smb_vc * vcp,struct sockaddr * sap)563 smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap)
564 {
565 return (ENOTSUP);
566 }
567
568 /*ARGSUSED*/
569 static int
smb_nbst_connect(struct smb_vc * vcp,struct sockaddr * sap)570 smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap)
571 {
572 return (ENOTSUP);
573 }
574
575 /*ARGSUSED*/
576 static int
smb_nbst_disconnect(struct smb_vc * vcp)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
nb_disconnect(struct nbpcb * nbp)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
smb_nbst_send(struct smb_vc * vcp,mblk_t * m)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
smb_nbst_recv(struct smb_vc * vcp,mblk_t ** mpp)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
smb_nbst_poll(struct smb_vc * vcp,int ticks)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
smb_nbst_getparam(struct smb_vc * vcp,int param,void * data)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
smb_nbst_setparam(struct smb_vc * vcp,int param,void * data)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
smb_nbst_fatal(struct smb_vc * vcp,int error)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