xref: /dragonfly/sys/netproto/smb/smb_iod.c (revision aa8d5dcb)
1 /*
2  * Copyright (c) 2000-2001 Boris Popov
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *    This product includes software developed by Boris Popov.
16  * 4. Neither the name of the author nor the names of any co-contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * $FreeBSD: src/sys/netsmb/smb_iod.c,v 1.1.2.2 2002/04/23 03:45:01 bp Exp $
33  * $DragonFly: src/sys/netproto/smb/smb_iod.c,v 1.8 2004/03/01 06:33:18 dillon Exp $
34  */
35 
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/proc.h>
39 #include <sys/kernel.h>
40 #include <sys/kthread.h>
41 #include <sys/malloc.h>
42 #include <sys/mbuf.h>
43 #include <sys/unistd.h>
44 
45 #include "smb.h"
46 #include "smb_conn.h"
47 #include "smb_rq.h"
48 #include "smb_tran.h"
49 #include "smb_trantcp.h"
50 
51 
52 #define SMBIOD_SLEEP_TIMO	2
53 #define	SMBIOD_PING_TIMO	60	/* seconds */
54 
55 #define	SMB_IOD_EVLOCKPTR(iod)	(&((iod)->iod_evlock))
56 #define	SMB_IOD_EVLOCK(ilock, iod)	smb_sl_lock(ilock, &((iod)->iod_evlock))
57 #define	SMB_IOD_EVUNLOCK(ilock)	smb_sl_unlock(ilock)
58 
59 #define	SMB_IOD_RQLOCKPTR(iod)	(&((iod)->iod_rqlock))
60 #define	SMB_IOD_RQLOCK(ilock, iod)	smb_sl_lock(ilock, &((iod)->iod_rqlock))
61 #define	SMB_IOD_RQUNLOCK(ilock)	smb_sl_unlock(ilock)
62 
63 #define	smb_iod_wakeup(iod)	wakeup(&(iod)->iod_flags)
64 
65 
66 static MALLOC_DEFINE(M_SMBIOD, "SMBIOD", "SMB network io daemon");
67 
68 static int smb_iod_next;
69 
70 static int  smb_iod_sendall(struct smbiod *iod);
71 static int  smb_iod_disconnect(struct smbiod *iod);
72 static void smb_iod_thread(void *);
73 
74 static __inline void
75 smb_iod_rqprocessed(struct smb_rq *rqp, int error)
76 {
77 	smb_ilock ilock;
78 
79 	SMBRQ_SLOCK(&ilock, rqp);
80 	rqp->sr_lerror = error;
81 	rqp->sr_rpgen++;
82 	rqp->sr_state = SMBRQ_NOTIFIED;
83 	wakeup(&rqp->sr_state);
84 	SMBRQ_SUNLOCK(&ilock);
85 }
86 
87 static void
88 smb_iod_invrq(struct smbiod *iod)
89 {
90 	struct smb_rq *rqp;
91 	smb_ilock ilock;
92 
93 	/*
94 	 * Invalidate all outstanding requests for this connection
95 	 */
96 	SMB_IOD_RQLOCK(&ilock, iod);
97 	TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) {
98 #if 0
99 		/* this makes no sense whatsoever XXX */
100 		if (rqp->sr_flags & SMBR_INTERNAL)
101 			SMBRQ_SUNLOCK(rqp);
102 #endif
103 		rqp->sr_flags |= SMBR_RESTART;
104 		smb_iod_rqprocessed(rqp, ENOTCONN);
105 	}
106 	SMB_IOD_RQUNLOCK(&ilock);
107 }
108 
109 static void
110 smb_iod_closetran(struct smbiod *iod)
111 {
112 	struct smb_vc *vcp = iod->iod_vc;
113 	struct thread *td = iod->iod_td;
114 
115 	if (vcp->vc_tdata == NULL)
116 		return;
117 	SMB_TRAN_DISCONNECT(vcp, td);
118 	SMB_TRAN_DONE(vcp, td);
119 	vcp->vc_tdata = NULL;
120 }
121 
122 static void
123 smb_iod_dead(struct smbiod *iod)
124 {
125 	iod->iod_state = SMBIOD_ST_DEAD;
126 	smb_iod_closetran(iod);
127 	smb_iod_invrq(iod);
128 }
129 
130 static int
131 smb_iod_connect(struct smbiod *iod)
132 {
133 	struct smb_vc *vcp = iod->iod_vc;
134 	struct thread *td = iod->iod_td;
135 	int error;
136 
137 	SMBIODEBUG("%d\n", iod->iod_state);
138 	switch(iod->iod_state) {
139 	    case SMBIOD_ST_VCACTIVE:
140 		SMBERROR("called for already opened connection\n");
141 		return EISCONN;
142 	    case SMBIOD_ST_DEAD:
143 		return ENOTCONN;	/* XXX: last error code ? */
144 	    default:
145 		break;
146 	}
147 	vcp->vc_genid++;
148 	error = 0;
149 	itry {
150 		ithrow(SMB_TRAN_CREATE(vcp, td));
151 		SMBIODEBUG("tcreate\n");
152 		if (vcp->vc_laddr) {
153 			ithrow(SMB_TRAN_BIND(vcp, vcp->vc_laddr, td));
154 		}
155 		SMBIODEBUG("tbind\n");
156 		ithrow(SMB_TRAN_CONNECT(vcp, vcp->vc_paddr, td));
157 		SMB_TRAN_SETPARAM(vcp, SMBTP_SELECTID, &iod->iod_flags);
158 		iod->iod_state = SMBIOD_ST_TRANACTIVE;
159 		SMBIODEBUG("tconnect\n");
160 /*		vcp->vc_mid = 0;*/
161 		ithrow(smb_smb_negotiate(vcp, &iod->iod_scred));
162 		SMBIODEBUG("snegotiate\n");
163 		ithrow(smb_smb_ssnsetup(vcp, &iod->iod_scred));
164 		iod->iod_state = SMBIOD_ST_VCACTIVE;
165 		SMBIODEBUG("completed\n");
166 		smb_iod_invrq(iod);
167 	} icatch(error) {
168 		smb_iod_dead(iod);
169 	} ifinally {
170 	} iendtry;
171 	return error;
172 }
173 
174 static int
175 smb_iod_disconnect(struct smbiod *iod)
176 {
177 	struct smb_vc *vcp = iod->iod_vc;
178 
179 	SMBIODEBUG("\n");
180 	if (iod->iod_state == SMBIOD_ST_VCACTIVE) {
181 		smb_smb_ssnclose(vcp, &iod->iod_scred);
182 		iod->iod_state = SMBIOD_ST_TRANACTIVE;
183 	}
184 	vcp->vc_smbuid = SMB_UID_UNKNOWN;
185 	smb_iod_closetran(iod);
186 	iod->iod_state = SMBIOD_ST_NOTCONN;
187 	return 0;
188 }
189 
190 static int
191 smb_iod_treeconnect(struct smbiod *iod, struct smb_share *ssp)
192 {
193 	int error;
194 	smb_ilock ilock;
195 
196 	if (iod->iod_state != SMBIOD_ST_VCACTIVE) {
197 		if (iod->iod_state != SMBIOD_ST_DEAD)
198 			return ENOTCONN;
199 		iod->iod_state = SMBIOD_ST_RECONNECT;
200 		error = smb_iod_connect(iod);
201 		if (error)
202 			return error;
203 	}
204 	SMBIODEBUG("tree reconnect\n");
205 	SMBS_ST_LOCK(&ilock, ssp);
206 	ssp->ss_flags |= SMBS_RECONNECTING;
207 	SMBS_ST_UNLOCK(&ilock);
208 	error = smb_smb_treeconnect(ssp, &iod->iod_scred);
209 	SMBS_ST_LOCK(&ilock, ssp);
210 	ssp->ss_flags &= ~SMBS_RECONNECTING;
211 	SMBS_ST_UNLOCK(&ilock);
212 	wakeup(&ssp->ss_vcgenid);
213 	return error;
214 }
215 
216 static int
217 smb_iod_sendrq(struct smbiod *iod, struct smb_rq *rqp)
218 {
219 	struct thread *td = iod->iod_td;
220 	struct smb_vc *vcp = iod->iod_vc;
221 	struct smb_share *ssp = rqp->sr_share;
222 	struct mbuf *m;
223 	int error;
224 
225 	SMBIODEBUG("iod_state = %d\n", iod->iod_state);
226 	switch (iod->iod_state) {
227 	    case SMBIOD_ST_NOTCONN:
228 		smb_iod_rqprocessed(rqp, ENOTCONN);
229 		return 0;
230 	    case SMBIOD_ST_DEAD:
231 		iod->iod_state = SMBIOD_ST_RECONNECT;
232 		return 0;
233 	    case SMBIOD_ST_RECONNECT:
234 		return 0;
235 	    default:
236 		break;
237 	}
238 	if (rqp->sr_sendcnt == 0) {
239 #ifdef movedtoanotherplace
240 		if (vcp->vc_maxmux != 0 && iod->iod_muxcnt >= vcp->vc_maxmux)
241 			return 0;
242 #endif
243 		*rqp->sr_rqtid = htoles(ssp ? ssp->ss_tid : SMB_TID_UNKNOWN);
244 		*rqp->sr_rquid = htoles(vcp ? vcp->vc_smbuid : 0);
245 		mb_fixhdr(&rqp->sr_rq);
246 	}
247 	if (rqp->sr_sendcnt++ > 5) {
248 		rqp->sr_flags |= SMBR_RESTART;
249 		smb_iod_rqprocessed(rqp, rqp->sr_lerror);
250 		/*
251 		 * If all attempts to send a request failed, then
252 		 * something is seriously hosed.
253 		 */
254 		return ENOTCONN;
255 	}
256 	SMBSDEBUG("M:%04x, P:%04x, U:%04x, T:%04x\n", rqp->sr_mid, 0, 0, 0);
257 	m_dumpm(rqp->sr_rq.mb_top);
258 	m = m_copym(rqp->sr_rq.mb_top, 0, M_COPYALL, M_WAIT);
259 	error = rqp->sr_lerror = m ? SMB_TRAN_SEND(vcp, m, td) : ENOBUFS;
260 	if (error == 0) {
261 		getnanotime(&rqp->sr_timesent);
262 		iod->iod_lastrqsent = rqp->sr_timesent;
263 		rqp->sr_flags |= SMBR_SENT;
264 		rqp->sr_state = SMBRQ_SENT;
265 		return 0;
266 	}
267 	/*
268 	 * Check for fatal errors
269 	 */
270 	if (SMB_TRAN_FATAL(vcp, error)) {
271 		/*
272 		 * No further attempts should be made
273 		 */
274 		return ENOTCONN;
275 	}
276 	if (smb_rq_intr(rqp))
277 		smb_iod_rqprocessed(rqp, EINTR);
278 	return 0;
279 }
280 
281 /*
282  * Process incoming packets
283  */
284 static int
285 smb_iod_recvall(struct smbiod *iod)
286 {
287 	struct smb_vc *vcp = iod->iod_vc;
288 	struct thread *td = iod->iod_td;
289 	struct smb_rq *rqp;
290 	struct mbuf *m;
291 	u_char *hp;
292 	u_short mid;
293 	int error;
294 	smb_ilock ilock;
295 	smb_ilock jlock;
296 
297 	switch (iod->iod_state) {
298 	    case SMBIOD_ST_NOTCONN:
299 	    case SMBIOD_ST_DEAD:
300 	    case SMBIOD_ST_RECONNECT:
301 		return 0;
302 	    default:
303 		break;
304 	}
305 	for (;;) {
306 		m = NULL;
307 		error = SMB_TRAN_RECV(vcp, &m, td);
308 		if (error == EWOULDBLOCK)
309 			break;
310 		if (SMB_TRAN_FATAL(vcp, error)) {
311 			smb_iod_dead(iod);
312 			break;
313 		}
314 		if (error)
315 			break;
316 		if (m == NULL) {
317 			SMBERROR("tran return NULL without error\n");
318 			error = EPIPE;
319 			continue;
320 		}
321 		m = m_pullup(m, SMB_HDRLEN);
322 		if (m == NULL)
323 			continue;	/* wait for a good packet */
324 		/*
325 		 * Now we got an entire and possibly invalid SMB packet.
326 		 * Be careful while parsing it.
327 		 */
328 		m_dumpm(m);
329 		hp = mtod(m, u_char*);
330 		if (bcmp(hp, SMB_SIGNATURE, SMB_SIGLEN) != 0) {
331 			m_freem(m);
332 			continue;
333 		}
334 		mid = SMB_HDRMID(hp);
335 		SMBSDEBUG("mid %04x\n", (u_int)mid);
336 		SMB_IOD_RQLOCK(&ilock, iod);
337 		TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) {
338 			if (rqp->sr_mid != mid)
339 				continue;
340 			SMBRQ_SLOCK(&jlock, rqp);
341 			if (rqp->sr_rp.md_top == NULL) {
342 				md_initm(&rqp->sr_rp, m);
343 			} else {
344 				if (rqp->sr_flags & SMBR_MULTIPACKET) {
345 					md_append_record(&rqp->sr_rp, m);
346 				} else {
347 					SMBRQ_SUNLOCK(&jlock);
348 					SMBERROR("duplicate response %d (ignored)\n", mid);
349 					break;
350 				}
351 			}
352 			SMBRQ_SUNLOCK(&jlock);
353 			smb_iod_rqprocessed(rqp, 0);
354 			break;
355 		}
356 		SMB_IOD_RQUNLOCK(&ilock);
357 		if (rqp == NULL) {
358 			SMBERROR("drop resp with mid %d\n", (u_int)mid);
359 /*			smb_printrqlist(vcp);*/
360 			m_freem(m);
361 		}
362 	}
363 	/*
364 	 * check for interrupts
365 	 */
366 	SMB_IOD_RQLOCK(&ilock, iod);
367 	TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) {
368 		if (smb_proc_intr(rqp->sr_cred->scr_td)) {
369 			smb_iod_rqprocessed(rqp, EINTR);
370 		}
371 	}
372 	SMB_IOD_RQUNLOCK(&ilock);
373 	return 0;
374 }
375 
376 int
377 smb_iod_request(struct smbiod *iod, int event, void *ident)
378 {
379 	struct smbiod_event *evp;
380 	int error;
381 	smb_ilock ilock;
382 
383 	SMBIODEBUG("\n");
384 	evp = smb_zmalloc(sizeof(*evp), M_SMBIOD, M_WAITOK);
385 	evp->ev_type = event;
386 	evp->ev_ident = ident;
387 	SMB_IOD_EVLOCK(&ilock, iod);
388 	STAILQ_INSERT_TAIL(&iod->iod_evlist, evp, ev_link);
389 	if ((event & SMBIOD_EV_SYNC) == 0) {
390 		SMB_IOD_EVUNLOCK(&ilock);
391 		smb_iod_wakeup(iod);
392 		return 0;
393 	}
394 	smb_iod_wakeup(iod);
395 	smb_sleep(evp, &ilock, PDROP, "90evw", 0);
396 	error = evp->ev_error;
397 	free(evp, M_SMBIOD);
398 	return error;
399 }
400 
401 /*
402  * Place request in the queue.
403  * Request from smbiod have a high priority.
404  */
405 int
406 smb_iod_addrq(struct smb_rq *rqp)
407 {
408 	struct smb_vc *vcp = rqp->sr_vc;
409 	struct smbiod *iod = vcp->vc_iod;
410 	smb_ilock ilock;
411 	int error;
412 
413 	SMBIODEBUG("\n");
414 	if (rqp->sr_cred->scr_td == iod->iod_td) {
415 		rqp->sr_flags |= SMBR_INTERNAL;
416 		SMB_IOD_RQLOCK(&ilock, iod);
417 		TAILQ_INSERT_HEAD(&iod->iod_rqlist, rqp, sr_link);
418 		SMB_IOD_RQUNLOCK(&ilock);
419 		for (;;) {
420 			if (smb_iod_sendrq(iod, rqp) != 0) {
421 				smb_iod_dead(iod);
422 				break;
423 			}
424 			/*
425 			 * we don't need to lock state field here
426 			 */
427 			if (rqp->sr_state != SMBRQ_NOTSENT)
428 				break;
429 			tsleep(&iod->iod_flags, 0, "90sndw", hz);
430 		}
431 		if (rqp->sr_lerror)
432 			smb_iod_removerq(rqp);
433 		return rqp->sr_lerror;
434 	}
435 
436 	switch (iod->iod_state) {
437 	    case SMBIOD_ST_NOTCONN:
438 		return ENOTCONN;
439 	    case SMBIOD_ST_DEAD:
440 		error = smb_iod_request(vcp->vc_iod, SMBIOD_EV_CONNECT | SMBIOD_EV_SYNC, NULL);
441 		if (error)
442 			return error;
443 		return EXDEV;
444 	    default:
445 		break;
446 	}
447 
448 	SMB_IOD_RQLOCK(&ilock, iod);
449 	for (;;) {
450 		if (vcp->vc_maxmux == 0) {
451 			SMBERROR("maxmux == 0\n");
452 			break;
453 		}
454 		if (iod->iod_muxcnt < vcp->vc_maxmux)
455 			break;
456 		iod->iod_muxwant++;
457 		smb_sleep(&iod->iod_muxwant, &ilock, 0, "90mux", 0);
458 	}
459 	iod->iod_muxcnt++;
460 	TAILQ_INSERT_TAIL(&iod->iod_rqlist, rqp, sr_link);
461 	SMB_IOD_RQUNLOCK(&ilock);
462 	smb_iod_wakeup(iod);
463 	return 0;
464 }
465 
466 int
467 smb_iod_removerq(struct smb_rq *rqp)
468 {
469 	struct smb_vc *vcp = rqp->sr_vc;
470 	struct smbiod *iod = vcp->vc_iod;
471 	smb_ilock ilock;
472 
473 	SMBIODEBUG("\n");
474 	if (rqp->sr_flags & SMBR_INTERNAL) {
475 		SMB_IOD_RQLOCK(&ilock, iod);
476 		TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link);
477 		SMB_IOD_RQUNLOCK(&ilock);
478 		return 0;
479 	}
480 	SMB_IOD_RQLOCK(&ilock, iod);
481 	while (rqp->sr_flags & SMBR_XLOCK) {
482 		rqp->sr_flags |= SMBR_XLOCKWANT;
483 		smb_sleep(rqp, &ilock, 0, "90xrm", 0);
484 	}
485 	TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link);
486 	iod->iod_muxcnt--;
487 	if (iod->iod_muxwant) {
488 		iod->iod_muxwant--;
489 		wakeup(&iod->iod_muxwant);
490 	}
491 	SMB_IOD_RQUNLOCK(&ilock);
492 	return 0;
493 }
494 
495 int
496 smb_iod_waitrq(struct smb_rq *rqp)
497 {
498 	struct smbiod *iod = rqp->sr_vc->vc_iod;
499 	smb_ilock ilock;
500 	int error;
501 
502 	SMBIODEBUG("\n");
503 	if (rqp->sr_flags & SMBR_INTERNAL) {
504 		for (;;) {
505 			smb_iod_sendall(iod);
506 			smb_iod_recvall(iod);
507 			if (rqp->sr_rpgen != rqp->sr_rplast)
508 				break;
509 			tsleep(&iod->iod_flags, 0, "90irq", hz);
510 		}
511 		smb_iod_removerq(rqp);
512 		return rqp->sr_lerror;
513 
514 	}
515 	SMBRQ_SLOCK(&ilock, rqp);
516 	if (rqp->sr_rpgen == rqp->sr_rplast)
517 		smb_sleep(&rqp->sr_state, &ilock, 0, "90wrq", 0);
518 	rqp->sr_rplast++;
519 	SMBRQ_SUNLOCK(&ilock);
520 	error = rqp->sr_lerror;
521 	if (rqp->sr_flags & SMBR_MULTIPACKET) {
522 		/*
523 		 * If request should stay in the list, then reinsert it
524 		 * at the end of queue so other waiters have chance to concur
525 		 */
526 		SMB_IOD_RQLOCK(&ilock, iod);
527 		TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link);
528 		TAILQ_INSERT_TAIL(&iod->iod_rqlist, rqp, sr_link);
529 		SMB_IOD_RQUNLOCK(&ilock);
530 	} else
531 		smb_iod_removerq(rqp);
532 	return error;
533 }
534 
535 
536 static int
537 smb_iod_sendall(struct smbiod *iod)
538 {
539 	struct smb_vc *vcp = iod->iod_vc;
540 	struct smb_rq *rqp;
541 	struct timespec ts, tstimeout;
542 	smb_ilock ilock;
543 	int herror;
544 
545 	herror = 0;
546 	/*
547 	 * Loop through the list of requests and send them if possible
548 	 */
549 	SMB_IOD_RQLOCK(&ilock, iod);
550 	TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) {
551 		switch (rqp->sr_state) {
552 		    case SMBRQ_NOTSENT:
553 			rqp->sr_flags |= SMBR_XLOCK;
554 			SMB_IOD_RQUNLOCK(&ilock);
555 			herror = smb_iod_sendrq(iod, rqp);
556 			SMB_IOD_RQLOCK(&ilock, iod);
557 			rqp->sr_flags &= ~SMBR_XLOCK;
558 			if (rqp->sr_flags & SMBR_XLOCKWANT) {
559 				rqp->sr_flags &= ~SMBR_XLOCKWANT;
560 				wakeup(rqp);
561 			}
562 			break;
563 		    case SMBRQ_SENT:
564 			SMB_TRAN_GETPARAM(vcp, SMBTP_TIMEOUT, &tstimeout);
565 			timespecadd(&tstimeout, &tstimeout);
566 			getnanotime(&ts);
567 			timespecsub(&ts, &tstimeout);
568 			if (timespeccmp(&ts, &rqp->sr_timesent, >)) {
569 				smb_iod_rqprocessed(rqp, ETIMEDOUT);
570 			}
571 			break;
572 		    default:
573 		}
574 		if (herror)
575 			break;
576 	}
577 	SMB_IOD_RQUNLOCK(&ilock);
578 	if (herror == ENOTCONN)
579 		smb_iod_dead(iod);
580 	return 0;
581 }
582 
583 /*
584  * "main" function for smbiod daemon
585  */
586 static __inline void
587 smb_iod_main(struct smbiod *iod)
588 {
589 /*	struct smb_vc *vcp = iod->iod_vc;*/
590 	struct smbiod_event *evp;
591 /*	struct timespec tsnow;*/
592 	int error;
593 	smb_ilock ilock;
594 
595 	SMBIODEBUG("\n");
596 	error = 0;
597 
598 	/*
599 	 * Check all interesting events
600 	 */
601 	for (;;) {
602 		SMB_IOD_EVLOCK(&ilock, iod);
603 		evp = STAILQ_FIRST(&iod->iod_evlist);
604 		if (evp == NULL) {
605 			SMB_IOD_EVUNLOCK(&ilock);
606 			break;
607 		}
608 		STAILQ_REMOVE_HEAD(&iod->iod_evlist, ev_link);
609 		evp->ev_type |= SMBIOD_EV_PROCESSING;
610 		SMB_IOD_EVUNLOCK(&ilock);
611 		switch (evp->ev_type & SMBIOD_EV_MASK) {
612 		    case SMBIOD_EV_CONNECT:
613 			iod->iod_state = SMBIOD_ST_RECONNECT;
614 			evp->ev_error = smb_iod_connect(iod);
615 			break;
616 		    case SMBIOD_EV_DISCONNECT:
617 			evp->ev_error = smb_iod_disconnect(iod);
618 			break;
619 		    case SMBIOD_EV_TREECONNECT:
620 			evp->ev_error = smb_iod_treeconnect(iod, evp->ev_ident);
621 			break;
622 		    case SMBIOD_EV_SHUTDOWN:
623 			iod->iod_flags |= SMBIOD_SHUTDOWN;
624 			break;
625 		    case SMBIOD_EV_NEWRQ:
626 			break;
627 		}
628 		if (evp->ev_type & SMBIOD_EV_SYNC) {
629 			SMB_IOD_EVLOCK(&ilock, iod);
630 			wakeup(evp);
631 			SMB_IOD_EVUNLOCK(&ilock);
632 		} else
633 			free(evp, M_SMBIOD);
634 	}
635 #if 0
636 	if (iod->iod_state == SMBIOD_ST_VCACTIVE) {
637 		getnanotime(&tsnow);
638 		timespecsub(&tsnow, &iod->iod_pingtimo);
639 		if (timespeccmp(&tsnow, &iod->iod_lastrqsent, >)) {
640 			smb_smb_echo(vcp, &iod->iod_scred);
641 		}
642 	}
643 #endif
644 	smb_iod_sendall(iod);
645 	smb_iod_recvall(iod);
646 	return;
647 }
648 
649 #define	kthread_create_compat	kthread_create2
650 
651 
652 void
653 smb_iod_thread(void *arg)
654 {
655 	struct smbiod *iod = arg;
656 
657 	smb_makescred(&iod->iod_scred, iod->iod_td, NULL);
658 	while ((iod->iod_flags & SMBIOD_SHUTDOWN) == 0) {
659 		smb_iod_main(iod);
660 		SMBIODEBUG("going to sleep for %d ticks\n", iod->iod_sleeptimo);
661 		if (iod->iod_flags & SMBIOD_SHUTDOWN)
662 			break;
663 		tsleep(&iod->iod_flags, 0, "90idle", iod->iod_sleeptimo);
664 	}
665 	kthread_exit();
666 }
667 
668 int
669 smb_iod_create(struct smb_vc *vcp)
670 {
671 	struct smbiod *iod;
672 	struct proc *newp = NULL;
673 	int error;
674 
675 	iod = smb_zmalloc(sizeof(*iod), M_SMBIOD, M_WAITOK);
676 	iod->iod_id = smb_iod_next++;
677 	iod->iod_state = SMBIOD_ST_NOTCONN;
678 	iod->iod_vc = vcp;
679 	iod->iod_sleeptimo = hz * SMBIOD_SLEEP_TIMO;
680 	iod->iod_pingtimo.tv_sec = SMBIOD_PING_TIMO;
681 	getnanotime(&iod->iod_lastrqsent);
682 	vcp->vc_iod = iod;
683 	smb_sl_init(&iod->iod_rqlock, "90rql");
684 	TAILQ_INIT(&iod->iod_rqlist);
685 	smb_sl_init(&iod->iod_evlock, "90evl");
686 	STAILQ_INIT(&iod->iod_evlist);
687 	error = kthread_create_compat(smb_iod_thread, iod, &newp,
688 	    RFNOWAIT, "smbiod%d", iod->iod_id);
689 	if (error) {
690 		SMBERROR("can't start smbiod: %d", error);
691 		free(iod, M_SMBIOD);
692 		return error;
693 	}
694 	iod->iod_td = newp->p_thread;
695 	return 0;
696 }
697 
698 int
699 smb_iod_destroy(struct smbiod *iod)
700 {
701 	smb_iod_request(iod, SMBIOD_EV_SHUTDOWN | SMBIOD_EV_SYNC, NULL);
702 	smb_sl_destroy(&iod->iod_rqlock);
703 	smb_sl_destroy(&iod->iod_evlock);
704 	free(iod, M_SMBIOD);
705 	return 0;
706 }
707 
708 int
709 smb_iod_init(void)
710 {
711 	return 0;
712 }
713 
714 int
715 smb_iod_done(void)
716 {
717 	return 0;
718 }
719 
720