1 /* $NetBSD: smb_trantcp.c,v 1.18 2005/02/26 22:39:50 perry Exp $ */
2
3 /*
4 * Copyright (c) 2000-2001 Boris Popov
5 * All rights reserved.
6 *
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.
21 *
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.
33 *
34 * FreeBSD: src/sys/netsmb/smb_trantcp.c,v 1.17 2003/02/19 05:47:38 imp Exp
35 */
36
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: smb_trantcp.c,v 1.18 2005/02/26 22:39:50 perry Exp $");
39
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>
52
53 #include <net/if.h>
54 #include <net/route.h>
55
56 #include <netinet/in.h>
57 #include <netinet/tcp.h>
58
59 #include <netsmb/mchain.h>
60
61 #include <netsmb/netbios.h>
62
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>
68
69 #define M_NBDATA M_PCB
70
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? */
74
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
80
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,p) (*(so)->so_send)(so, NULL, (struct uio *)0, \
86 m, (struct mbuf *)0, flags, p)
87 #endif
88
89 static int nbssn_recv(struct nbpcb *nbp, struct mbuf **mpp, int *lenp,
90 u_int8_t *rpcodep, struct proc *p);
91 static int smb_nbst_disconnect(struct smb_vc *vcp, struct proc *p);
92
93 static int
94 nb_setsockopt_int(struct socket *so, int level, int name, int val)
95 {
96 #ifdef __NetBSD__
97 return sosetopt(so, level, name, NULL); /* XXX */
98 #else
99 struct sockopt sopt;
100
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
108 }
109
110 static __inline int
111 nb_poll(struct nbpcb *nbp, int events, struct proc *p)
112 {
113 #ifndef __NetBSD__
114 return nbp->nbp_tso->so_proto->pr_usrreqs->pru_sopoll(nbp->nbp_tso,
115 events, NULL, p);
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();
121
122 if (events & (POLLIN | POLLRDNORM))
123 if (soreadable(so))
124 revents |= events & (POLLIN | POLLRDNORM);
125
126 if (events & (POLLOUT | POLLWRNORM))
127 if (sowritable(so))
128 revents |= events & (POLLOUT | POLLWRNORM);
129
130 if (events & (POLLPRI | POLLRDBAND))
131 if (so->so_oobmark || (so->so_state & SS_RCVATMARK))
132 revents |= events & (POLLPRI | POLLRDBAND);
133
134 if (revents == 0) {
135 if (events & (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)) {
136 selrecord(p, &so->so_rcv.sb_sel);
137 so->so_rcv.sb_flags |= SB_SEL;
138 }
139
140 if (events & (POLLOUT | POLLWRNORM)) {
141 selrecord(p, &so->so_snd.sb_sel);
142 so->so_snd.sb_flags |= SB_SEL;
143 }
144 }
145
146 splx(s);
147 return (revents);
148 #endif
149 }
150
151 static int
152 nbssn_rselect(struct nbpcb *nbp, const struct timeval *tv, int events,
153 struct proc *p)
154 {
155 struct timeval atv;
156 extern int nselcoll;
157 int ncoll;
158 int timo, error;
159 int s;
160 struct lwp *l = curlwp;
161
162 if (tv) {
163 atv = *tv;
164 if (itimerfix(&atv))
165 return (EINVAL);
166 s = splclock();
167 timeradd(&atv, &time, &atv);
168 splx(s);
169 timo = hzto(&atv);
170 if (timo <= 0)
171 return (EWOULDBLOCK);
172 } else
173 timo = 0;
174
175 retry:
176 ncoll = nselcoll;
177 l->l_flag |= L_SELECT;
178 error = nb_poll(nbp, events, p);
179 if (error) {
180 error = 0;
181 goto done;
182 }
183 if (tv) {
184 /*
185 * We have to recalculate the timeout on every retry.
186 */
187 timo = hzto(&atv);
188 if (timo <= 0) {
189 error = EWOULDBLOCK;
190 goto done;
191 }
192 }
193
194 s = splsched();
195 if ((l->l_flag & L_SELECT) == 0 || nselcoll != ncoll) {
196 splx(s);
197 goto retry;
198 }
199 l->l_flag &= ~L_SELECT;
200 error = tsleep((caddr_t)&selwait, PSOCK, "smbsel", timo);
201 splx(s);
202
203 if (error == 0)
204 goto retry;
205
206 done:
207 l->l_flag &= ~L_SELECT;
208 /* select is not restarted after signals... */
209 if (error == ERESTART)
210 error = 0;
211 return (error);
212 }
213
214 static int
215 nb_intr(struct nbpcb *nbp, struct proc *p)
216 {
217 return 0;
218 }
219
220 static void
221 nb_upcall(struct socket *so, caddr_t arg, int waitflag)
222 {
223 struct nbpcb *nbp = (void *)arg;
224
225 if (arg == NULL || nbp->nbp_selectid == NULL)
226 return;
227 wakeup(nbp->nbp_selectid);
228 }
229
230 static int
231 nb_sethdr(struct mbuf *m, u_int8_t type, u_int32_t len)
232 {
233 u_int32_t *p = mtod(m, u_int32_t *);
234
235 *p = htonl((len & 0x1FFFF) | (type << 24));
236 return 0;
237 }
238
239 static int
240 nb_put_name(struct mbchain *mbp, struct sockaddr_nb *snb)
241 {
242 int error;
243 u_char seglen, *cp;
244
245 cp = snb->snb_name;
246 if (*cp == 0)
247 return EINVAL;
248 NBDEBUG("[%s]\n", cp);
249 for (;;) {
250 seglen = (*cp) + 1;
251 error = mb_put_mem(mbp, cp, seglen, MB_MSYSTEM);
252 if (error)
253 return error;
254 if (seglen == 1)
255 break;
256 cp += seglen;
257 }
258 return 0;
259 }
260
261 static int
262 nb_connect_in(struct nbpcb *nbp, struct sockaddr_in *to, struct proc *p)
263 {
264 struct socket *so;
265 int error, s;
266 #ifdef __NetBSD__
267 struct mbuf *m;
268 #endif
269
270 error = socreate(AF_INET, &so, SOCK_STREAM, IPPROTO_TCP, p);
271 if (error)
272 return error;
273 nbp->nbp_tso = so;
274 so->so_upcallarg = (caddr_t)nbp;
275 so->so_upcall = nb_upcall;
276 so->so_rcv.sb_flags |= SB_UPCALL;
277 so->so_rcv.sb_timeo = NB_SNDTIMEO;
278 so->so_snd.sb_timeo = NB_RCVTIMEO;
279 error = soreserve(so, nb_tcpsndbuf, nb_tcprcvbuf);
280 if (error)
281 goto bad;
282 nb_setsockopt_int(so, SOL_SOCKET, SO_KEEPALIVE, 1);
283 nb_setsockopt_int(so, IPPROTO_TCP, TCP_NODELAY, 1);
284 so->so_rcv.sb_flags &= ~SB_NOINTR;
285 so->so_snd.sb_flags &= ~SB_NOINTR;
286 #ifndef __NetBSD__
287 error = soconnect(so, (struct sockaddr*)to, p);
288 #else
289 m = m_get(M_WAIT, MT_SONAME);
290 *mtod(m, struct sockaddr *) = *(struct sockaddr *)to;
291 m->m_len = sizeof(struct sockaddr);
292 error = soconnect(so, m, p);
293 m_free(m);
294 #endif
295 if (error)
296 goto bad;
297 s = splnet();
298 while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
299 tsleep(&so->so_timeo, PSOCK, "smbcon", 2 * hz);
300 if ((so->so_state & SS_ISCONNECTING) && so->so_error == 0 &&
301 (error = nb_intr(nbp, p)) != 0) {
302 so->so_state &= ~SS_ISCONNECTING;
303 splx(s);
304 goto bad;
305 }
306 }
307 if (so->so_error) {
308 error = so->so_error;
309 so->so_error = 0;
310 splx(s);
311 goto bad;
312 }
313 splx(s);
314 return 0;
315 bad:
316 smb_nbst_disconnect(nbp->nbp_vc, p);
317 return error;
318 }
319
320 static int
321 nbssn_rq_request(struct nbpcb *nbp, struct proc *p)
322 {
323 struct mbchain mb, *mbp = &mb;
324 struct mdchain md, *mdp = &md;
325 struct mbuf *m0;
326 struct sockaddr_in sin;
327 u_short port;
328 u_int8_t rpcode;
329 int error, rplen;
330
331 error = mb_init(mbp);
332 if (error)
333 return error;
334 mb_put_uint32le(mbp, 0);
335 (void) nb_put_name(mbp, nbp->nbp_paddr);
336 (void) nb_put_name(mbp, nbp->nbp_laddr);
337 nb_sethdr(mbp->mb_top, NB_SSN_REQUEST, mb_fixhdr(mbp) - 4);
338 error = nb_sosend(nbp->nbp_tso, mbp->mb_top, 0, p);
339 if (!error) {
340 nbp->nbp_state = NBST_RQSENT;
341 }
342 mb_detach(mbp);
343 mb_done(mbp);
344 if (error)
345 return error;
346 error = nbssn_rselect(nbp, &nb_timo, POLLIN, p);
347 if (error == EWOULDBLOCK) { /* Timeout */
348 NBDEBUG("initial request timeout\n");
349 return ETIMEDOUT;
350 }
351 if (error) /* restart or interrupt */
352 return error;
353 error = nbssn_recv(nbp, &m0, &rplen, &rpcode, p);
354 if (error) {
355 NBDEBUG("recv() error %d\n", error);
356 return error;
357 }
358 /*
359 * Process NETBIOS reply
360 */
361 if (m0)
362 md_initm(mdp, m0);
363 error = 0;
364 do {
365 if (rpcode == NB_SSN_POSRESP) {
366 nbp->nbp_state = NBST_SESSION;
367 nbp->nbp_flags |= NBF_CONNECTED;
368 break;
369 }
370 if (rpcode != NB_SSN_RTGRESP) {
371 error = ECONNABORTED;
372 break;
373 }
374 if (rplen != 6) {
375 error = ECONNABORTED;
376 break;
377 }
378 md_get_mem(mdp, (caddr_t)&sin.sin_addr, 4, MB_MSYSTEM);
379 md_get_uint16(mdp, &port);
380 sin.sin_port = port;
381 nbp->nbp_state = NBST_RETARGET;
382 smb_nbst_disconnect(nbp->nbp_vc, p);
383 error = nb_connect_in(nbp, &sin, p);
384 if (!error)
385 error = nbssn_rq_request(nbp, p);
386 if (error) {
387 smb_nbst_disconnect(nbp->nbp_vc, p);
388 break;
389 }
390 } while(0);
391 if (m0)
392 md_done(mdp);
393 return error;
394 }
395
396 static int
397 nbssn_recvhdr(struct nbpcb *nbp, int *lenp,
398 u_int8_t *rpcodep, int flags, struct proc *p)
399 {
400 struct socket *so = nbp->nbp_tso;
401 struct uio auio;
402 struct iovec aio;
403 u_int32_t len;
404 int error;
405
406 aio.iov_base = (caddr_t)&len;
407 aio.iov_len = sizeof(len);
408 auio.uio_iov = &aio;
409 auio.uio_iovcnt = 1;
410 auio.uio_segflg = UIO_SYSSPACE;
411 auio.uio_rw = UIO_READ;
412 auio.uio_offset = 0;
413 auio.uio_resid = sizeof(len);
414 auio.uio_procp = NULL;
415 #ifndef __NetBSD__
416 error = so->so_proto->pr_usrreqs->pru_soreceive
417 (so, (struct sockaddr **)NULL, &auio,
418 (struct mbuf **)NULL, (struct mbuf **)NULL, &flags);
419 #else
420 error = (*so->so_receive)(so, (struct mbuf **)0, &auio,
421 (struct mbuf **)NULL,
422 (struct mbuf **)NULL, &flags);
423 #endif
424 if (error)
425 return error;
426 if (auio.uio_resid > 0) {
427 SMBSDEBUG("short reply\n");
428 return EPIPE;
429 }
430 len = ntohl(len);
431 *rpcodep = (len >> 24) & 0xFF;
432 len &= 0x1ffff;
433 if (len > SMB_MAXPKTLEN) {
434 SMBERROR("packet too long (%d)\n", len);
435 return EFBIG;
436 }
437 *lenp = len;
438 return 0;
439 }
440
441 static int
442 nbssn_recv(struct nbpcb *nbp, struct mbuf **mpp, int *lenp,
443 u_int8_t *rpcodep, struct proc *p)
444 {
445 struct socket *so = nbp->nbp_tso;
446 struct uio auio;
447 struct mbuf *m, *tm, *im;
448 u_int8_t rpcode;
449 int len, resid;
450 int error, rcvflg;
451
452 if (so == NULL)
453 return ENOTCONN;
454
455 if (mpp)
456 *mpp = NULL;
457 m = NULL;
458 for(;;) {
459 /*
460 * Poll for a response header.
461 * If we don't have one waiting, return.
462 */
463 error = nbssn_recvhdr(nbp, &len, &rpcode, MSG_DONTWAIT, p);
464 if (so->so_state &
465 (SS_ISDISCONNECTING | SS_ISDISCONNECTED | SS_CANTRCVMORE)) {
466 nbp->nbp_state = NBST_CLOSED;
467 NBDEBUG("session closed by peer\n");
468 return ECONNRESET;
469 }
470 if (error)
471 return error;
472 if (len == 0 && nbp->nbp_state != NBST_SESSION)
473 break;
474 /* no data, try again */
475 if (rpcode == NB_SSN_KEEPALIVE)
476 continue;
477
478 /*
479 * Loop, blocking, for data following the response header.
480 *
481 * Note that we can't simply block here with MSG_WAITALL for the
482 * entire response size, as it may be larger than the TCP
483 * slow-start window that the sender employs. This will result
484 * in the sender stalling until the delayed ACK is sent, then
485 * resuming slow-start, resulting in very poor performance.
486 *
487 * Instead, we never request more than NB_SORECEIVE_CHUNK
488 * bytes at a time, resulting in an ack being pushed by
489 * the TCP code at the completion of each call.
490 */
491 resid = len;
492 while (resid > 0) {
493 tm = NULL;
494 rcvflg = MSG_WAITALL;
495 bzero(&auio, sizeof(auio));
496 auio.uio_resid = min(resid, NB_SORECEIVE_CHUNK);
497 auio.uio_procp = p;
498 resid -= auio.uio_resid;
499 /*
500 * Spin until we have collected everything in
501 * this chunk.
502 */
503 do {
504 rcvflg = MSG_WAITALL;
505 #ifdef __NetBSD__
506 error = (*so->so_receive)(so, (struct mbuf **)0,
507 &auio, &tm, (struct mbuf **)NULL,
508 &rcvflg);
509 #else
510 error = so->so_proto->pr_usrreqs->pru_soreceive
511 (so, (struct sockaddr **)NULL,
512 &auio, &tm, (struct mbuf **)NULL, &rcvflg);
513 #endif
514 } while (error == EWOULDBLOCK || error == EINTR ||
515 error == ERESTART);
516 if (error)
517 goto out;
518 /* short return guarantees unhappiness */
519 if (auio.uio_resid > 0) {
520 SMBERROR("packet is shorter than expected\n");
521 error = EPIPE;
522 goto out;
523 }
524 /* append received chunk to previous chunk(s) */
525 if (m == NULL) {
526 m = tm;
527 } else {
528 /*
529 * Just glue the new chain on the end.
530 * Consumer will pullup as required.
531 */
532 for (im = m; im->m_next != NULL; im = im->m_next)
533 ;
534 im->m_next = tm;
535 }
536 }
537 /* got a session/message packet? */
538 if (nbp->nbp_state == NBST_SESSION &&
539 rpcode == NB_SSN_MESSAGE)
540 break;
541 /* drop packet and try for another */
542 NBDEBUG("non-session packet %x\n", rpcode);
543 if (m) {
544 m_freem(m);
545 m = NULL;
546 }
547 }
548
549 out:
550 if (error) {
551 if (m)
552 m_freem(m);
553 return error;
554 }
555 if (mpp)
556 *mpp = m;
557 else
558 m_freem(m);
559 *lenp = len;
560 *rpcodep = rpcode;
561 return 0;
562 }
563
564 /*
565 * SMB transport interface
566 */
567 static int
568 smb_nbst_create(struct smb_vc *vcp, struct proc *p)
569 {
570 struct nbpcb *nbp;
571
572 MALLOC(nbp, struct nbpcb *, sizeof *nbp, M_NBDATA, M_WAITOK);
573 memset(nbp, 0, sizeof *nbp);
574 nbp->nbp_state = NBST_CLOSED;
575 nbp->nbp_vc = vcp;
576 vcp->vc_tdata = nbp;
577 return 0;
578 }
579
580 static int
581 smb_nbst_done(struct smb_vc *vcp, struct proc *p)
582 {
583 struct nbpcb *nbp = vcp->vc_tdata;
584
585 if (nbp == NULL)
586 return ENOTCONN;
587 smb_nbst_disconnect(vcp, p);
588 if (nbp->nbp_laddr)
589 free(nbp->nbp_laddr, M_SONAME);
590 if (nbp->nbp_paddr)
591 free(nbp->nbp_paddr, M_SONAME);
592 free(nbp, M_NBDATA);
593 return 0;
594 }
595
596 static int
597 smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap, struct proc *p)
598 {
599 struct nbpcb *nbp = vcp->vc_tdata;
600 struct sockaddr_nb *snb;
601 int error, slen;
602
603 NBDEBUG("\n");
604 error = EINVAL;
605 do {
606 if (nbp->nbp_flags & NBF_LOCADDR)
607 break;
608 /*
609 * It is possible to create NETBIOS name in the kernel,
610 * but nothing prevents us to do it in the user space.
611 */
612 if (sap == NULL)
613 break;
614 slen = sap->sa_len;
615 if (slen < NB_MINSALEN)
616 break;
617 snb = (struct sockaddr_nb*)dup_sockaddr(sap, 1);
618 if (snb == NULL) {
619 error = ENOMEM;
620 break;
621 }
622 nbp->nbp_laddr = snb;
623 nbp->nbp_flags |= NBF_LOCADDR;
624 error = 0;
625 } while(0);
626 return error;
627 }
628
629 static int
630 smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap, struct proc *p)
631 {
632 struct nbpcb *nbp = vcp->vc_tdata;
633 struct sockaddr_in sin;
634 struct sockaddr_nb *snb;
635 int error, slen;
636
637 NBDEBUG("\n");
638 if (nbp->nbp_tso != NULL)
639 return EISCONN;
640 if (nbp->nbp_laddr == NULL)
641 return EINVAL;
642 slen = sap->sa_len;
643 if (slen < NB_MINSALEN)
644 return EINVAL;
645 if (nbp->nbp_paddr) {
646 free(nbp->nbp_paddr, M_SONAME);
647 nbp->nbp_paddr = NULL;
648 }
649 snb = (struct sockaddr_nb*)dup_sockaddr(sap, 1);
650 if (snb == NULL)
651 return ENOMEM;
652 nbp->nbp_paddr = snb;
653 sin = snb->snb_addrin;
654 error = nb_connect_in(nbp, &sin, p);
655 if (error)
656 return error;
657 error = nbssn_rq_request(nbp, p);
658 if (error)
659 smb_nbst_disconnect(vcp, p);
660 return error;
661 }
662
663 static int
664 smb_nbst_disconnect(struct smb_vc *vcp, struct proc *p)
665 {
666 struct nbpcb *nbp = vcp->vc_tdata;
667 struct socket *so;
668
669 if (nbp == NULL || nbp->nbp_tso == NULL)
670 return ENOTCONN;
671 if ((so = nbp->nbp_tso) != NULL) {
672 nbp->nbp_flags &= ~NBF_CONNECTED;
673 nbp->nbp_tso = (struct socket *)NULL;
674 soshutdown(so, 2);
675 soclose(so);
676 }
677 if (nbp->nbp_state != NBST_RETARGET) {
678 nbp->nbp_state = NBST_CLOSED;
679 }
680 return 0;
681 }
682
683 static int
684 smb_nbst_send(struct smb_vc *vcp, struct mbuf *m0, struct proc *p)
685 {
686 struct nbpcb *nbp = vcp->vc_tdata;
687 int error;
688
689 if (nbp->nbp_state != NBST_SESSION) {
690 error = ENOTCONN;
691 goto abort;
692 }
693 M_PREPEND(m0, 4, M_WAITOK);
694 if (m0 == NULL)
695 return ENOBUFS;
696 nb_sethdr(m0, NB_SSN_MESSAGE, m_fixhdr(m0) - 4);
697 error = nb_sosend(nbp->nbp_tso, m0, 0, p);
698 return error;
699 abort:
700 if (m0)
701 m_freem(m0);
702 return error;
703 }
704
705
706 static int
707 smb_nbst_recv(struct smb_vc *vcp, struct mbuf **mpp, struct proc *p)
708 {
709 struct nbpcb *nbp = vcp->vc_tdata;
710 u_int8_t rpcode;
711 int error, rplen;
712
713 nbp->nbp_flags |= NBF_RECVLOCK;
714 error = nbssn_recv(nbp, mpp, &rplen, &rpcode, p);
715 nbp->nbp_flags &= ~NBF_RECVLOCK;
716 return error;
717 }
718
719 static void
720 smb_nbst_timo(struct smb_vc *vcp)
721 {
722
723 /* Nothing */
724 }
725
726 static void
727 smb_nbst_intr(struct smb_vc *vcp)
728 {
729 struct nbpcb *nbp = vcp->vc_tdata;
730
731 if (nbp == NULL || nbp->nbp_tso == NULL)
732 return;
733 sorwakeup(nbp->nbp_tso);
734 sowwakeup(nbp->nbp_tso);
735 }
736
737 static int
738 smb_nbst_getparam(struct smb_vc *vcp, int param, void *data)
739 {
740 switch (param) {
741 case SMBTP_SNDSZ:
742 *(int*)data = nb_tcpsndbuf;
743 break;
744 case SMBTP_RCVSZ:
745 *(int*)data = nb_tcprcvbuf;
746 break;
747 case SMBTP_TIMEOUT:
748 *(struct timeval*)data = nb_timo;
749 break;
750 default:
751 return EINVAL;
752 }
753 return 0;
754 }
755
756 static int
757 smb_nbst_setparam(struct smb_vc *vcp, int param, void *data)
758 {
759 struct nbpcb *nbp = vcp->vc_tdata;
760
761 switch (param) {
762 case SMBTP_SELECTID:
763 nbp->nbp_selectid = data;
764 break;
765 default:
766 return EINVAL;
767 }
768 return 0;
769 }
770
771 /*
772 * Check for fatal errors
773 */
774 static int
775 smb_nbst_fatal(struct smb_vc *vcp, int error)
776 {
777 switch (error) {
778 case ENOTCONN:
779 case ENETRESET:
780 case ECONNABORTED:
781 return 1;
782 }
783 return 0;
784 }
785
786
787 struct smb_tran_desc smb_tran_nbtcp_desc = {
788 SMBT_NBTCP,
789 smb_nbst_create, smb_nbst_done,
790 smb_nbst_bind, smb_nbst_connect, smb_nbst_disconnect,
791 smb_nbst_send, smb_nbst_recv,
792 smb_nbst_timo, smb_nbst_intr,
793 smb_nbst_getparam, smb_nbst_setparam,
794 smb_nbst_fatal
795 };
796
Cache object: cf5cee2bd16599951b36c31b2133cfc0
|