1c398230bSWarner Losh /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3fe267a55SPedro F. Giffuni *
4681a5bbeSBoris Popov * Copyright (c) 2000-2001 Boris Popov
5681a5bbeSBoris Popov * All rights reserved.
6681a5bbeSBoris Popov *
7681a5bbeSBoris Popov * Redistribution and use in source and binary forms, with or without
8681a5bbeSBoris Popov * modification, are permitted provided that the following conditions
9681a5bbeSBoris Popov * are met:
10681a5bbeSBoris Popov * 1. Redistributions of source code must retain the above copyright
11681a5bbeSBoris Popov * notice, this list of conditions and the following disclaimer.
12681a5bbeSBoris Popov * 2. Redistributions in binary form must reproduce the above copyright
13681a5bbeSBoris Popov * notice, this list of conditions and the following disclaimer in the
14681a5bbeSBoris Popov * documentation and/or other materials provided with the distribution.
15681a5bbeSBoris Popov *
16681a5bbeSBoris Popov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17681a5bbeSBoris Popov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18681a5bbeSBoris Popov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19681a5bbeSBoris Popov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20681a5bbeSBoris Popov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21681a5bbeSBoris Popov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22681a5bbeSBoris Popov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23681a5bbeSBoris Popov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24681a5bbeSBoris Popov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25681a5bbeSBoris Popov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26681a5bbeSBoris Popov * SUCH DAMAGE.
27681a5bbeSBoris Popov */
28681a5bbeSBoris Popov
29681a5bbeSBoris Popov #include <sys/param.h>
30681a5bbeSBoris Popov #include <sys/systm.h>
31a30d4b32SMike Barcroft #include <sys/endian.h>
32681a5bbeSBoris Popov #include <sys/proc.h>
33681a5bbeSBoris Popov #include <sys/kernel.h>
34681a5bbeSBoris Popov #include <sys/kthread.h>
35681a5bbeSBoris Popov #include <sys/malloc.h>
36681a5bbeSBoris Popov #include <sys/mbuf.h>
37681a5bbeSBoris Popov #include <sys/unistd.h>
38681a5bbeSBoris Popov
39681a5bbeSBoris Popov #include <netsmb/smb.h>
40681a5bbeSBoris Popov #include <netsmb/smb_conn.h>
41681a5bbeSBoris Popov #include <netsmb/smb_rq.h>
42681a5bbeSBoris Popov #include <netsmb/smb_tran.h>
43681a5bbeSBoris Popov #include <netsmb/smb_trantcp.h>
44681a5bbeSBoris Popov
45681a5bbeSBoris Popov #define SMBIOD_SLEEP_TIMO 2
46681a5bbeSBoris Popov #define SMBIOD_PING_TIMO 60 /* seconds */
47681a5bbeSBoris Popov
48681a5bbeSBoris Popov #define SMB_IOD_EVLOCKPTR(iod) (&((iod)->iod_evlock))
49681a5bbeSBoris Popov #define SMB_IOD_EVLOCK(iod) smb_sl_lock(&((iod)->iod_evlock))
50681a5bbeSBoris Popov #define SMB_IOD_EVUNLOCK(iod) smb_sl_unlock(&((iod)->iod_evlock))
51681a5bbeSBoris Popov
52681a5bbeSBoris Popov #define SMB_IOD_RQLOCKPTR(iod) (&((iod)->iod_rqlock))
53681a5bbeSBoris Popov #define SMB_IOD_RQLOCK(iod) smb_sl_lock(&((iod)->iod_rqlock))
54681a5bbeSBoris Popov #define SMB_IOD_RQUNLOCK(iod) smb_sl_unlock(&((iod)->iod_rqlock))
55681a5bbeSBoris Popov
56681a5bbeSBoris Popov #define smb_iod_wakeup(iod) wakeup(&(iod)->iod_flags)
57681a5bbeSBoris Popov
58681a5bbeSBoris Popov static MALLOC_DEFINE(M_SMBIOD, "SMBIOD", "SMB network io daemon");
59681a5bbeSBoris Popov
60681a5bbeSBoris Popov static int smb_iod_next;
61681a5bbeSBoris Popov
62681a5bbeSBoris Popov static int smb_iod_sendall(struct smbiod *iod);
63681a5bbeSBoris Popov static int smb_iod_disconnect(struct smbiod *iod);
64681a5bbeSBoris Popov static void smb_iod_thread(void *);
65681a5bbeSBoris Popov
66681a5bbeSBoris Popov static __inline void
smb_iod_rqprocessed(struct smb_rq * rqp,int error)67681a5bbeSBoris Popov smb_iod_rqprocessed(struct smb_rq *rqp, int error)
68681a5bbeSBoris Popov {
69681a5bbeSBoris Popov SMBRQ_SLOCK(rqp);
70681a5bbeSBoris Popov rqp->sr_lerror = error;
71681a5bbeSBoris Popov rqp->sr_rpgen++;
72681a5bbeSBoris Popov rqp->sr_state = SMBRQ_NOTIFIED;
73681a5bbeSBoris Popov wakeup(&rqp->sr_state);
74681a5bbeSBoris Popov SMBRQ_SUNLOCK(rqp);
75681a5bbeSBoris Popov }
76681a5bbeSBoris Popov
77681a5bbeSBoris Popov static void
smb_iod_invrq(struct smbiod * iod)78681a5bbeSBoris Popov smb_iod_invrq(struct smbiod *iod)
79681a5bbeSBoris Popov {
80681a5bbeSBoris Popov struct smb_rq *rqp;
81681a5bbeSBoris Popov
82681a5bbeSBoris Popov /*
83681a5bbeSBoris Popov * Invalidate all outstanding requests for this connection
84681a5bbeSBoris Popov */
85681a5bbeSBoris Popov SMB_IOD_RQLOCK(iod);
86681a5bbeSBoris Popov TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) {
87681a5bbeSBoris Popov rqp->sr_flags |= SMBR_RESTART;
88681a5bbeSBoris Popov smb_iod_rqprocessed(rqp, ENOTCONN);
89681a5bbeSBoris Popov }
90681a5bbeSBoris Popov SMB_IOD_RQUNLOCK(iod);
91681a5bbeSBoris Popov }
92681a5bbeSBoris Popov
93681a5bbeSBoris Popov static void
smb_iod_closetran(struct smbiod * iod)94681a5bbeSBoris Popov smb_iod_closetran(struct smbiod *iod)
95681a5bbeSBoris Popov {
96681a5bbeSBoris Popov struct smb_vc *vcp = iod->iod_vc;
97fce6fbfaSBoris Popov struct thread *td = iod->iod_td;
98681a5bbeSBoris Popov
99681a5bbeSBoris Popov if (vcp->vc_tdata == NULL)
100681a5bbeSBoris Popov return;
101fce6fbfaSBoris Popov SMB_TRAN_DISCONNECT(vcp, td);
102fce6fbfaSBoris Popov SMB_TRAN_DONE(vcp, td);
103681a5bbeSBoris Popov vcp->vc_tdata = NULL;
104681a5bbeSBoris Popov }
105681a5bbeSBoris Popov
106681a5bbeSBoris Popov static void
smb_iod_dead(struct smbiod * iod)107681a5bbeSBoris Popov smb_iod_dead(struct smbiod *iod)
108681a5bbeSBoris Popov {
109681a5bbeSBoris Popov iod->iod_state = SMBIOD_ST_DEAD;
110681a5bbeSBoris Popov smb_iod_closetran(iod);
111681a5bbeSBoris Popov smb_iod_invrq(iod);
112681a5bbeSBoris Popov }
113681a5bbeSBoris Popov
114681a5bbeSBoris Popov static int
smb_iod_connect(struct smbiod * iod)115681a5bbeSBoris Popov smb_iod_connect(struct smbiod *iod)
116681a5bbeSBoris Popov {
117681a5bbeSBoris Popov struct smb_vc *vcp = iod->iod_vc;
118fce6fbfaSBoris Popov struct thread *td = iod->iod_td;
119681a5bbeSBoris Popov int error;
120681a5bbeSBoris Popov
121681a5bbeSBoris Popov SMBIODEBUG("%d\n", iod->iod_state);
122681a5bbeSBoris Popov switch(iod->iod_state) {
123681a5bbeSBoris Popov case SMBIOD_ST_VCACTIVE:
124681a5bbeSBoris Popov SMBERROR("called for already opened connection\n");
125681a5bbeSBoris Popov return EISCONN;
126681a5bbeSBoris Popov case SMBIOD_ST_DEAD:
127681a5bbeSBoris Popov return ENOTCONN; /* XXX: last error code ? */
128681a5bbeSBoris Popov default:
129681a5bbeSBoris Popov break;
130681a5bbeSBoris Popov }
131681a5bbeSBoris Popov vcp->vc_genid++;
132681a5bbeSBoris Popov error = 0;
133e51fe875SMarcel Moolenaar
134e51fe875SMarcel Moolenaar error = (int)SMB_TRAN_CREATE(vcp, td);
135e51fe875SMarcel Moolenaar if (error)
136e51fe875SMarcel Moolenaar goto fail;
137681a5bbeSBoris Popov SMBIODEBUG("tcreate\n");
138681a5bbeSBoris Popov if (vcp->vc_laddr) {
139e51fe875SMarcel Moolenaar error = (int)SMB_TRAN_BIND(vcp, vcp->vc_laddr, td);
140e51fe875SMarcel Moolenaar if (error)
141e51fe875SMarcel Moolenaar goto fail;
142681a5bbeSBoris Popov }
143681a5bbeSBoris Popov SMBIODEBUG("tbind\n");
144e51fe875SMarcel Moolenaar error = (int)SMB_TRAN_CONNECT(vcp, vcp->vc_paddr, td);
145e51fe875SMarcel Moolenaar if (error)
146e51fe875SMarcel Moolenaar goto fail;
147681a5bbeSBoris Popov SMB_TRAN_SETPARAM(vcp, SMBTP_SELECTID, &iod->iod_flags);
148681a5bbeSBoris Popov iod->iod_state = SMBIOD_ST_TRANACTIVE;
149681a5bbeSBoris Popov SMBIODEBUG("tconnect\n");
150681a5bbeSBoris Popov /* vcp->vc_mid = 0;*/
151e51fe875SMarcel Moolenaar error = (int)smb_smb_negotiate(vcp, &iod->iod_scred);
152e51fe875SMarcel Moolenaar if (error)
153e51fe875SMarcel Moolenaar goto fail;
154681a5bbeSBoris Popov SMBIODEBUG("snegotiate\n");
155e51fe875SMarcel Moolenaar error = (int)smb_smb_ssnsetup(vcp, &iod->iod_scred);
156e51fe875SMarcel Moolenaar if (error)
157e51fe875SMarcel Moolenaar goto fail;
158681a5bbeSBoris Popov iod->iod_state = SMBIOD_ST_VCACTIVE;
159681a5bbeSBoris Popov SMBIODEBUG("completed\n");
160681a5bbeSBoris Popov smb_iod_invrq(iod);
161e51fe875SMarcel Moolenaar return (0);
162e51fe875SMarcel Moolenaar
163e51fe875SMarcel Moolenaar fail:
164681a5bbeSBoris Popov smb_iod_dead(iod);
165e51fe875SMarcel Moolenaar return (error);
166681a5bbeSBoris Popov }
167681a5bbeSBoris Popov
168681a5bbeSBoris Popov static int
smb_iod_disconnect(struct smbiod * iod)169681a5bbeSBoris Popov smb_iod_disconnect(struct smbiod *iod)
170681a5bbeSBoris Popov {
171681a5bbeSBoris Popov struct smb_vc *vcp = iod->iod_vc;
172681a5bbeSBoris Popov
173681a5bbeSBoris Popov SMBIODEBUG("\n");
174681a5bbeSBoris Popov if (iod->iod_state == SMBIOD_ST_VCACTIVE) {
175681a5bbeSBoris Popov smb_smb_ssnclose(vcp, &iod->iod_scred);
176681a5bbeSBoris Popov iod->iod_state = SMBIOD_ST_TRANACTIVE;
177681a5bbeSBoris Popov }
178681a5bbeSBoris Popov vcp->vc_smbuid = SMB_UID_UNKNOWN;
179681a5bbeSBoris Popov smb_iod_closetran(iod);
180681a5bbeSBoris Popov iod->iod_state = SMBIOD_ST_NOTCONN;
181681a5bbeSBoris Popov return 0;
182681a5bbeSBoris Popov }
183681a5bbeSBoris Popov
184681a5bbeSBoris Popov static int
smb_iod_treeconnect(struct smbiod * iod,struct smb_share * ssp)185681a5bbeSBoris Popov smb_iod_treeconnect(struct smbiod *iod, struct smb_share *ssp)
186681a5bbeSBoris Popov {
187681a5bbeSBoris Popov int error;
188681a5bbeSBoris Popov
189681a5bbeSBoris Popov if (iod->iod_state != SMBIOD_ST_VCACTIVE) {
190681a5bbeSBoris Popov if (iod->iod_state != SMBIOD_ST_DEAD)
191681a5bbeSBoris Popov return ENOTCONN;
192681a5bbeSBoris Popov iod->iod_state = SMBIOD_ST_RECONNECT;
193681a5bbeSBoris Popov error = smb_iod_connect(iod);
194681a5bbeSBoris Popov if (error)
195681a5bbeSBoris Popov return error;
196681a5bbeSBoris Popov }
197681a5bbeSBoris Popov SMBIODEBUG("tree reconnect\n");
198681a5bbeSBoris Popov SMBS_ST_LOCK(ssp);
199681a5bbeSBoris Popov ssp->ss_flags |= SMBS_RECONNECTING;
200681a5bbeSBoris Popov SMBS_ST_UNLOCK(ssp);
201681a5bbeSBoris Popov error = smb_smb_treeconnect(ssp, &iod->iod_scred);
202681a5bbeSBoris Popov SMBS_ST_LOCK(ssp);
203681a5bbeSBoris Popov ssp->ss_flags &= ~SMBS_RECONNECTING;
204681a5bbeSBoris Popov SMBS_ST_UNLOCK(ssp);
205681a5bbeSBoris Popov wakeup(&ssp->ss_vcgenid);
206681a5bbeSBoris Popov return error;
207681a5bbeSBoris Popov }
208681a5bbeSBoris Popov
209681a5bbeSBoris Popov static int
smb_iod_sendrq(struct smbiod * iod,struct smb_rq * rqp)210681a5bbeSBoris Popov smb_iod_sendrq(struct smbiod *iod, struct smb_rq *rqp)
211681a5bbeSBoris Popov {
212fce6fbfaSBoris Popov struct thread *td = iod->iod_td;
213681a5bbeSBoris Popov struct smb_vc *vcp = iod->iod_vc;
214681a5bbeSBoris Popov struct smb_share *ssp = rqp->sr_share;
215681a5bbeSBoris Popov struct mbuf *m;
216681a5bbeSBoris Popov int error;
217681a5bbeSBoris Popov
218681a5bbeSBoris Popov SMBIODEBUG("iod_state = %d\n", iod->iod_state);
219681a5bbeSBoris Popov switch (iod->iod_state) {
220681a5bbeSBoris Popov case SMBIOD_ST_NOTCONN:
221681a5bbeSBoris Popov smb_iod_rqprocessed(rqp, ENOTCONN);
222681a5bbeSBoris Popov return 0;
223681a5bbeSBoris Popov case SMBIOD_ST_DEAD:
224681a5bbeSBoris Popov iod->iod_state = SMBIOD_ST_RECONNECT;
225681a5bbeSBoris Popov return 0;
226681a5bbeSBoris Popov case SMBIOD_ST_RECONNECT:
227681a5bbeSBoris Popov return 0;
228681a5bbeSBoris Popov default:
229681a5bbeSBoris Popov break;
230681a5bbeSBoris Popov }
231681a5bbeSBoris Popov if (rqp->sr_sendcnt == 0) {
232681a5bbeSBoris Popov #ifdef movedtoanotherplace
233681a5bbeSBoris Popov if (vcp->vc_maxmux != 0 && iod->iod_muxcnt >= vcp->vc_maxmux)
234681a5bbeSBoris Popov return 0;
235681a5bbeSBoris Popov #endif
236a6a4232fSMarcel Moolenaar le16enc(rqp->sr_rqtid, ssp ? ssp->ss_tid : SMB_TID_UNKNOWN);
237a6a4232fSMarcel Moolenaar le16enc(rqp->sr_rquid, vcp ? vcp->vc_smbuid : 0);
238681a5bbeSBoris Popov mb_fixhdr(&rqp->sr_rq);
239190b2c4fSTim J. Robbins if (vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE)
240190b2c4fSTim J. Robbins smb_rq_sign(rqp);
241681a5bbeSBoris Popov }
242681a5bbeSBoris Popov if (rqp->sr_sendcnt++ > 5) {
243681a5bbeSBoris Popov rqp->sr_flags |= SMBR_RESTART;
244681a5bbeSBoris Popov smb_iod_rqprocessed(rqp, rqp->sr_lerror);
245681a5bbeSBoris Popov /*
246681a5bbeSBoris Popov * If all attempts to send a request failed, then
247681a5bbeSBoris Popov * something is seriously hosed.
248681a5bbeSBoris Popov */
249681a5bbeSBoris Popov return ENOTCONN;
250681a5bbeSBoris Popov }
251681a5bbeSBoris Popov SMBSDEBUG("M:%04x, P:%04x, U:%04x, T:%04x\n", rqp->sr_mid, 0, 0, 0);
252681a5bbeSBoris Popov m_dumpm(rqp->sr_rq.mb_top);
253eb1b1807SGleb Smirnoff m = m_copym(rqp->sr_rq.mb_top, 0, M_COPYALL, M_WAITOK);
254ea26d587SRuslan Ermilov error = rqp->sr_lerror = SMB_TRAN_SEND(vcp, m, td);
255681a5bbeSBoris Popov if (error == 0) {
256681a5bbeSBoris Popov getnanotime(&rqp->sr_timesent);
257681a5bbeSBoris Popov iod->iod_lastrqsent = rqp->sr_timesent;
258681a5bbeSBoris Popov rqp->sr_flags |= SMBR_SENT;
259681a5bbeSBoris Popov rqp->sr_state = SMBRQ_SENT;
260681a5bbeSBoris Popov return 0;
261681a5bbeSBoris Popov }
262681a5bbeSBoris Popov /*
263681a5bbeSBoris Popov * Check for fatal errors
264681a5bbeSBoris Popov */
265681a5bbeSBoris Popov if (SMB_TRAN_FATAL(vcp, error)) {
266681a5bbeSBoris Popov /*
267681a5bbeSBoris Popov * No further attempts should be made
268681a5bbeSBoris Popov */
269681a5bbeSBoris Popov return ENOTCONN;
270681a5bbeSBoris Popov }
271681a5bbeSBoris Popov if (smb_rq_intr(rqp))
272681a5bbeSBoris Popov smb_iod_rqprocessed(rqp, EINTR);
273681a5bbeSBoris Popov return 0;
274681a5bbeSBoris Popov }
275681a5bbeSBoris Popov
276681a5bbeSBoris Popov /*
277681a5bbeSBoris Popov * Process incoming packets
278681a5bbeSBoris Popov */
279681a5bbeSBoris Popov static int
smb_iod_recvall(struct smbiod * iod)280681a5bbeSBoris Popov smb_iod_recvall(struct smbiod *iod)
281681a5bbeSBoris Popov {
282681a5bbeSBoris Popov struct smb_vc *vcp = iod->iod_vc;
283fce6fbfaSBoris Popov struct thread *td = iod->iod_td;
284681a5bbeSBoris Popov struct smb_rq *rqp;
285681a5bbeSBoris Popov struct mbuf *m;
286681a5bbeSBoris Popov u_char *hp;
287681a5bbeSBoris Popov u_short mid;
288681a5bbeSBoris Popov int error;
289681a5bbeSBoris Popov
290681a5bbeSBoris Popov switch (iod->iod_state) {
291681a5bbeSBoris Popov case SMBIOD_ST_NOTCONN:
292681a5bbeSBoris Popov case SMBIOD_ST_DEAD:
293681a5bbeSBoris Popov case SMBIOD_ST_RECONNECT:
294681a5bbeSBoris Popov return 0;
295681a5bbeSBoris Popov default:
296681a5bbeSBoris Popov break;
297681a5bbeSBoris Popov }
298681a5bbeSBoris Popov for (;;) {
299681a5bbeSBoris Popov m = NULL;
300fce6fbfaSBoris Popov error = SMB_TRAN_RECV(vcp, &m, td);
301681a5bbeSBoris Popov if (error == EWOULDBLOCK)
302681a5bbeSBoris Popov break;
303681a5bbeSBoris Popov if (SMB_TRAN_FATAL(vcp, error)) {
304681a5bbeSBoris Popov smb_iod_dead(iod);
305681a5bbeSBoris Popov break;
306681a5bbeSBoris Popov }
307681a5bbeSBoris Popov if (error)
308681a5bbeSBoris Popov break;
309681a5bbeSBoris Popov if (m == NULL) {
310681a5bbeSBoris Popov SMBERROR("tran return NULL without error\n");
311681a5bbeSBoris Popov error = EPIPE;
312681a5bbeSBoris Popov continue;
313681a5bbeSBoris Popov }
314681a5bbeSBoris Popov m = m_pullup(m, SMB_HDRLEN);
315681a5bbeSBoris Popov if (m == NULL)
316681a5bbeSBoris Popov continue; /* wait for a good packet */
317681a5bbeSBoris Popov /*
318681a5bbeSBoris Popov * Now we got an entire and possibly invalid SMB packet.
319681a5bbeSBoris Popov * Be careful while parsing it.
320681a5bbeSBoris Popov */
321681a5bbeSBoris Popov m_dumpm(m);
322681a5bbeSBoris Popov hp = mtod(m, u_char*);
323681a5bbeSBoris Popov if (bcmp(hp, SMB_SIGNATURE, SMB_SIGLEN) != 0) {
324681a5bbeSBoris Popov m_freem(m);
325681a5bbeSBoris Popov continue;
326681a5bbeSBoris Popov }
327681a5bbeSBoris Popov mid = SMB_HDRMID(hp);
328681a5bbeSBoris Popov SMBSDEBUG("mid %04x\n", (u_int)mid);
329681a5bbeSBoris Popov SMB_IOD_RQLOCK(iod);
330681a5bbeSBoris Popov TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) {
331681a5bbeSBoris Popov if (rqp->sr_mid != mid)
332681a5bbeSBoris Popov continue;
333681a5bbeSBoris Popov SMBRQ_SLOCK(rqp);
334681a5bbeSBoris Popov if (rqp->sr_rp.md_top == NULL) {
335681a5bbeSBoris Popov md_initm(&rqp->sr_rp, m);
336681a5bbeSBoris Popov } else {
337681a5bbeSBoris Popov if (rqp->sr_flags & SMBR_MULTIPACKET) {
338681a5bbeSBoris Popov md_append_record(&rqp->sr_rp, m);
339681a5bbeSBoris Popov } else {
340681a5bbeSBoris Popov SMBRQ_SUNLOCK(rqp);
341681a5bbeSBoris Popov SMBERROR("duplicate response %d (ignored)\n", mid);
342681a5bbeSBoris Popov break;
343681a5bbeSBoris Popov }
344681a5bbeSBoris Popov }
345681a5bbeSBoris Popov SMBRQ_SUNLOCK(rqp);
346681a5bbeSBoris Popov smb_iod_rqprocessed(rqp, 0);
347681a5bbeSBoris Popov break;
348681a5bbeSBoris Popov }
349681a5bbeSBoris Popov SMB_IOD_RQUNLOCK(iod);
350681a5bbeSBoris Popov if (rqp == NULL) {
351681a5bbeSBoris Popov SMBERROR("drop resp with mid %d\n", (u_int)mid);
352681a5bbeSBoris Popov /* smb_printrqlist(vcp);*/
353681a5bbeSBoris Popov m_freem(m);
354681a5bbeSBoris Popov }
355681a5bbeSBoris Popov }
356681a5bbeSBoris Popov /*
357681a5bbeSBoris Popov * check for interrupts
358681a5bbeSBoris Popov */
359681a5bbeSBoris Popov SMB_IOD_RQLOCK(iod);
360681a5bbeSBoris Popov TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) {
3614093529dSJeff Roberson if (smb_td_intr(rqp->sr_cred->scr_td)) {
362681a5bbeSBoris Popov smb_iod_rqprocessed(rqp, EINTR);
363681a5bbeSBoris Popov }
364681a5bbeSBoris Popov }
365681a5bbeSBoris Popov SMB_IOD_RQUNLOCK(iod);
366681a5bbeSBoris Popov return 0;
367681a5bbeSBoris Popov }
368681a5bbeSBoris Popov
369681a5bbeSBoris Popov int
smb_iod_request(struct smbiod * iod,int event,void * ident)370681a5bbeSBoris Popov smb_iod_request(struct smbiod *iod, int event, void *ident)
371681a5bbeSBoris Popov {
372681a5bbeSBoris Popov struct smbiod_event *evp;
373681a5bbeSBoris Popov int error;
374681a5bbeSBoris Popov
375681a5bbeSBoris Popov SMBIODEBUG("\n");
376a163d034SWarner Losh evp = smb_zmalloc(sizeof(*evp), M_SMBIOD, M_WAITOK);
377681a5bbeSBoris Popov evp->ev_type = event;
378681a5bbeSBoris Popov evp->ev_ident = ident;
379681a5bbeSBoris Popov SMB_IOD_EVLOCK(iod);
380681a5bbeSBoris Popov STAILQ_INSERT_TAIL(&iod->iod_evlist, evp, ev_link);
381681a5bbeSBoris Popov if ((event & SMBIOD_EV_SYNC) == 0) {
382681a5bbeSBoris Popov SMB_IOD_EVUNLOCK(iod);
383681a5bbeSBoris Popov smb_iod_wakeup(iod);
384681a5bbeSBoris Popov return 0;
385681a5bbeSBoris Popov }
386681a5bbeSBoris Popov smb_iod_wakeup(iod);
387681a5bbeSBoris Popov msleep(evp, SMB_IOD_EVLOCKPTR(iod), PWAIT | PDROP, "90evw", 0);
388681a5bbeSBoris Popov error = evp->ev_error;
389681a5bbeSBoris Popov free(evp, M_SMBIOD);
390681a5bbeSBoris Popov return error;
391681a5bbeSBoris Popov }
392681a5bbeSBoris Popov
393681a5bbeSBoris Popov /*
394681a5bbeSBoris Popov * Place request in the queue.
395681a5bbeSBoris Popov * Request from smbiod have a high priority.
396681a5bbeSBoris Popov */
397681a5bbeSBoris Popov int
smb_iod_addrq(struct smb_rq * rqp)398681a5bbeSBoris Popov smb_iod_addrq(struct smb_rq *rqp)
399681a5bbeSBoris Popov {
400681a5bbeSBoris Popov struct smb_vc *vcp = rqp->sr_vc;
401681a5bbeSBoris Popov struct smbiod *iod = vcp->vc_iod;
402681a5bbeSBoris Popov int error;
403681a5bbeSBoris Popov
404681a5bbeSBoris Popov SMBIODEBUG("\n");
40562ca80a7STim J. Robbins if (rqp->sr_cred->scr_td != NULL &&
40662ca80a7STim J. Robbins rqp->sr_cred->scr_td->td_proc == iod->iod_p) {
407681a5bbeSBoris Popov rqp->sr_flags |= SMBR_INTERNAL;
408681a5bbeSBoris Popov SMB_IOD_RQLOCK(iod);
409681a5bbeSBoris Popov TAILQ_INSERT_HEAD(&iod->iod_rqlist, rqp, sr_link);
410681a5bbeSBoris Popov SMB_IOD_RQUNLOCK(iod);
411681a5bbeSBoris Popov for (;;) {
412681a5bbeSBoris Popov if (smb_iod_sendrq(iod, rqp) != 0) {
413681a5bbeSBoris Popov smb_iod_dead(iod);
414681a5bbeSBoris Popov break;
415681a5bbeSBoris Popov }
416681a5bbeSBoris Popov /*
417681a5bbeSBoris Popov * we don't need to lock state field here
418681a5bbeSBoris Popov */
419681a5bbeSBoris Popov if (rqp->sr_state != SMBRQ_NOTSENT)
420681a5bbeSBoris Popov break;
421681a5bbeSBoris Popov tsleep(&iod->iod_flags, PWAIT, "90sndw", hz);
422681a5bbeSBoris Popov }
423681a5bbeSBoris Popov if (rqp->sr_lerror)
424681a5bbeSBoris Popov smb_iod_removerq(rqp);
425681a5bbeSBoris Popov return rqp->sr_lerror;
426681a5bbeSBoris Popov }
427681a5bbeSBoris Popov
428681a5bbeSBoris Popov switch (iod->iod_state) {
429681a5bbeSBoris Popov case SMBIOD_ST_NOTCONN:
430681a5bbeSBoris Popov return ENOTCONN;
431681a5bbeSBoris Popov case SMBIOD_ST_DEAD:
432681a5bbeSBoris Popov error = smb_iod_request(vcp->vc_iod, SMBIOD_EV_CONNECT | SMBIOD_EV_SYNC, NULL);
433681a5bbeSBoris Popov if (error)
434681a5bbeSBoris Popov return error;
435681a5bbeSBoris Popov return EXDEV;
436681a5bbeSBoris Popov default:
437681a5bbeSBoris Popov break;
438681a5bbeSBoris Popov }
439681a5bbeSBoris Popov
440681a5bbeSBoris Popov SMB_IOD_RQLOCK(iod);
441681a5bbeSBoris Popov for (;;) {
442681a5bbeSBoris Popov if (vcp->vc_maxmux == 0) {
443681a5bbeSBoris Popov SMBERROR("maxmux == 0\n");
444681a5bbeSBoris Popov break;
445681a5bbeSBoris Popov }
446681a5bbeSBoris Popov if (iod->iod_muxcnt < vcp->vc_maxmux)
447681a5bbeSBoris Popov break;
448681a5bbeSBoris Popov iod->iod_muxwant++;
449681a5bbeSBoris Popov msleep(&iod->iod_muxwant, SMB_IOD_RQLOCKPTR(iod),
450681a5bbeSBoris Popov PWAIT, "90mux", 0);
451681a5bbeSBoris Popov }
452681a5bbeSBoris Popov iod->iod_muxcnt++;
453681a5bbeSBoris Popov TAILQ_INSERT_TAIL(&iod->iod_rqlist, rqp, sr_link);
454681a5bbeSBoris Popov SMB_IOD_RQUNLOCK(iod);
455681a5bbeSBoris Popov smb_iod_wakeup(iod);
456681a5bbeSBoris Popov return 0;
457681a5bbeSBoris Popov }
458681a5bbeSBoris Popov
459681a5bbeSBoris Popov int
smb_iod_removerq(struct smb_rq * rqp)460681a5bbeSBoris Popov smb_iod_removerq(struct smb_rq *rqp)
461681a5bbeSBoris Popov {
462681a5bbeSBoris Popov struct smb_vc *vcp = rqp->sr_vc;
463681a5bbeSBoris Popov struct smbiod *iod = vcp->vc_iod;
464681a5bbeSBoris Popov
465681a5bbeSBoris Popov SMBIODEBUG("\n");
466681a5bbeSBoris Popov if (rqp->sr_flags & SMBR_INTERNAL) {
467681a5bbeSBoris Popov SMB_IOD_RQLOCK(iod);
468681a5bbeSBoris Popov TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link);
469681a5bbeSBoris Popov SMB_IOD_RQUNLOCK(iod);
470681a5bbeSBoris Popov return 0;
471681a5bbeSBoris Popov }
472681a5bbeSBoris Popov SMB_IOD_RQLOCK(iod);
473681a5bbeSBoris Popov while (rqp->sr_flags & SMBR_XLOCK) {
474681a5bbeSBoris Popov rqp->sr_flags |= SMBR_XLOCKWANT;
475681a5bbeSBoris Popov msleep(rqp, SMB_IOD_RQLOCKPTR(iod), PWAIT, "90xrm", 0);
476681a5bbeSBoris Popov }
477681a5bbeSBoris Popov TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link);
478681a5bbeSBoris Popov iod->iod_muxcnt--;
479681a5bbeSBoris Popov if (iod->iod_muxwant) {
480681a5bbeSBoris Popov iod->iod_muxwant--;
481681a5bbeSBoris Popov wakeup(&iod->iod_muxwant);
482681a5bbeSBoris Popov }
483681a5bbeSBoris Popov SMB_IOD_RQUNLOCK(iod);
484681a5bbeSBoris Popov return 0;
485681a5bbeSBoris Popov }
486681a5bbeSBoris Popov
487681a5bbeSBoris Popov int
smb_iod_waitrq(struct smb_rq * rqp)488681a5bbeSBoris Popov smb_iod_waitrq(struct smb_rq *rqp)
489681a5bbeSBoris Popov {
490681a5bbeSBoris Popov struct smbiod *iod = rqp->sr_vc->vc_iod;
491681a5bbeSBoris Popov int error;
492681a5bbeSBoris Popov
493681a5bbeSBoris Popov SMBIODEBUG("\n");
494681a5bbeSBoris Popov if (rqp->sr_flags & SMBR_INTERNAL) {
495681a5bbeSBoris Popov for (;;) {
496681a5bbeSBoris Popov smb_iod_sendall(iod);
497681a5bbeSBoris Popov smb_iod_recvall(iod);
498681a5bbeSBoris Popov if (rqp->sr_rpgen != rqp->sr_rplast)
499681a5bbeSBoris Popov break;
500681a5bbeSBoris Popov tsleep(&iod->iod_flags, PWAIT, "90irq", hz);
501681a5bbeSBoris Popov }
502681a5bbeSBoris Popov smb_iod_removerq(rqp);
503681a5bbeSBoris Popov return rqp->sr_lerror;
504681a5bbeSBoris Popov }
505681a5bbeSBoris Popov SMBRQ_SLOCK(rqp);
506681a5bbeSBoris Popov if (rqp->sr_rpgen == rqp->sr_rplast)
507681a5bbeSBoris Popov msleep(&rqp->sr_state, SMBRQ_SLOCKPTR(rqp), PWAIT, "90wrq", 0);
508681a5bbeSBoris Popov rqp->sr_rplast++;
509681a5bbeSBoris Popov SMBRQ_SUNLOCK(rqp);
510681a5bbeSBoris Popov error = rqp->sr_lerror;
511681a5bbeSBoris Popov if (rqp->sr_flags & SMBR_MULTIPACKET) {
512681a5bbeSBoris Popov /*
513681a5bbeSBoris Popov * If request should stay in the list, then reinsert it
514681a5bbeSBoris Popov * at the end of queue so other waiters have chance to concur
515681a5bbeSBoris Popov */
516681a5bbeSBoris Popov SMB_IOD_RQLOCK(iod);
517681a5bbeSBoris Popov TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link);
518681a5bbeSBoris Popov TAILQ_INSERT_TAIL(&iod->iod_rqlist, rqp, sr_link);
519681a5bbeSBoris Popov SMB_IOD_RQUNLOCK(iod);
520681a5bbeSBoris Popov } else
521681a5bbeSBoris Popov smb_iod_removerq(rqp);
522681a5bbeSBoris Popov return error;
523681a5bbeSBoris Popov }
524681a5bbeSBoris Popov
525681a5bbeSBoris Popov static int
smb_iod_sendall(struct smbiod * iod)526681a5bbeSBoris Popov smb_iod_sendall(struct smbiod *iod)
527681a5bbeSBoris Popov {
528681a5bbeSBoris Popov struct smb_vc *vcp = iod->iod_vc;
529681a5bbeSBoris Popov struct smb_rq *rqp;
530681a5bbeSBoris Popov struct timespec ts, tstimeout;
531681a5bbeSBoris Popov int herror;
532681a5bbeSBoris Popov
533681a5bbeSBoris Popov herror = 0;
534681a5bbeSBoris Popov /*
535681a5bbeSBoris Popov * Loop through the list of requests and send them if possible
536681a5bbeSBoris Popov */
537681a5bbeSBoris Popov SMB_IOD_RQLOCK(iod);
538681a5bbeSBoris Popov TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) {
539681a5bbeSBoris Popov switch (rqp->sr_state) {
540681a5bbeSBoris Popov case SMBRQ_NOTSENT:
541681a5bbeSBoris Popov rqp->sr_flags |= SMBR_XLOCK;
542681a5bbeSBoris Popov SMB_IOD_RQUNLOCK(iod);
543681a5bbeSBoris Popov herror = smb_iod_sendrq(iod, rqp);
544681a5bbeSBoris Popov SMB_IOD_RQLOCK(iod);
545681a5bbeSBoris Popov rqp->sr_flags &= ~SMBR_XLOCK;
546681a5bbeSBoris Popov if (rqp->sr_flags & SMBR_XLOCKWANT) {
547681a5bbeSBoris Popov rqp->sr_flags &= ~SMBR_XLOCKWANT;
548681a5bbeSBoris Popov wakeup(rqp);
549681a5bbeSBoris Popov }
550681a5bbeSBoris Popov break;
551681a5bbeSBoris Popov case SMBRQ_SENT:
552681a5bbeSBoris Popov SMB_TRAN_GETPARAM(vcp, SMBTP_TIMEOUT, &tstimeout);
5536040822cSAlan Somers timespecadd(&tstimeout, &tstimeout, &tstimeout);
554681a5bbeSBoris Popov getnanotime(&ts);
5556040822cSAlan Somers timespecsub(&ts, &tstimeout, &ts);
556681a5bbeSBoris Popov if (timespeccmp(&ts, &rqp->sr_timesent, >)) {
557681a5bbeSBoris Popov smb_iod_rqprocessed(rqp, ETIMEDOUT);
558681a5bbeSBoris Popov }
559681a5bbeSBoris Popov break;
560681a5bbeSBoris Popov default:
561dacd8bbbSPeter Wemm break;
562681a5bbeSBoris Popov }
563681a5bbeSBoris Popov if (herror)
564681a5bbeSBoris Popov break;
565681a5bbeSBoris Popov }
566681a5bbeSBoris Popov SMB_IOD_RQUNLOCK(iod);
567681a5bbeSBoris Popov if (herror == ENOTCONN)
568681a5bbeSBoris Popov smb_iod_dead(iod);
569681a5bbeSBoris Popov return 0;
570681a5bbeSBoris Popov }
571681a5bbeSBoris Popov
572681a5bbeSBoris Popov /*
573681a5bbeSBoris Popov * "main" function for smbiod daemon
574681a5bbeSBoris Popov */
575681a5bbeSBoris Popov static __inline void
smb_iod_main(struct smbiod * iod)576681a5bbeSBoris Popov smb_iod_main(struct smbiod *iod)
577681a5bbeSBoris Popov {
578681a5bbeSBoris Popov /* struct smb_vc *vcp = iod->iod_vc;*/
579681a5bbeSBoris Popov struct smbiod_event *evp;
580681a5bbeSBoris Popov /* struct timespec tsnow;*/
581681a5bbeSBoris Popov
582681a5bbeSBoris Popov SMBIODEBUG("\n");
583681a5bbeSBoris Popov
584681a5bbeSBoris Popov /*
585681a5bbeSBoris Popov * Check all interesting events
586681a5bbeSBoris Popov */
587681a5bbeSBoris Popov for (;;) {
588681a5bbeSBoris Popov SMB_IOD_EVLOCK(iod);
589681a5bbeSBoris Popov evp = STAILQ_FIRST(&iod->iod_evlist);
590681a5bbeSBoris Popov if (evp == NULL) {
591681a5bbeSBoris Popov SMB_IOD_EVUNLOCK(iod);
592681a5bbeSBoris Popov break;
593681a5bbeSBoris Popov }
594681a5bbeSBoris Popov STAILQ_REMOVE_HEAD(&iod->iod_evlist, ev_link);
595681a5bbeSBoris Popov evp->ev_type |= SMBIOD_EV_PROCESSING;
596681a5bbeSBoris Popov SMB_IOD_EVUNLOCK(iod);
597681a5bbeSBoris Popov switch (evp->ev_type & SMBIOD_EV_MASK) {
598681a5bbeSBoris Popov case SMBIOD_EV_CONNECT:
599681a5bbeSBoris Popov iod->iod_state = SMBIOD_ST_RECONNECT;
600681a5bbeSBoris Popov evp->ev_error = smb_iod_connect(iod);
601681a5bbeSBoris Popov break;
602681a5bbeSBoris Popov case SMBIOD_EV_DISCONNECT:
603681a5bbeSBoris Popov evp->ev_error = smb_iod_disconnect(iod);
604681a5bbeSBoris Popov break;
605681a5bbeSBoris Popov case SMBIOD_EV_TREECONNECT:
606681a5bbeSBoris Popov evp->ev_error = smb_iod_treeconnect(iod, evp->ev_ident);
607681a5bbeSBoris Popov break;
608681a5bbeSBoris Popov case SMBIOD_EV_SHUTDOWN:
609681a5bbeSBoris Popov iod->iod_flags |= SMBIOD_SHUTDOWN;
610681a5bbeSBoris Popov break;
611681a5bbeSBoris Popov case SMBIOD_EV_NEWRQ:
612681a5bbeSBoris Popov break;
613681a5bbeSBoris Popov }
614681a5bbeSBoris Popov if (evp->ev_type & SMBIOD_EV_SYNC) {
615681a5bbeSBoris Popov SMB_IOD_EVLOCK(iod);
616681a5bbeSBoris Popov wakeup(evp);
617681a5bbeSBoris Popov SMB_IOD_EVUNLOCK(iod);
618681a5bbeSBoris Popov } else
619681a5bbeSBoris Popov free(evp, M_SMBIOD);
620681a5bbeSBoris Popov }
621681a5bbeSBoris Popov #if 0
622681a5bbeSBoris Popov if (iod->iod_state == SMBIOD_ST_VCACTIVE) {
623681a5bbeSBoris Popov getnanotime(&tsnow);
6246040822cSAlan Somers timespecsub(&tsnow, &iod->iod_pingtimo, &tsnow);
625681a5bbeSBoris Popov if (timespeccmp(&tsnow, &iod->iod_lastrqsent, >)) {
626681a5bbeSBoris Popov smb_smb_echo(vcp, &iod->iod_scred);
627681a5bbeSBoris Popov }
628681a5bbeSBoris Popov }
629681a5bbeSBoris Popov #endif
630681a5bbeSBoris Popov smb_iod_sendall(iod);
631681a5bbeSBoris Popov smb_iod_recvall(iod);
632681a5bbeSBoris Popov return;
633681a5bbeSBoris Popov }
634681a5bbeSBoris Popov
635681a5bbeSBoris Popov void
smb_iod_thread(void * arg)636681a5bbeSBoris Popov smb_iod_thread(void *arg)
637681a5bbeSBoris Popov {
638681a5bbeSBoris Popov struct smbiod *iod = arg;
639681a5bbeSBoris Popov
640e15e150dSAttilio Rao mtx_lock(&Giant);
641e15e150dSAttilio Rao
642fce6fbfaSBoris Popov /*
643fce6fbfaSBoris Popov * Here we assume that the thread structure will be the same
644fce6fbfaSBoris Popov * for an entire kthread (kproc, to be more precise) life.
645fce6fbfaSBoris Popov */
646fce6fbfaSBoris Popov iod->iod_td = curthread;
647fce6fbfaSBoris Popov smb_makescred(&iod->iod_scred, iod->iod_td, NULL);
648681a5bbeSBoris Popov while ((iod->iod_flags & SMBIOD_SHUTDOWN) == 0) {
649681a5bbeSBoris Popov smb_iod_main(iod);
650681a5bbeSBoris Popov SMBIODEBUG("going to sleep for %d ticks\n", iod->iod_sleeptimo);
651681a5bbeSBoris Popov if (iod->iod_flags & SMBIOD_SHUTDOWN)
652681a5bbeSBoris Popov break;
653681a5bbeSBoris Popov tsleep(&iod->iod_flags, PWAIT, "90idle", iod->iod_sleeptimo);
654681a5bbeSBoris Popov }
655e06f502cSRick Macklem
656e06f502cSRick Macklem /* We can now safely destroy the mutexes and free the iod structure. */
657e06f502cSRick Macklem smb_sl_destroy(&iod->iod_rqlock);
658e06f502cSRick Macklem smb_sl_destroy(&iod->iod_evlock);
659e06f502cSRick Macklem free(iod, M_SMBIOD);
660e15e150dSAttilio Rao mtx_unlock(&Giant);
6613745c395SJulian Elischer kproc_exit(0);
662681a5bbeSBoris Popov }
663681a5bbeSBoris Popov
664681a5bbeSBoris Popov int
smb_iod_create(struct smb_vc * vcp)665681a5bbeSBoris Popov smb_iod_create(struct smb_vc *vcp)
666681a5bbeSBoris Popov {
667681a5bbeSBoris Popov struct smbiod *iod;
668681a5bbeSBoris Popov int error;
669681a5bbeSBoris Popov
670a163d034SWarner Losh iod = smb_zmalloc(sizeof(*iod), M_SMBIOD, M_WAITOK);
671681a5bbeSBoris Popov iod->iod_id = smb_iod_next++;
672681a5bbeSBoris Popov iod->iod_state = SMBIOD_ST_NOTCONN;
673681a5bbeSBoris Popov iod->iod_vc = vcp;
674681a5bbeSBoris Popov iod->iod_sleeptimo = hz * SMBIOD_SLEEP_TIMO;
675681a5bbeSBoris Popov iod->iod_pingtimo.tv_sec = SMBIOD_PING_TIMO;
676681a5bbeSBoris Popov getnanotime(&iod->iod_lastrqsent);
677681a5bbeSBoris Popov vcp->vc_iod = iod;
678681a5bbeSBoris Popov smb_sl_init(&iod->iod_rqlock, "90rql");
679681a5bbeSBoris Popov TAILQ_INIT(&iod->iod_rqlist);
680681a5bbeSBoris Popov smb_sl_init(&iod->iod_evlock, "90evl");
681681a5bbeSBoris Popov STAILQ_INIT(&iod->iod_evlist);
6823745c395SJulian Elischer error = kproc_create(smb_iod_thread, iod, &iod->iod_p,
683316ec49aSScott Long RFNOWAIT, 0, "smbiod%d", iod->iod_id);
684681a5bbeSBoris Popov if (error) {
685681a5bbeSBoris Popov SMBERROR("can't start smbiod: %d", error);
68669527b11SRick Macklem vcp->vc_iod = NULL;
68769527b11SRick Macklem smb_sl_destroy(&iod->iod_rqlock);
68869527b11SRick Macklem smb_sl_destroy(&iod->iod_evlock);
689681a5bbeSBoris Popov free(iod, M_SMBIOD);
690681a5bbeSBoris Popov return error;
691681a5bbeSBoris Popov }
692681a5bbeSBoris Popov return 0;
693681a5bbeSBoris Popov }
694681a5bbeSBoris Popov
695681a5bbeSBoris Popov int
smb_iod_destroy(struct smbiod * iod)696681a5bbeSBoris Popov smb_iod_destroy(struct smbiod *iod)
697681a5bbeSBoris Popov {
698681a5bbeSBoris Popov smb_iod_request(iod, SMBIOD_EV_SHUTDOWN | SMBIOD_EV_SYNC, NULL);
699681a5bbeSBoris Popov return 0;
700681a5bbeSBoris Popov }
701681a5bbeSBoris Popov
702681a5bbeSBoris Popov int
smb_iod_init(void)703681a5bbeSBoris Popov smb_iod_init(void)
704681a5bbeSBoris Popov {
705681a5bbeSBoris Popov return 0;
706681a5bbeSBoris Popov }
707681a5bbeSBoris Popov
708681a5bbeSBoris Popov int
smb_iod_done(void)709681a5bbeSBoris Popov smb_iod_done(void)
710681a5bbeSBoris Popov {
711681a5bbeSBoris Popov return 0;
712681a5bbeSBoris Popov }
713