compat linux32 syscalls cleanup.
[netbsd-mini2440.git] / sys / netsmb / smb_trantcp.c
blobab4325e31f18e0813fe957d2fd384a553a1bd364
1 /* $NetBSD: smb_trantcp.c,v 1.30 2007/07/09 21:11:15 ad Exp $ */
3 /*
4 * Copyright (c) 2000-2001 Boris Popov
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Boris Popov.
18 * 4. Neither the name of the author nor the names of any co-contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
34 * FreeBSD: src/sys/netsmb/smb_trantcp.c,v 1.17 2003/02/19 05:47:38 imp Exp
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: smb_trantcp.c,v 1.30 2007/07/09 21:11:15 ad Exp $");
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/kernel.h>
43 #include <sys/malloc.h>
44 #include <sys/mbuf.h>
45 #include <sys/proc.h>
46 #include <sys/protosw.h>
47 #include <sys/socket.h>
48 #include <sys/socketvar.h>
49 #include <sys/poll.h>
50 #include <sys/uio.h>
51 #include <sys/sysctl.h>
53 #include <net/if.h>
54 #include <net/route.h>
56 #include <netinet/in.h>
57 #include <netinet/tcp.h>
59 #include <netsmb/mchain.h>
61 #include <netsmb/netbios.h>
63 #include <netsmb/smb.h>
64 #include <netsmb/smb_conn.h>
65 #include <netsmb/smb_tran.h>
66 #include <netsmb/smb_trantcp.h>
67 #include <netsmb/smb_subr.h>
69 #define M_NBDATA M_PCB
71 static int nb_tcpsndbuf = NB_SNDQ;
72 static int nb_tcprcvbuf = NB_RCVQ;
73 static const struct timeval nb_timo = { 15, 0 }; /* XXX sysctl? */
75 #ifndef __NetBSD__
76 SYSCTL_DECL(_net_smb);
77 SYSCTL_INT(_net_smb, OID_AUTO, tcpsndbuf, CTLFLAG_RW, &nb_tcpsndbuf, 0, "");
78 SYSCTL_INT(_net_smb, OID_AUTO, tcprcvbuf, CTLFLAG_RW, &nb_tcprcvbuf, 0, "");
79 #endif
81 #ifndef __NetBSD__
82 #define nb_sosend(so,m,flags,p) (so)->so_proto->pr_usrreqs->pru_sosend( \
83 so, NULL, 0, m, 0, flags, p)
84 #else
85 #define nb_sosend(so,m,flags,l) (*(so)->so_send)(so, NULL, (struct uio *)0, \
86 m, (struct mbuf *)0, flags, l)
87 #endif
89 static int nbssn_recv(struct nbpcb *nbp, struct mbuf **mpp, int *lenp,
90 u_int8_t *rpcodep, struct lwp *l);
91 static int smb_nbst_disconnect(struct smb_vc *vcp, struct lwp *l);
93 static int
94 nb_setsockopt_int(struct socket *so, int level, int name, int val)
96 #ifdef __NetBSD__
97 return sosetopt(so, level, name, NULL); /* XXX */
98 #else
99 struct sockopt sopt;
101 bzero(&sopt, sizeof(sopt));
102 sopt.sopt_level = level;
103 sopt.sopt_name = name;
104 sopt.sopt_val = &val;
105 sopt.sopt_valsize = sizeof(val);
106 return sosetopt(so, &sopt);
107 #endif
110 static inline int
111 nb_poll(struct nbpcb *nbp, int events, struct lwp *l)
113 #ifndef __NetBSD__
114 return nbp->nbp_tso->so_proto->pr_usrreqs->pru_sopoll(nbp->nbp_tso,
115 events, NULL, l);
116 #else
117 /* XXX this is exactly equal to soo_poll() */
118 struct socket *so = nbp->nbp_tso;
119 int revents = 0;
120 int s = splsoftnet();
122 if (events & (POLLIN | POLLRDNORM))
123 if (soreadable(so))
124 revents |= events & (POLLIN | POLLRDNORM);
126 if (events & (POLLOUT | POLLWRNORM))
127 if (sowritable(so))
128 revents |= events & (POLLOUT | POLLWRNORM);
130 if (events & (POLLPRI | POLLRDBAND))
131 if (so->so_oobmark || (so->so_state & SS_RCVATMARK))
132 revents |= events & (POLLPRI | POLLRDBAND);
134 if (revents == 0) {
135 if (events & (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)) {
136 selrecord(l, &so->so_rcv.sb_sel);
137 so->so_rcv.sb_flags |= SB_SEL;
140 if (events & (POLLOUT | POLLWRNORM)) {
141 selrecord(l, &so->so_snd.sb_sel);
142 so->so_snd.sb_flags |= SB_SEL;
146 splx(s);
147 return (revents);
148 #endif
151 /* XXX WTF re-implemented select()? */
152 static int
153 nbssn_rselect(struct nbpcb *nbp, const struct timeval *tv, int events,
154 struct lwp *l)
156 extern kcondvar_t select_cv;
157 extern kmutex_t select_lock;
158 struct timeval atv;
159 extern int nselcoll;
160 int ncoll;
161 int timo, error;
163 if (tv) {
164 atv = *tv;
165 if (itimerfix(&atv))
166 return (EINVAL);
167 timo = tvtohz(&atv);
168 if (timo <= 0)
169 return (EWOULDBLOCK);
170 } else
171 timo = 0;
173 mutex_enter(&select_lock);
174 retry:
175 ncoll = nselcoll;
176 l->l_selflag = 1;
177 mutex_exit(&select_lock);
178 error = nb_poll(nbp, events, l);
179 mutex_enter(&select_lock);
180 if (error) {
181 error = 0;
182 goto done;
184 if (tv) {
186 * We have to recalculate the timeout on every retry.
188 timo = tvtohz(&atv);
189 if (timo <= 0) {
190 error = EWOULDBLOCK;
191 goto done;
195 if (l->l_selflag != 1 || nselcoll != ncoll)
196 goto retry;
197 l->l_selflag = 2;
198 error = cv_timedwait(&select_cv, &select_lock, timo);
199 if (error == 0)
200 goto retry;
202 done:
203 l->l_selflag = 0;
204 mutex_exit(&select_lock);
205 /* select is not restarted after signals... */
206 if (error == ERESTART)
207 error = 0;
208 return (error);
211 static int
212 nb_intr(struct nbpcb *nbp, struct lwp *l)
214 return 0;
217 static void
218 nb_upcall(struct socket *so, void *arg, int waitflag)
220 struct nbpcb *nbp = (void *)arg;
222 if (arg == NULL || nbp->nbp_selectid == NULL)
223 return;
224 wakeup(nbp->nbp_selectid);
227 static int
228 nb_sethdr(struct mbuf *m, u_int8_t type, u_int32_t len)
230 u_int32_t *p = mtod(m, u_int32_t *);
232 *p = htonl((len & 0x1FFFF) | (type << 24));
233 return 0;
236 static int
237 nb_put_name(struct mbchain *mbp, struct sockaddr_nb *snb)
239 int error;
240 u_char seglen, *cp;
242 cp = snb->snb_name;
243 if (*cp == 0)
244 return EINVAL;
245 NBDEBUG("[%s]\n", cp);
246 for (;;) {
247 seglen = (*cp) + 1;
248 error = mb_put_mem(mbp, cp, seglen, MB_MSYSTEM);
249 if (error)
250 return error;
251 if (seglen == 1)
252 break;
253 cp += seglen;
255 return 0;
258 static int
259 nb_connect_in(struct nbpcb *nbp, struct sockaddr_in *to, struct lwp *l)
261 struct socket *so;
262 int error, s;
263 #ifdef __NetBSD__
264 struct mbuf *m;
265 #endif
267 error = socreate(AF_INET, &so, SOCK_STREAM, IPPROTO_TCP, l);
268 if (error)
269 return error;
270 nbp->nbp_tso = so;
271 so->so_upcallarg = (void *)nbp;
272 so->so_upcall = nb_upcall;
273 so->so_rcv.sb_flags |= SB_UPCALL;
274 so->so_rcv.sb_timeo = NB_SNDTIMEO;
275 so->so_snd.sb_timeo = NB_RCVTIMEO;
276 error = soreserve(so, nb_tcpsndbuf, nb_tcprcvbuf);
277 if (error)
278 goto bad;
279 nb_setsockopt_int(so, SOL_SOCKET, SO_KEEPALIVE, 1);
280 nb_setsockopt_int(so, IPPROTO_TCP, TCP_NODELAY, 1);
281 so->so_rcv.sb_flags &= ~SB_NOINTR;
282 so->so_snd.sb_flags &= ~SB_NOINTR;
283 #ifndef __NetBSD__
284 error = soconnect(so, (struct sockaddr*)to, l);
285 #else
286 m = m_get(M_WAIT, MT_SONAME);
287 *mtod(m, struct sockaddr *) = *(struct sockaddr *)to;
288 m->m_len = sizeof(struct sockaddr);
289 error = soconnect(so, m, l);
290 m_free(m);
291 #endif
292 if (error)
293 goto bad;
294 s = splnet();
295 while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
296 tsleep(&so->so_timeo, PSOCK, "smbcon", 2 * hz);
297 if ((so->so_state & SS_ISCONNECTING) && so->so_error == 0 &&
298 (error = nb_intr(nbp, l)) != 0) {
299 so->so_state &= ~SS_ISCONNECTING;
300 splx(s);
301 goto bad;
304 if (so->so_error) {
305 error = so->so_error;
306 so->so_error = 0;
307 splx(s);
308 goto bad;
310 splx(s);
311 return 0;
312 bad:
313 smb_nbst_disconnect(nbp->nbp_vc, l);
314 return error;
317 static int
318 nbssn_rq_request(struct nbpcb *nbp, struct lwp *l)
320 struct mbchain mb, *mbp = &mb;
321 struct mdchain md, *mdp = &md;
322 struct mbuf *m0;
323 struct sockaddr_in sin;
324 u_short port;
325 u_int8_t rpcode;
326 int error, rplen;
328 error = mb_init(mbp);
329 if (error)
330 return error;
331 mb_put_uint32le(mbp, 0);
332 (void) nb_put_name(mbp, nbp->nbp_paddr);
333 (void) nb_put_name(mbp, nbp->nbp_laddr);
334 nb_sethdr(mbp->mb_top, NB_SSN_REQUEST, mb_fixhdr(mbp) - 4);
335 error = nb_sosend(nbp->nbp_tso, mbp->mb_top, 0, l);
336 if (!error) {
337 nbp->nbp_state = NBST_RQSENT;
339 mb_detach(mbp);
340 mb_done(mbp);
341 if (error)
342 return error;
343 error = nbssn_rselect(nbp, &nb_timo, POLLIN, l);
344 if (error == EWOULDBLOCK) { /* Timeout */
345 NBDEBUG("initial request timeout\n");
346 return ETIMEDOUT;
348 if (error) /* restart or interrupt */
349 return error;
350 error = nbssn_recv(nbp, &m0, &rplen, &rpcode, l);
351 if (error) {
352 NBDEBUG("recv() error %d\n", error);
353 return error;
356 * Process NETBIOS reply
358 if (m0)
359 md_initm(mdp, m0);
360 error = 0;
361 do {
362 if (rpcode == NB_SSN_POSRESP) {
363 nbp->nbp_state = NBST_SESSION;
364 nbp->nbp_flags |= NBF_CONNECTED;
365 break;
367 if (rpcode != NB_SSN_RTGRESP) {
368 error = ECONNABORTED;
369 break;
371 if (rplen != 6) {
372 error = ECONNABORTED;
373 break;
375 md_get_mem(mdp, (void *)&sin.sin_addr, 4, MB_MSYSTEM);
376 md_get_uint16(mdp, &port);
377 sin.sin_port = port;
378 nbp->nbp_state = NBST_RETARGET;
379 smb_nbst_disconnect(nbp->nbp_vc, l);
380 error = nb_connect_in(nbp, &sin, l);
381 if (!error)
382 error = nbssn_rq_request(nbp, l);
383 if (error) {
384 smb_nbst_disconnect(nbp->nbp_vc, l);
385 break;
387 } while(0);
388 if (m0)
389 md_done(mdp);
390 return error;
393 static int
394 nbssn_recvhdr(struct nbpcb *nbp, int *lenp,
395 u_int8_t *rpcodep, int flags, struct lwp *l)
397 struct socket *so = nbp->nbp_tso;
398 struct uio auio;
399 struct iovec aio;
400 u_int32_t len;
401 int error;
403 aio.iov_base = (void *)&len;
404 aio.iov_len = sizeof(len);
405 auio.uio_iov = &aio;
406 auio.uio_iovcnt = 1;
407 auio.uio_rw = UIO_READ;
408 auio.uio_offset = 0;
409 auio.uio_resid = sizeof(len);
410 UIO_SETUP_SYSSPACE(&auio);
411 #ifndef __NetBSD__
412 error = so->so_proto->pr_usrreqs->pru_soreceive
413 (so, (struct sockaddr **)NULL, &auio,
414 (struct mbuf **)NULL, (struct mbuf **)NULL, &flags);
415 #else
416 error = (*so->so_receive)(so, (struct mbuf **)0, &auio,
417 (struct mbuf **)NULL,
418 (struct mbuf **)NULL, &flags);
419 #endif
420 if (error)
421 return error;
422 if (auio.uio_resid > 0) {
423 SMBSDEBUG("short reply\n");
424 return EPIPE;
426 len = ntohl(len);
427 *rpcodep = (len >> 24) & 0xFF;
428 len &= 0x1ffff;
429 if (len > SMB_MAXPKTLEN) {
430 SMBERROR("packet too long (%d)\n", len);
431 return EFBIG;
433 *lenp = len;
434 return 0;
437 static int
438 nbssn_recv(struct nbpcb *nbp, struct mbuf **mpp, int *lenp,
439 u_int8_t *rpcodep, struct lwp *l)
441 struct socket *so = nbp->nbp_tso;
442 struct uio auio;
443 struct mbuf *m, *tm, *im;
444 u_int8_t rpcode;
445 int len, resid;
446 int error, rcvflg;
448 len = 0; /* XXX gcc */
449 rpcode = 0; /* XXX gcc */
451 if (so == NULL)
452 return ENOTCONN;
454 if (mpp)
455 *mpp = NULL;
456 m = NULL;
457 for(;;) {
459 * Poll for a response header.
460 * If we don't have one waiting, return.
462 error = nbssn_recvhdr(nbp, &len, &rpcode, MSG_DONTWAIT, l);
463 if (so->so_state &
464 (SS_ISDISCONNECTING | SS_ISDISCONNECTED | SS_CANTRCVMORE)) {
465 nbp->nbp_state = NBST_CLOSED;
466 NBDEBUG("session closed by peer\n");
467 return ECONNRESET;
469 if (error)
470 return error;
471 if (len == 0 && nbp->nbp_state != NBST_SESSION)
472 break;
473 /* no data, try again */
474 if (rpcode == NB_SSN_KEEPALIVE)
475 continue;
478 * Loop, blocking, for data following the response header.
480 * Note that we can't simply block here with MSG_WAITALL for the
481 * entire response size, as it may be larger than the TCP
482 * slow-start window that the sender employs. This will result
483 * in the sender stalling until the delayed ACK is sent, then
484 * resuming slow-start, resulting in very poor performance.
486 * Instead, we never request more than NB_SORECEIVE_CHUNK
487 * bytes at a time, resulting in an ack being pushed by
488 * the TCP code at the completion of each call.
490 resid = len;
491 while (resid > 0) {
492 tm = NULL;
493 rcvflg = MSG_WAITALL;
494 bzero(&auio, sizeof(auio));
495 auio.uio_resid = min(resid, NB_SORECEIVE_CHUNK);
496 /* not need to setup uio_vmspace */
497 resid -= auio.uio_resid;
499 * Spin until we have collected everything in
500 * this chunk.
502 do {
503 rcvflg = MSG_WAITALL;
504 #ifdef __NetBSD__
505 error = (*so->so_receive)(so, (struct mbuf **)0,
506 &auio, &tm, (struct mbuf **)NULL,
507 &rcvflg);
508 #else
509 error = so->so_proto->pr_usrreqs->pru_soreceive
510 (so, (struct sockaddr **)NULL,
511 &auio, &tm, (struct mbuf **)NULL, &rcvflg);
512 #endif
513 } while (error == EWOULDBLOCK || error == EINTR ||
514 error == ERESTART);
515 if (error)
516 goto out;
517 /* short return guarantees unhappiness */
518 if (auio.uio_resid > 0) {
519 SMBERROR("packet is shorter than expected\n");
520 error = EPIPE;
521 goto out;
523 /* append received chunk to previous chunk(s) */
524 if (m == NULL) {
525 m = tm;
526 } else {
528 * Just glue the new chain on the end.
529 * Consumer will pullup as required.
531 for (im = m; im->m_next != NULL; im = im->m_next)
533 im->m_next = tm;
536 /* got a session/message packet? */
537 if (nbp->nbp_state == NBST_SESSION &&
538 rpcode == NB_SSN_MESSAGE)
539 break;
540 /* drop packet and try for another */
541 NBDEBUG("non-session packet %x\n", rpcode);
542 if (m) {
543 m_freem(m);
544 m = NULL;
548 out:
549 if (error) {
550 if (m)
551 m_freem(m);
552 return error;
554 if (mpp)
555 *mpp = m;
556 else
557 m_freem(m);
558 *lenp = len;
559 *rpcodep = rpcode;
560 return 0;
564 * SMB transport interface
566 static int
567 smb_nbst_create(struct smb_vc *vcp, struct lwp *l)
569 struct nbpcb *nbp;
571 MALLOC(nbp, struct nbpcb *, sizeof *nbp, M_NBDATA, M_WAITOK);
572 memset(nbp, 0, sizeof *nbp);
573 nbp->nbp_state = NBST_CLOSED;
574 nbp->nbp_vc = vcp;
575 vcp->vc_tdata = nbp;
576 return 0;
579 static int
580 smb_nbst_done(struct smb_vc *vcp, struct lwp *l)
582 struct nbpcb *nbp = vcp->vc_tdata;
584 if (nbp == NULL)
585 return ENOTCONN;
586 smb_nbst_disconnect(vcp, l);
587 if (nbp->nbp_laddr)
588 free(nbp->nbp_laddr, M_SONAME);
589 if (nbp->nbp_paddr)
590 free(nbp->nbp_paddr, M_SONAME);
591 free(nbp, M_NBDATA);
592 return 0;
595 static int
596 smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap, struct lwp *l)
598 struct nbpcb *nbp = vcp->vc_tdata;
599 struct sockaddr_nb *snb;
600 int error, slen;
602 NBDEBUG("\n");
603 error = EINVAL;
604 do {
605 if (nbp->nbp_flags & NBF_LOCADDR)
606 break;
608 * It is possible to create NETBIOS name in the kernel,
609 * but nothing prevents us to do it in the user space.
611 if (sap == NULL)
612 break;
613 slen = sap->sa_len;
614 if (slen < NB_MINSALEN)
615 break;
616 snb = (struct sockaddr_nb*)dup_sockaddr(sap, 1);
617 if (snb == NULL) {
618 error = ENOMEM;
619 break;
621 nbp->nbp_laddr = snb;
622 nbp->nbp_flags |= NBF_LOCADDR;
623 error = 0;
624 } while(0);
625 return error;
628 static int
629 smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap, struct lwp *l)
631 struct nbpcb *nbp = vcp->vc_tdata;
632 struct sockaddr_in sin;
633 struct sockaddr_nb *snb;
634 int error, slen;
636 NBDEBUG("\n");
637 if (nbp->nbp_tso != NULL)
638 return EISCONN;
639 if (nbp->nbp_laddr == NULL)
640 return EINVAL;
641 slen = sap->sa_len;
642 if (slen < NB_MINSALEN)
643 return EINVAL;
644 if (nbp->nbp_paddr) {
645 free(nbp->nbp_paddr, M_SONAME);
646 nbp->nbp_paddr = NULL;
648 snb = (struct sockaddr_nb*)dup_sockaddr(sap, 1);
649 if (snb == NULL)
650 return ENOMEM;
651 nbp->nbp_paddr = snb;
652 sin = snb->snb_addrin;
653 error = nb_connect_in(nbp, &sin, l);
654 if (error)
655 return error;
656 error = nbssn_rq_request(nbp, l);
657 if (error)
658 smb_nbst_disconnect(vcp, l);
659 return error;
662 static int
663 smb_nbst_disconnect(struct smb_vc *vcp, struct lwp *l)
665 struct nbpcb *nbp = vcp->vc_tdata;
666 struct socket *so;
668 if (nbp == NULL || nbp->nbp_tso == NULL)
669 return ENOTCONN;
670 if ((so = nbp->nbp_tso) != NULL) {
671 nbp->nbp_flags &= ~NBF_CONNECTED;
672 nbp->nbp_tso = (struct socket *)NULL;
673 soshutdown(so, 2);
674 soclose(so);
676 if (nbp->nbp_state != NBST_RETARGET) {
677 nbp->nbp_state = NBST_CLOSED;
679 return 0;
682 static int
683 smb_nbst_send(struct smb_vc *vcp, struct mbuf *m0, struct lwp *l)
685 struct nbpcb *nbp = vcp->vc_tdata;
686 int error;
688 if (nbp->nbp_state != NBST_SESSION) {
689 error = ENOTCONN;
690 goto abort;
692 M_PREPEND(m0, 4, M_WAITOK);
693 if (m0 == NULL)
694 return ENOBUFS;
695 nb_sethdr(m0, NB_SSN_MESSAGE, m_fixhdr(m0) - 4);
696 error = nb_sosend(nbp->nbp_tso, m0, 0, l);
697 return error;
698 abort:
699 if (m0)
700 m_freem(m0);
701 return error;
705 static int
706 smb_nbst_recv(struct smb_vc *vcp, struct mbuf **mpp, struct lwp *l)
708 struct nbpcb *nbp = vcp->vc_tdata;
709 u_int8_t rpcode;
710 int error, rplen;
712 nbp->nbp_flags |= NBF_RECVLOCK;
713 error = nbssn_recv(nbp, mpp, &rplen, &rpcode, l);
714 nbp->nbp_flags &= ~NBF_RECVLOCK;
715 return error;
718 static void
719 smb_nbst_timo(struct smb_vc *vcp)
722 /* Nothing */
725 static void
726 smb_nbst_intr(struct smb_vc *vcp)
728 struct nbpcb *nbp = vcp->vc_tdata;
730 if (nbp == NULL || nbp->nbp_tso == NULL)
731 return;
732 sorwakeup(nbp->nbp_tso);
733 sowwakeup(nbp->nbp_tso);
736 static int
737 smb_nbst_getparam(struct smb_vc *vcp, int param, void *data)
739 switch (param) {
740 case SMBTP_SNDSZ:
741 *(int*)data = nb_tcpsndbuf;
742 break;
743 case SMBTP_RCVSZ:
744 *(int*)data = nb_tcprcvbuf;
745 break;
746 case SMBTP_TIMEOUT:
747 *(struct timeval*)data = nb_timo;
748 break;
749 default:
750 return EINVAL;
752 return 0;
755 static int
756 smb_nbst_setparam(struct smb_vc *vcp, int param, void *data)
758 struct nbpcb *nbp = vcp->vc_tdata;
760 switch (param) {
761 case SMBTP_SELECTID:
762 nbp->nbp_selectid = data;
763 break;
764 default:
765 return EINVAL;
767 return 0;
771 * Check for fatal errors
773 static int
774 smb_nbst_fatal(struct smb_vc *vcp, int error)
776 switch (error) {
777 case ENOTCONN:
778 case ENETRESET:
779 case ECONNABORTED:
780 return 1;
782 return 0;
786 struct smb_tran_desc smb_tran_nbtcp_desc = {
787 SMBT_NBTCP,
788 smb_nbst_create, smb_nbst_done,
789 smb_nbst_bind, smb_nbst_connect, smb_nbst_disconnect,
790 smb_nbst_send, smb_nbst_recv,
791 smb_nbst_timo, smb_nbst_intr,
792 smb_nbst_getparam, smb_nbst_setparam,
793 smb_nbst_fatal,
794 { NULL, NULL },