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