xref: /freebsd/sys/netsmb/smb_iod.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
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