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