Commit | Line | Data |
---|---|---|
984263bc MD |
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 | * $FreeBSD: src/sys/netsmb/smb_trantcp.c,v 1.3.2.1 2001/05/22 08:32:34 bp Exp $ | |
33 | */ | |
34 | #include <sys/param.h> | |
35 | #include <sys/systm.h> | |
36 | #include <sys/kernel.h> | |
37 | #include <sys/malloc.h> | |
38 | #include <sys/mbuf.h> | |
39 | #include <sys/proc.h> | |
40 | #include <sys/protosw.h> | |
e4700d00 | 41 | #include <sys/resourcevar.h> |
984263bc MD |
42 | #include <sys/socket.h> |
43 | #include <sys/socketvar.h> | |
93bffeca | 44 | #include <sys/socketvar2.h> |
6b6e0885 | 45 | #include <sys/socketops.h> |
984263bc MD |
46 | #include <sys/poll.h> |
47 | #include <sys/uio.h> | |
9ba76b73 | 48 | #include <sys/fcntl.h> |
984263bc | 49 | #include <sys/sysctl.h> |
636ae7e8 | 50 | #include <sys/thread2.h> |
984263bc MD |
51 | |
52 | #include <net/if.h> | |
53 | #include <net/route.h> | |
54 | ||
55 | #include <netinet/in.h> | |
56 | #include <netinet/tcp.h> | |
57 | ||
58 | #include <sys/mchain.h> | |
59 | ||
1f2de5d4 | 60 | #include "netbios.h" |
984263bc | 61 | |
1f2de5d4 MD |
62 | #include "smb.h" |
63 | #include "smb_conn.h" | |
64 | #include "smb_tran.h" | |
65 | #include "smb_trantcp.h" | |
66 | #include "smb_subr.h" | |
984263bc MD |
67 | |
68 | #define M_NBDATA M_PCB | |
69 | ||
70 | static int smb_tcpsndbuf = 10 * 1024; | |
71 | static int smb_tcprcvbuf = 10 * 1024; | |
72 | ||
73 | SYSCTL_DECL(_net_smb); | |
74 | SYSCTL_INT(_net_smb, OID_AUTO, tcpsndbuf, CTLFLAG_RW, &smb_tcpsndbuf, 0, ""); | |
75 | SYSCTL_INT(_net_smb, OID_AUTO, tcprcvbuf, CTLFLAG_RW, &smb_tcprcvbuf, 0, ""); | |
76 | ||
6b6e0885 JH |
77 | #define nb_sosend(so,m,flags,p) \ |
78 | so_pru_sosend(so, NULL, NULL, m, NULL, flags, td) | |
984263bc MD |
79 | |
80 | static int nbssn_recv(struct nbpcb *nbp, struct mbuf **mpp, int *lenp, | |
dadab5e9 MD |
81 | u_int8_t *rpcodep, struct thread *td); |
82 | static int smb_nbst_disconnect(struct smb_vc *vcp, struct thread *td); | |
984263bc MD |
83 | |
84 | static int | |
85 | nb_setsockopt_int(struct socket *so, int level, int name, int val) | |
86 | { | |
87 | struct sockopt sopt; | |
88 | ||
89 | bzero(&sopt, sizeof(sopt)); | |
90 | sopt.sopt_level = level; | |
91 | sopt.sopt_name = name; | |
92 | sopt.sopt_val = &val; | |
93 | sopt.sopt_valsize = sizeof(val); | |
94 | return sosetopt(so, &sopt); | |
95 | } | |
96 | ||
984263bc | 97 | static int |
dadab5e9 | 98 | nb_intr(struct nbpcb *nbp, struct thread *td) |
984263bc MD |
99 | { |
100 | return 0; | |
101 | } | |
102 | ||
103 | static void | |
104 | nb_upcall(struct socket *so, void *arg, int waitflag) | |
105 | { | |
106 | struct nbpcb *nbp = arg; | |
107 | ||
108 | if (arg == NULL || nbp->nbp_selectid == NULL) | |
109 | return; | |
110 | wakeup(nbp->nbp_selectid); | |
111 | } | |
112 | ||
113 | static int | |
114 | nb_sethdr(struct mbuf *m, u_int8_t type, u_int32_t len) | |
115 | { | |
116 | u_int32_t *p = mtod(m, u_int32_t *); | |
117 | ||
118 | *p = htonl((len & 0x1FFFF) | (type << 24)); | |
119 | return 0; | |
120 | } | |
121 | ||
122 | static int | |
123 | nb_put_name(struct mbchain *mbp, struct sockaddr_nb *snb) | |
124 | { | |
125 | int error; | |
126 | u_char seglen, *cp; | |
127 | ||
128 | cp = snb->snb_name; | |
129 | if (*cp == 0) | |
130 | return EINVAL; | |
131 | NBDEBUG("[%s]\n", cp); | |
132 | for (;;) { | |
133 | seglen = (*cp) + 1; | |
134 | error = mb_put_mem(mbp, cp, seglen, MB_MSYSTEM); | |
135 | if (error) | |
136 | return error; | |
137 | if (seglen == 1) | |
138 | break; | |
139 | cp += seglen; | |
140 | } | |
141 | return 0; | |
142 | } | |
143 | ||
144 | static int | |
dadab5e9 | 145 | nb_connect_in(struct nbpcb *nbp, struct sockaddr_in *to, struct thread *td) |
984263bc MD |
146 | { |
147 | struct socket *so; | |
636ae7e8 | 148 | int error; |
984263bc | 149 | |
dadab5e9 | 150 | error = socreate(AF_INET, &so, SOCK_STREAM, IPPROTO_TCP, td); |
984263bc MD |
151 | if (error) |
152 | return error; | |
153 | nbp->nbp_tso = so; | |
154 | so->so_upcallarg = (caddr_t)nbp; | |
155 | so->so_upcall = nb_upcall; | |
14343ad3 | 156 | atomic_set_int(&so->so_rcv.ssb_flags, SSB_UPCALL); |
6d49aa6f MD |
157 | so->so_rcv.ssb_timeo = (5 * hz); |
158 | so->so_snd.ssb_timeo = (5 * hz); | |
e4700d00 JH |
159 | error = soreserve(so, nbp->nbp_sndbuf, nbp->nbp_rcvbuf, |
160 | &td->td_proc->p_rlimit[RLIMIT_SBSIZE]); | |
984263bc MD |
161 | if (error) |
162 | goto bad; | |
163 | nb_setsockopt_int(so, SOL_SOCKET, SO_KEEPALIVE, 1); | |
164 | nb_setsockopt_int(so, IPPROTO_TCP, TCP_NODELAY, 1); | |
14343ad3 MD |
165 | atomic_clear_int(&so->so_rcv.ssb_flags, SSB_NOINTR); |
166 | atomic_clear_int(&so->so_snd.ssb_flags, SSB_NOINTR); | |
e368a6e9 | 167 | error = soconnect(so, (struct sockaddr*)to, td, TRUE); |
99ae8c41 MD |
168 | |
169 | /* | |
170 | * If signals are allowed nbssn_recv() can wind up in a hard loop | |
b272101a | 171 | * on EWOULDBLOCK. |
99ae8c41 | 172 | */ |
14343ad3 MD |
173 | atomic_set_int(&so->so_rcv.ssb_flags, SSB_NOINTR); |
174 | atomic_set_int(&so->so_snd.ssb_flags, SSB_NOINTR); | |
984263bc MD |
175 | if (error) |
176 | goto bad; | |
636ae7e8 | 177 | crit_enter(); |
984263bc | 178 | while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { |
377d4740 | 179 | tsleep(&so->so_timeo, 0, "nbcon", 2 * hz); |
984263bc | 180 | if ((so->so_state & SS_ISCONNECTING) && so->so_error == 0 && |
dadab5e9 | 181 | (error = nb_intr(nbp, td)) != 0) { |
6cef7136 | 182 | soclrstate(so, SS_ISCONNECTING); |
636ae7e8 | 183 | crit_exit(); |
984263bc MD |
184 | goto bad; |
185 | } | |
186 | } | |
187 | if (so->so_error) { | |
188 | error = so->so_error; | |
189 | so->so_error = 0; | |
636ae7e8 | 190 | crit_exit(); |
984263bc MD |
191 | goto bad; |
192 | } | |
636ae7e8 | 193 | crit_exit(); |
984263bc MD |
194 | return 0; |
195 | bad: | |
dadab5e9 | 196 | smb_nbst_disconnect(nbp->nbp_vc, td); |
984263bc MD |
197 | return error; |
198 | } | |
199 | ||
200 | static int | |
dadab5e9 | 201 | nbssn_rq_request(struct nbpcb *nbp, struct thread *td) |
984263bc MD |
202 | { |
203 | struct mbchain mb, *mbp = &mb; | |
204 | struct mdchain md, *mdp = &md; | |
205 | struct mbuf *m0; | |
984263bc MD |
206 | struct sockaddr_in sin; |
207 | u_short port; | |
208 | u_int8_t rpcode; | |
8b5c39bb | 209 | int error, rplen, res; |
984263bc MD |
210 | |
211 | error = mb_init(mbp); | |
212 | if (error) | |
213 | return error; | |
214 | mb_put_uint32le(mbp, 0); | |
215 | nb_put_name(mbp, nbp->nbp_paddr); | |
216 | nb_put_name(mbp, nbp->nbp_laddr); | |
217 | nb_sethdr(mbp->mb_top, NB_SSN_REQUEST, mb_fixhdr(mbp) - 4); | |
dadab5e9 | 218 | error = nb_sosend(nbp->nbp_tso, mbp->mb_top, 0, td); |
984263bc MD |
219 | if (!error) { |
220 | nbp->nbp_state = NBST_RQSENT; | |
221 | } | |
222 | mb_detach(mbp); | |
223 | mb_done(mbp); | |
224 | if (error) | |
225 | return error; | |
8b5c39bb | 226 | error = socket_wait(nbp->nbp_tso, &nbp->nbp_timo, &res); |
984263bc MD |
227 | if (error == EWOULDBLOCK) { /* Timeout */ |
228 | NBDEBUG("initial request timeout\n"); | |
229 | return ETIMEDOUT; | |
230 | } | |
231 | if (error) /* restart or interrupt */ | |
232 | return error; | |
dadab5e9 | 233 | error = nbssn_recv(nbp, &m0, &rplen, &rpcode, td); |
984263bc MD |
234 | if (error) { |
235 | NBDEBUG("recv() error %d\n", error); | |
236 | return error; | |
237 | } | |
238 | /* | |
239 | * Process NETBIOS reply | |
240 | */ | |
241 | if (m0) | |
242 | md_initm(mdp, m0); | |
243 | error = 0; | |
244 | do { | |
245 | if (rpcode == NB_SSN_POSRESP) { | |
246 | nbp->nbp_state = NBST_SESSION; | |
247 | nbp->nbp_flags |= NBF_CONNECTED; | |
248 | break; | |
249 | } | |
250 | if (rpcode != NB_SSN_RTGRESP) { | |
251 | error = ECONNABORTED; | |
252 | break; | |
253 | } | |
254 | if (rplen != 6) { | |
255 | error = ECONNABORTED; | |
256 | break; | |
257 | } | |
258 | md_get_mem(mdp, (caddr_t)&sin.sin_addr, 4, MB_MSYSTEM); | |
259 | md_get_uint16(mdp, &port); | |
260 | sin.sin_port = port; | |
261 | nbp->nbp_state = NBST_RETARGET; | |
dadab5e9 MD |
262 | smb_nbst_disconnect(nbp->nbp_vc, td); |
263 | error = nb_connect_in(nbp, &sin, td); | |
984263bc | 264 | if (!error) |
dadab5e9 | 265 | error = nbssn_rq_request(nbp, td); |
984263bc | 266 | if (error) { |
dadab5e9 | 267 | smb_nbst_disconnect(nbp->nbp_vc, td); |
984263bc MD |
268 | break; |
269 | } | |
270 | } while(0); | |
271 | if (m0) | |
272 | md_done(mdp); | |
273 | return error; | |
274 | } | |
275 | ||
276 | static int | |
277 | nbssn_recvhdr(struct nbpcb *nbp, int *lenp, | |
dadab5e9 | 278 | u_int8_t *rpcodep, int flags, struct thread *td) |
984263bc MD |
279 | { |
280 | struct socket *so = nbp->nbp_tso; | |
281 | struct uio auio; | |
282 | struct iovec aio; | |
283 | u_int32_t len; | |
284 | int error; | |
285 | ||
286 | aio.iov_base = (caddr_t)&len; | |
287 | aio.iov_len = sizeof(len); | |
288 | auio.uio_iov = &aio; | |
289 | auio.uio_iovcnt = 1; | |
290 | auio.uio_segflg = UIO_SYSSPACE; | |
291 | auio.uio_rw = UIO_READ; | |
292 | auio.uio_offset = 0; | |
293 | auio.uio_resid = sizeof(len); | |
dadab5e9 | 294 | auio.uio_td = td; |
6b6e0885 | 295 | error = so_pru_soreceive(so, NULL, &auio, NULL, NULL, &flags); |
984263bc MD |
296 | if (error) |
297 | return error; | |
298 | if (auio.uio_resid > 0) { | |
299 | SMBSDEBUG("short reply\n"); | |
300 | return EPIPE; | |
301 | } | |
302 | len = ntohl(len); | |
303 | *rpcodep = (len >> 24) & 0xFF; | |
304 | len &= 0x1ffff; | |
305 | if (len > SMB_MAXPKTLEN) { | |
306 | SMBERROR("packet too long (%d)\n", len); | |
307 | return EFBIG; | |
308 | } | |
309 | *lenp = len; | |
310 | return 0; | |
311 | } | |
312 | ||
313 | static int | |
314 | nbssn_recv(struct nbpcb *nbp, struct mbuf **mpp, int *lenp, | |
dadab5e9 | 315 | u_int8_t *rpcodep, struct thread *td) |
984263bc MD |
316 | { |
317 | struct socket *so = nbp->nbp_tso; | |
6d49aa6f | 318 | struct sockbuf sio; |
e54488bb MD |
319 | int error, rcvflg; |
320 | int savelen = 0; | |
321 | u_int8_t rpcode = 0; | |
984263bc MD |
322 | |
323 | if (so == NULL) | |
324 | return ENOTCONN; | |
325 | ||
6d49aa6f | 326 | sbinit(&sio, 0); |
984263bc MD |
327 | if (mpp) |
328 | *mpp = NULL; | |
d8a9a23b | 329 | |
984263bc | 330 | for(;;) { |
d8a9a23b | 331 | error = nbssn_recvhdr(nbp, &savelen, &rpcode, MSG_DONTWAIT, td); |
984263bc MD |
332 | if (so->so_state & |
333 | (SS_ISDISCONNECTING | SS_ISDISCONNECTED | SS_CANTRCVMORE)) { | |
334 | nbp->nbp_state = NBST_CLOSED; | |
335 | NBDEBUG("session closed by peer\n"); | |
d8a9a23b MD |
336 | error = ECONNRESET; |
337 | break; | |
984263bc MD |
338 | } |
339 | if (error) | |
d8a9a23b MD |
340 | break; |
341 | if (savelen == 0 && nbp->nbp_state != NBST_SESSION) | |
984263bc MD |
342 | break; |
343 | if (rpcode == NB_SSN_KEEPALIVE) | |
344 | continue; | |
984263bc | 345 | do { |
6d49aa6f | 346 | sbinit(&sio, savelen); |
984263bc | 347 | rcvflg = MSG_WAITALL; |
d8a9a23b MD |
348 | error = so_pru_soreceive(so, NULL, NULL, &sio, |
349 | NULL, &rcvflg); | |
984263bc MD |
350 | } while (error == EWOULDBLOCK || error == EINTR || |
351 | error == ERESTART); | |
352 | if (error) | |
353 | break; | |
6d49aa6f | 354 | if (sio.sb_cc != savelen) { |
984263bc MD |
355 | SMBERROR("packet is shorter than expected\n"); |
356 | error = EPIPE; | |
6d49aa6f | 357 | m_freem(sio.sb_mb); |
984263bc MD |
358 | break; |
359 | } | |
d8a9a23b | 360 | if (nbp->nbp_state == NBST_SESSION && rpcode == NB_SSN_MESSAGE) |
984263bc MD |
361 | break; |
362 | NBDEBUG("non-session packet %x\n", rpcode); | |
6d49aa6f MD |
363 | m_freem(sio.sb_mb); |
364 | sio.sb_mb = NULL; | |
365 | sio.sb_cc = 0; | |
984263bc | 366 | } |
d8a9a23b MD |
367 | if (error == 0) { |
368 | if (mpp) | |
6d49aa6f | 369 | *mpp = sio.sb_mb; |
d8a9a23b | 370 | else |
6d49aa6f MD |
371 | m_freem(sio.sb_mb); |
372 | *lenp = sio.sb_cc; | |
d8a9a23b | 373 | *rpcodep = rpcode; |
984263bc | 374 | } |
d8a9a23b | 375 | return (error); |
984263bc MD |
376 | } |
377 | ||
378 | /* | |
379 | * SMB transport interface | |
380 | */ | |
381 | static int | |
dadab5e9 | 382 | smb_nbst_create(struct smb_vc *vcp, struct thread *td) |
984263bc MD |
383 | { |
384 | struct nbpcb *nbp; | |
385 | ||
884717e1 | 386 | nbp = kmalloc(sizeof *nbp, M_NBDATA, M_WAITOK | M_ZERO); |
984263bc MD |
387 | nbp->nbp_timo.tv_sec = 15; /* XXX: sysctl ? */ |
388 | nbp->nbp_state = NBST_CLOSED; | |
389 | nbp->nbp_vc = vcp; | |
390 | nbp->nbp_sndbuf = smb_tcpsndbuf; | |
391 | nbp->nbp_rcvbuf = smb_tcprcvbuf; | |
392 | vcp->vc_tdata = nbp; | |
393 | return 0; | |
394 | } | |
395 | ||
396 | static int | |
dadab5e9 | 397 | smb_nbst_done(struct smb_vc *vcp, struct thread *td) |
984263bc MD |
398 | { |
399 | struct nbpcb *nbp = vcp->vc_tdata; | |
400 | ||
401 | if (nbp == NULL) | |
402 | return ENOTCONN; | |
dadab5e9 | 403 | smb_nbst_disconnect(vcp, td); |
984263bc | 404 | if (nbp->nbp_laddr) |
efda3bd0 | 405 | kfree(nbp->nbp_laddr, M_SONAME); |
984263bc | 406 | if (nbp->nbp_paddr) |
efda3bd0 MD |
407 | kfree(nbp->nbp_paddr, M_SONAME); |
408 | kfree(nbp, M_NBDATA); | |
984263bc MD |
409 | return 0; |
410 | } | |
411 | ||
412 | static int | |
dadab5e9 | 413 | smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap, struct thread *td) |
984263bc MD |
414 | { |
415 | struct nbpcb *nbp = vcp->vc_tdata; | |
416 | struct sockaddr_nb *snb; | |
417 | int error, slen; | |
418 | ||
419 | NBDEBUG("\n"); | |
420 | error = EINVAL; | |
421 | do { | |
422 | if (nbp->nbp_flags & NBF_LOCADDR) | |
423 | break; | |
424 | /* | |
425 | * It is possible to create NETBIOS name in the kernel, | |
426 | * but nothing prevents us to do it in the user space. | |
427 | */ | |
428 | if (sap == NULL) | |
429 | break; | |
430 | slen = sap->sa_len; | |
431 | if (slen < NB_MINSALEN) | |
432 | break; | |
cfa2ba21 | 433 | snb = (struct sockaddr_nb*)dup_sockaddr(sap); |
984263bc MD |
434 | if (snb == NULL) { |
435 | error = ENOMEM; | |
436 | break; | |
437 | } | |
438 | nbp->nbp_laddr = snb; | |
439 | nbp->nbp_flags |= NBF_LOCADDR; | |
440 | error = 0; | |
441 | } while(0); | |
442 | return error; | |
443 | } | |
444 | ||
445 | static int | |
dadab5e9 | 446 | smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap, struct thread *td) |
984263bc MD |
447 | { |
448 | struct nbpcb *nbp = vcp->vc_tdata; | |
449 | struct sockaddr_in sin; | |
450 | struct sockaddr_nb *snb; | |
451 | struct timespec ts1, ts2; | |
452 | int error, slen; | |
453 | ||
454 | NBDEBUG("\n"); | |
455 | if (nbp->nbp_tso != NULL) | |
456 | return EISCONN; | |
457 | if (nbp->nbp_laddr == NULL) | |
458 | return EINVAL; | |
459 | slen = sap->sa_len; | |
460 | if (slen < NB_MINSALEN) | |
461 | return EINVAL; | |
462 | if (nbp->nbp_paddr) { | |
efda3bd0 | 463 | kfree(nbp->nbp_paddr, M_SONAME); |
984263bc MD |
464 | nbp->nbp_paddr = NULL; |
465 | } | |
cfa2ba21 | 466 | snb = (struct sockaddr_nb*)dup_sockaddr(sap); |
984263bc MD |
467 | if (snb == NULL) |
468 | return ENOMEM; | |
469 | nbp->nbp_paddr = snb; | |
470 | sin = snb->snb_addrin; | |
471 | getnanotime(&ts1); | |
dadab5e9 | 472 | error = nb_connect_in(nbp, &sin, td); |
984263bc MD |
473 | if (error) |
474 | return error; | |
475 | getnanotime(&ts2); | |
944cd60c | 476 | timespecsub(&ts2, &ts1, &ts2); |
9c104da7 | 477 | if (ts2.tv_sec == 0) { |
984263bc | 478 | ts2.tv_sec = 1; |
9c104da7 SW |
479 | ts2.tv_nsec = 0; |
480 | } | |
944cd60c SW |
481 | timespecadd(&ts2, &ts2, &nbp->nbp_timo); |
482 | timespecadd(&nbp->nbp_timo, &ts2, &nbp->nbp_timo); | |
483 | timespecadd(&nbp->nbp_timo, &ts2, &nbp->nbp_timo); /* * 4 */ | |
dadab5e9 | 484 | error = nbssn_rq_request(nbp, td); |
984263bc | 485 | if (error) |
dadab5e9 | 486 | smb_nbst_disconnect(vcp, td); |
984263bc MD |
487 | return error; |
488 | } | |
489 | ||
490 | static int | |
dadab5e9 | 491 | smb_nbst_disconnect(struct smb_vc *vcp, struct thread *td) |
984263bc MD |
492 | { |
493 | struct nbpcb *nbp = vcp->vc_tdata; | |
494 | struct socket *so; | |
495 | ||
496 | if (nbp == NULL || nbp->nbp_tso == NULL) | |
497 | return ENOTCONN; | |
498 | if ((so = nbp->nbp_tso) != NULL) { | |
499 | nbp->nbp_flags &= ~NBF_CONNECTED; | |
2038fb68 | 500 | nbp->nbp_tso = NULL; |
e5d03018 | 501 | soshutdown(so, SHUT_RDWR); |
9ba76b73 | 502 | soclose(so, FNONBLOCK); |
984263bc MD |
503 | } |
504 | if (nbp->nbp_state != NBST_RETARGET) { | |
505 | nbp->nbp_state = NBST_CLOSED; | |
506 | } | |
507 | return 0; | |
508 | } | |
509 | ||
510 | static int | |
dadab5e9 | 511 | smb_nbst_send(struct smb_vc *vcp, struct mbuf *m0, struct thread *td) |
984263bc MD |
512 | { |
513 | struct nbpcb *nbp = vcp->vc_tdata; | |
514 | int error; | |
515 | ||
516 | if (nbp->nbp_state != NBST_SESSION) { | |
517 | error = ENOTCONN; | |
518 | goto abort; | |
519 | } | |
b5523eac | 520 | M_PREPEND(m0, 4, M_WAITOK); |
984263bc | 521 | nb_sethdr(m0, NB_SSN_MESSAGE, m_fixhdr(m0) - 4); |
dadab5e9 | 522 | error = nb_sosend(nbp->nbp_tso, m0, 0, td); |
984263bc MD |
523 | return error; |
524 | abort: | |
525 | if (m0) | |
526 | m_freem(m0); | |
527 | return error; | |
528 | } | |
529 | ||
530 | ||
531 | static int | |
dadab5e9 | 532 | smb_nbst_recv(struct smb_vc *vcp, struct mbuf **mpp, struct thread *td) |
984263bc MD |
533 | { |
534 | struct nbpcb *nbp = vcp->vc_tdata; | |
535 | u_int8_t rpcode; | |
536 | int error, rplen; | |
537 | ||
538 | nbp->nbp_flags |= NBF_RECVLOCK; | |
dadab5e9 | 539 | error = nbssn_recv(nbp, mpp, &rplen, &rpcode, td); |
984263bc MD |
540 | nbp->nbp_flags &= ~NBF_RECVLOCK; |
541 | return error; | |
542 | } | |
543 | ||
544 | static void | |
545 | smb_nbst_timo(struct smb_vc *vcp) | |
546 | { | |
547 | return; | |
548 | } | |
549 | ||
550 | static void | |
551 | smb_nbst_intr(struct smb_vc *vcp) | |
552 | { | |
553 | struct nbpcb *nbp = vcp->vc_tdata; | |
554 | ||
555 | if (nbp == NULL || nbp->nbp_tso == NULL) | |
556 | return; | |
557 | sorwakeup(nbp->nbp_tso); | |
558 | sowwakeup(nbp->nbp_tso); | |
559 | } | |
560 | ||
561 | static int | |
562 | smb_nbst_getparam(struct smb_vc *vcp, int param, void *data) | |
563 | { | |
564 | struct nbpcb *nbp = vcp->vc_tdata; | |
565 | ||
566 | switch (param) { | |
567 | case SMBTP_SNDSZ: | |
568 | *(int*)data = nbp->nbp_sndbuf; | |
569 | break; | |
570 | case SMBTP_RCVSZ: | |
571 | *(int*)data = nbp->nbp_rcvbuf; | |
572 | break; | |
573 | case SMBTP_TIMEOUT: | |
574 | *(struct timespec*)data = nbp->nbp_timo; | |
575 | break; | |
576 | default: | |
577 | return EINVAL; | |
578 | } | |
579 | return 0; | |
580 | } | |
581 | ||
582 | static int | |
583 | smb_nbst_setparam(struct smb_vc *vcp, int param, void *data) | |
584 | { | |
585 | struct nbpcb *nbp = vcp->vc_tdata; | |
586 | ||
587 | switch (param) { | |
588 | case SMBTP_SELECTID: | |
589 | nbp->nbp_selectid = data; | |
590 | break; | |
591 | default: | |
592 | return EINVAL; | |
593 | } | |
594 | return 0; | |
595 | } | |
596 | ||
597 | /* | |
598 | * Check for fatal errors | |
599 | */ | |
600 | static int | |
601 | smb_nbst_fatal(struct smb_vc *vcp, int error) | |
602 | { | |
603 | switch (error) { | |
604 | case ENOTCONN: | |
605 | case ENETRESET: | |
606 | case ECONNABORTED: | |
607 | return 1; | |
608 | } | |
609 | return 0; | |
610 | } | |
611 | ||
612 | ||
613 | struct smb_tran_desc smb_tran_nbtcp_desc = { | |
614 | SMBT_NBTCP, | |
615 | smb_nbst_create, smb_nbst_done, | |
616 | smb_nbst_bind, smb_nbst_connect, smb_nbst_disconnect, | |
617 | smb_nbst_send, smb_nbst_recv, | |
618 | smb_nbst_timo, smb_nbst_intr, | |
619 | smb_nbst_getparam, smb_nbst_setparam, | |
620 | smb_nbst_fatal | |
621 | }; | |
622 |