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