smb_iod.c revision 119376
175374Sbp/*
275374Sbp * Copyright (c) 2000-2001 Boris Popov
375374Sbp * All rights reserved.
475374Sbp *
575374Sbp * Redistribution and use in source and binary forms, with or without
675374Sbp * modification, are permitted provided that the following conditions
775374Sbp * are met:
875374Sbp * 1. Redistributions of source code must retain the above copyright
975374Sbp *    notice, this list of conditions and the following disclaimer.
1075374Sbp * 2. Redistributions in binary form must reproduce the above copyright
1175374Sbp *    notice, this list of conditions and the following disclaimer in the
1275374Sbp *    documentation and/or other materials provided with the distribution.
1375374Sbp * 3. All advertising materials mentioning features or use of this software
1475374Sbp *    must display the following acknowledgement:
1575374Sbp *    This product includes software developed by Boris Popov.
1675374Sbp * 4. Neither the name of the author nor the names of any co-contributors
1775374Sbp *    may be used to endorse or promote products derived from this software
1875374Sbp *    without specific prior written permission.
1975374Sbp *
2075374Sbp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2175374Sbp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2275374Sbp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2375374Sbp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2475374Sbp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2575374Sbp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2675374Sbp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2775374Sbp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2875374Sbp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2975374Sbp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3075374Sbp * SUCH DAMAGE.
3175374Sbp */
32116189Sobrien
33116189Sobrien#include <sys/cdefs.h>
34116189Sobrien__FBSDID("$FreeBSD: head/sys/netsmb/smb_iod.c 119376 2003-08-23 21:43:33Z marcel $");
3575374Sbp
3675374Sbp#include <sys/param.h>
3775374Sbp#include <sys/systm.h>
3895533Smike#include <sys/endian.h>
3975374Sbp#include <sys/proc.h>
4075374Sbp#include <sys/kernel.h>
4175374Sbp#include <sys/kthread.h>
4275374Sbp#include <sys/malloc.h>
4375374Sbp#include <sys/mbuf.h>
4475374Sbp#include <sys/unistd.h>
4575374Sbp
4675374Sbp#include <netsmb/smb.h>
4775374Sbp#include <netsmb/smb_conn.h>
4875374Sbp#include <netsmb/smb_rq.h>
4975374Sbp#include <netsmb/smb_tran.h>
5075374Sbp#include <netsmb/smb_trantcp.h>
5175374Sbp
5275374Sbp
5375374Sbp#define SMBIOD_SLEEP_TIMO	2
5475374Sbp#define	SMBIOD_PING_TIMO	60	/* seconds */
5575374Sbp
5675374Sbp#define	SMB_IOD_EVLOCKPTR(iod)	(&((iod)->iod_evlock))
5775374Sbp#define	SMB_IOD_EVLOCK(iod)	smb_sl_lock(&((iod)->iod_evlock))
5875374Sbp#define	SMB_IOD_EVUNLOCK(iod)	smb_sl_unlock(&((iod)->iod_evlock))
5975374Sbp
6075374Sbp#define	SMB_IOD_RQLOCKPTR(iod)	(&((iod)->iod_rqlock))
6175374Sbp#define	SMB_IOD_RQLOCK(iod)	smb_sl_lock(&((iod)->iod_rqlock))
6275374Sbp#define	SMB_IOD_RQUNLOCK(iod)	smb_sl_unlock(&((iod)->iod_rqlock))
6375374Sbp
6475374Sbp#define	smb_iod_wakeup(iod)	wakeup(&(iod)->iod_flags)
6575374Sbp
6675374Sbp
6775374Sbpstatic MALLOC_DEFINE(M_SMBIOD, "SMBIOD", "SMB network io daemon");
6875374Sbp
6975374Sbpstatic int smb_iod_next;
7075374Sbp
7175374Sbpstatic int  smb_iod_sendall(struct smbiod *iod);
7275374Sbpstatic int  smb_iod_disconnect(struct smbiod *iod);
7375374Sbpstatic void smb_iod_thread(void *);
7475374Sbp
7575374Sbpstatic __inline void
7675374Sbpsmb_iod_rqprocessed(struct smb_rq *rqp, int error)
7775374Sbp{
7875374Sbp	SMBRQ_SLOCK(rqp);
7975374Sbp	rqp->sr_lerror = error;
8075374Sbp	rqp->sr_rpgen++;
8175374Sbp	rqp->sr_state = SMBRQ_NOTIFIED;
8275374Sbp	wakeup(&rqp->sr_state);
8375374Sbp	SMBRQ_SUNLOCK(rqp);
8475374Sbp}
8575374Sbp
8675374Sbpstatic void
8775374Sbpsmb_iod_invrq(struct smbiod *iod)
8875374Sbp{
8975374Sbp	struct smb_rq *rqp;
9075374Sbp
9175374Sbp	/*
9282045Sbp	 * Invalidate all outstanding requests for this connection
9375374Sbp	 */
9475374Sbp	SMB_IOD_RQLOCK(iod);
9575374Sbp	TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) {
9675374Sbp		if (rqp->sr_flags & SMBR_INTERNAL)
9775374Sbp			SMBRQ_SUNLOCK(rqp);
9875374Sbp		rqp->sr_flags |= SMBR_RESTART;
9975374Sbp		smb_iod_rqprocessed(rqp, ENOTCONN);
10075374Sbp	}
10175374Sbp	SMB_IOD_RQUNLOCK(iod);
10275374Sbp}
10375374Sbp
10475374Sbpstatic void
10575374Sbpsmb_iod_closetran(struct smbiod *iod)
10675374Sbp{
10775374Sbp	struct smb_vc *vcp = iod->iod_vc;
10887192Sbp	struct thread *td = iod->iod_td;
10975374Sbp
11075374Sbp	if (vcp->vc_tdata == NULL)
11175374Sbp		return;
11287192Sbp	SMB_TRAN_DISCONNECT(vcp, td);
11387192Sbp	SMB_TRAN_DONE(vcp, td);
11475374Sbp	vcp->vc_tdata = NULL;
11575374Sbp}
11675374Sbp
11775374Sbpstatic void
11875374Sbpsmb_iod_dead(struct smbiod *iod)
11975374Sbp{
12075374Sbp	iod->iod_state = SMBIOD_ST_DEAD;
12175374Sbp	smb_iod_closetran(iod);
12275374Sbp	smb_iod_invrq(iod);
12375374Sbp}
12475374Sbp
12575374Sbpstatic int
12675374Sbpsmb_iod_connect(struct smbiod *iod)
12775374Sbp{
12875374Sbp	struct smb_vc *vcp = iod->iod_vc;
12987192Sbp	struct thread *td = iod->iod_td;
13075374Sbp	int error;
13175374Sbp
13275374Sbp	SMBIODEBUG("%d\n", iod->iod_state);
13375374Sbp	switch(iod->iod_state) {
13475374Sbp	    case SMBIOD_ST_VCACTIVE:
13575374Sbp		SMBERROR("called for already opened connection\n");
13675374Sbp		return EISCONN;
13775374Sbp	    case SMBIOD_ST_DEAD:
13875374Sbp		return ENOTCONN;	/* XXX: last error code ? */
13975374Sbp	    default:
14075374Sbp		break;
14175374Sbp	}
14275374Sbp	vcp->vc_genid++;
14375374Sbp	error = 0;
144119376Smarcel
145119376Smarcel	error = (int)SMB_TRAN_CREATE(vcp, td);
146119376Smarcel	if (error)
147119376Smarcel		goto fail;
148119376Smarcel	SMBIODEBUG("tcreate\n");
149119376Smarcel	if (vcp->vc_laddr) {
150119376Smarcel		error = (int)SMB_TRAN_BIND(vcp, vcp->vc_laddr, td);
151119376Smarcel		if (error)
152119376Smarcel			goto fail;
153119376Smarcel	}
154119376Smarcel	SMBIODEBUG("tbind\n");
155119376Smarcel	error = (int)SMB_TRAN_CONNECT(vcp, vcp->vc_paddr, td);
156119376Smarcel	if (error)
157119376Smarcel		goto fail;
158119376Smarcel	SMB_TRAN_SETPARAM(vcp, SMBTP_SELECTID, &iod->iod_flags);
159119376Smarcel	iod->iod_state = SMBIOD_ST_TRANACTIVE;
160119376Smarcel	SMBIODEBUG("tconnect\n");
161119376Smarcel	/* vcp->vc_mid = 0;*/
162119376Smarcel	error = (int)smb_smb_negotiate(vcp, &iod->iod_scred);
163119376Smarcel	if (error)
164119376Smarcel		goto fail;
165119376Smarcel	SMBIODEBUG("snegotiate\n");
166119376Smarcel	error = (int)smb_smb_ssnsetup(vcp, &iod->iod_scred);
167119376Smarcel	if (error)
168119376Smarcel		goto fail;
169119376Smarcel	iod->iod_state = SMBIOD_ST_VCACTIVE;
170119376Smarcel	SMBIODEBUG("completed\n");
171119376Smarcel	smb_iod_invrq(iod);
172119376Smarcel	return (0);
173119376Smarcel
174119376Smarcel fail:
175119376Smarcel	smb_iod_dead(iod);
176119376Smarcel	return (error);
17775374Sbp}
17875374Sbp
17975374Sbpstatic int
18075374Sbpsmb_iod_disconnect(struct smbiod *iod)
18175374Sbp{
18275374Sbp	struct smb_vc *vcp = iod->iod_vc;
18375374Sbp
18475374Sbp	SMBIODEBUG("\n");
18575374Sbp	if (iod->iod_state == SMBIOD_ST_VCACTIVE) {
18675374Sbp		smb_smb_ssnclose(vcp, &iod->iod_scred);
18775374Sbp		iod->iod_state = SMBIOD_ST_TRANACTIVE;
18875374Sbp	}
18975374Sbp	vcp->vc_smbuid = SMB_UID_UNKNOWN;
19075374Sbp	smb_iod_closetran(iod);
19175374Sbp	iod->iod_state = SMBIOD_ST_NOTCONN;
19275374Sbp	return 0;
19375374Sbp}
19475374Sbp
19575374Sbpstatic int
19675374Sbpsmb_iod_treeconnect(struct smbiod *iod, struct smb_share *ssp)
19775374Sbp{
19875374Sbp	int error;
19975374Sbp
20075374Sbp	if (iod->iod_state != SMBIOD_ST_VCACTIVE) {
20175374Sbp		if (iod->iod_state != SMBIOD_ST_DEAD)
20275374Sbp			return ENOTCONN;
20375374Sbp		iod->iod_state = SMBIOD_ST_RECONNECT;
20475374Sbp		error = smb_iod_connect(iod);
20575374Sbp		if (error)
20675374Sbp			return error;
20775374Sbp	}
20875374Sbp	SMBIODEBUG("tree reconnect\n");
20975374Sbp	SMBS_ST_LOCK(ssp);
21075374Sbp	ssp->ss_flags |= SMBS_RECONNECTING;
21175374Sbp	SMBS_ST_UNLOCK(ssp);
21275374Sbp	error = smb_smb_treeconnect(ssp, &iod->iod_scred);
21375374Sbp	SMBS_ST_LOCK(ssp);
21475374Sbp	ssp->ss_flags &= ~SMBS_RECONNECTING;
21575374Sbp	SMBS_ST_UNLOCK(ssp);
21675374Sbp	wakeup(&ssp->ss_vcgenid);
21775374Sbp	return error;
21875374Sbp}
21975374Sbp
22075374Sbpstatic int
22175374Sbpsmb_iod_sendrq(struct smbiod *iod, struct smb_rq *rqp)
22275374Sbp{
22387192Sbp	struct thread *td = iod->iod_td;
22475374Sbp	struct smb_vc *vcp = iod->iod_vc;
22575374Sbp	struct smb_share *ssp = rqp->sr_share;
22675374Sbp	struct mbuf *m;
22775374Sbp	int error;
22875374Sbp
22975374Sbp	SMBIODEBUG("iod_state = %d\n", iod->iod_state);
23075374Sbp	switch (iod->iod_state) {
23175374Sbp	    case SMBIOD_ST_NOTCONN:
23275374Sbp		smb_iod_rqprocessed(rqp, ENOTCONN);
23375374Sbp		return 0;
23475374Sbp	    case SMBIOD_ST_DEAD:
23575374Sbp		iod->iod_state = SMBIOD_ST_RECONNECT;
23675374Sbp		return 0;
23775374Sbp	    case SMBIOD_ST_RECONNECT:
23875374Sbp		return 0;
23975374Sbp	    default:
24075374Sbp		break;
24175374Sbp	}
24275374Sbp	if (rqp->sr_sendcnt == 0) {
24375374Sbp#ifdef movedtoanotherplace
24475374Sbp		if (vcp->vc_maxmux != 0 && iod->iod_muxcnt >= vcp->vc_maxmux)
24575374Sbp			return 0;
24675374Sbp#endif
247107940Srobert		*rqp->sr_rqtid = htole16(ssp ? ssp->ss_tid : SMB_TID_UNKNOWN);
248107940Srobert		*rqp->sr_rquid = htole16(vcp ? vcp->vc_smbuid : 0);
24975374Sbp		mb_fixhdr(&rqp->sr_rq);
25075374Sbp	}
25175374Sbp	if (rqp->sr_sendcnt++ > 5) {
25275374Sbp		rqp->sr_flags |= SMBR_RESTART;
25375374Sbp		smb_iod_rqprocessed(rqp, rqp->sr_lerror);
25475374Sbp		/*
25575374Sbp		 * If all attempts to send a request failed, then
25675374Sbp		 * something is seriously hosed.
25775374Sbp		 */
25875374Sbp		return ENOTCONN;
25975374Sbp	}
26075374Sbp	SMBSDEBUG("M:%04x, P:%04x, U:%04x, T:%04x\n", rqp->sr_mid, 0, 0, 0);
26175374Sbp	m_dumpm(rqp->sr_rq.mb_top);
262111119Simp	m = m_copym(rqp->sr_rq.mb_top, 0, M_COPYALL, M_TRYWAIT);
26387192Sbp	error = rqp->sr_lerror = m ? SMB_TRAN_SEND(vcp, m, td) : ENOBUFS;
26475374Sbp	if (error == 0) {
26575374Sbp		getnanotime(&rqp->sr_timesent);
26675374Sbp		iod->iod_lastrqsent = rqp->sr_timesent;
26775374Sbp		rqp->sr_flags |= SMBR_SENT;
26875374Sbp		rqp->sr_state = SMBRQ_SENT;
26975374Sbp		return 0;
27075374Sbp	}
27175374Sbp	/*
27275374Sbp	 * Check for fatal errors
27375374Sbp	 */
27475374Sbp	if (SMB_TRAN_FATAL(vcp, error)) {
27575374Sbp		/*
27675374Sbp		 * No further attempts should be made
27775374Sbp		 */
27875374Sbp		return ENOTCONN;
27975374Sbp	}
28075374Sbp	if (smb_rq_intr(rqp))
28175374Sbp		smb_iod_rqprocessed(rqp, EINTR);
28275374Sbp	return 0;
28375374Sbp}
28475374Sbp
28575374Sbp/*
28675374Sbp * Process incoming packets
28775374Sbp */
28875374Sbpstatic int
28975374Sbpsmb_iod_recvall(struct smbiod *iod)
29075374Sbp{
29175374Sbp	struct smb_vc *vcp = iod->iod_vc;
29287192Sbp	struct thread *td = iod->iod_td;
29375374Sbp	struct smb_rq *rqp;
29475374Sbp	struct mbuf *m;
29575374Sbp	u_char *hp;
29675374Sbp	u_short mid;
29775374Sbp	int error;
29875374Sbp
29975374Sbp	switch (iod->iod_state) {
30075374Sbp	    case SMBIOD_ST_NOTCONN:
30175374Sbp	    case SMBIOD_ST_DEAD:
30275374Sbp	    case SMBIOD_ST_RECONNECT:
30375374Sbp		return 0;
30475374Sbp	    default:
30575374Sbp		break;
30675374Sbp	}
30775374Sbp	for (;;) {
30875374Sbp		m = NULL;
30987192Sbp		error = SMB_TRAN_RECV(vcp, &m, td);
31075374Sbp		if (error == EWOULDBLOCK)
31175374Sbp			break;
31275374Sbp		if (SMB_TRAN_FATAL(vcp, error)) {
31375374Sbp			smb_iod_dead(iod);
31475374Sbp			break;
31575374Sbp		}
31675374Sbp		if (error)
31775374Sbp			break;
31875374Sbp		if (m == NULL) {
31975374Sbp			SMBERROR("tran return NULL without error\n");
32075374Sbp			error = EPIPE;
32175374Sbp			continue;
32275374Sbp		}
32375374Sbp		m = m_pullup(m, SMB_HDRLEN);
32475374Sbp		if (m == NULL)
32575374Sbp			continue;	/* wait for a good packet */
32675374Sbp		/*
32775374Sbp		 * Now we got an entire and possibly invalid SMB packet.
32875374Sbp		 * Be careful while parsing it.
32975374Sbp		 */
33075374Sbp		m_dumpm(m);
33175374Sbp		hp = mtod(m, u_char*);
33275374Sbp		if (bcmp(hp, SMB_SIGNATURE, SMB_SIGLEN) != 0) {
33375374Sbp			m_freem(m);
33475374Sbp			continue;
33575374Sbp		}
33675374Sbp		mid = SMB_HDRMID(hp);
33775374Sbp		SMBSDEBUG("mid %04x\n", (u_int)mid);
33875374Sbp		SMB_IOD_RQLOCK(iod);
33975374Sbp		TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) {
34075374Sbp			if (rqp->sr_mid != mid)
34175374Sbp				continue;
34275374Sbp			SMBRQ_SLOCK(rqp);
34375374Sbp			if (rqp->sr_rp.md_top == NULL) {
34475374Sbp				md_initm(&rqp->sr_rp, m);
34575374Sbp			} else {
34675374Sbp				if (rqp->sr_flags & SMBR_MULTIPACKET) {
34775374Sbp					md_append_record(&rqp->sr_rp, m);
34875374Sbp				} else {
34975374Sbp					SMBRQ_SUNLOCK(rqp);
35075374Sbp					SMBERROR("duplicate response %d (ignored)\n", mid);
35175374Sbp					break;
35275374Sbp				}
35375374Sbp			}
35475374Sbp			SMBRQ_SUNLOCK(rqp);
35575374Sbp			smb_iod_rqprocessed(rqp, 0);
35675374Sbp			break;
35775374Sbp		}
35875374Sbp		SMB_IOD_RQUNLOCK(iod);
35975374Sbp		if (rqp == NULL) {
36075374Sbp			SMBERROR("drop resp with mid %d\n", (u_int)mid);
36175374Sbp/*			smb_printrqlist(vcp);*/
36275374Sbp			m_freem(m);
36375374Sbp		}
36475374Sbp	}
36575374Sbp	/*
36675374Sbp	 * check for interrupts
36775374Sbp	 */
36875374Sbp	SMB_IOD_RQLOCK(iod);
36975374Sbp	TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) {
370112888Sjeff		if (smb_td_intr(rqp->sr_cred->scr_td)) {
37175374Sbp			smb_iod_rqprocessed(rqp, EINTR);
37275374Sbp		}
37375374Sbp	}
37475374Sbp	SMB_IOD_RQUNLOCK(iod);
37575374Sbp	return 0;
37675374Sbp}
37775374Sbp
37875374Sbpint
37975374Sbpsmb_iod_request(struct smbiod *iod, int event, void *ident)
38075374Sbp{
38175374Sbp	struct smbiod_event *evp;
38275374Sbp	int error;
38375374Sbp
38475374Sbp	SMBIODEBUG("\n");
385111119Simp	evp = smb_zmalloc(sizeof(*evp), M_SMBIOD, M_WAITOK);
38675374Sbp	evp->ev_type = event;
38775374Sbp	evp->ev_ident = ident;
38875374Sbp	SMB_IOD_EVLOCK(iod);
38975374Sbp	STAILQ_INSERT_TAIL(&iod->iod_evlist, evp, ev_link);
39075374Sbp	if ((event & SMBIOD_EV_SYNC) == 0) {
39175374Sbp		SMB_IOD_EVUNLOCK(iod);
39275374Sbp		smb_iod_wakeup(iod);
39375374Sbp		return 0;
39475374Sbp	}
39575374Sbp	smb_iod_wakeup(iod);
39675374Sbp	msleep(evp, SMB_IOD_EVLOCKPTR(iod), PWAIT | PDROP, "90evw", 0);
39775374Sbp	error = evp->ev_error;
39875374Sbp	free(evp, M_SMBIOD);
39975374Sbp	return error;
40075374Sbp}
40175374Sbp
40275374Sbp/*
40375374Sbp * Place request in the queue.
40475374Sbp * Request from smbiod have a high priority.
40575374Sbp */
40675374Sbpint
40775374Sbpsmb_iod_addrq(struct smb_rq *rqp)
40875374Sbp{
40975374Sbp	struct smb_vc *vcp = rqp->sr_vc;
41075374Sbp	struct smbiod *iod = vcp->vc_iod;
41175374Sbp	int error;
41275374Sbp
41375374Sbp	SMBIODEBUG("\n");
414116339Stjr	if (rqp->sr_cred->scr_td != NULL &&
415116339Stjr	    rqp->sr_cred->scr_td->td_proc == iod->iod_p) {
41675374Sbp		rqp->sr_flags |= SMBR_INTERNAL;
41775374Sbp		SMB_IOD_RQLOCK(iod);
41875374Sbp		TAILQ_INSERT_HEAD(&iod->iod_rqlist, rqp, sr_link);
41975374Sbp		SMB_IOD_RQUNLOCK(iod);
42075374Sbp		for (;;) {
42175374Sbp			if (smb_iod_sendrq(iod, rqp) != 0) {
42275374Sbp				smb_iod_dead(iod);
42375374Sbp				break;
42475374Sbp			}
42575374Sbp			/*
42675374Sbp			 * we don't need to lock state field here
42775374Sbp			 */
42875374Sbp			if (rqp->sr_state != SMBRQ_NOTSENT)
42975374Sbp				break;
43075374Sbp			tsleep(&iod->iod_flags, PWAIT, "90sndw", hz);
43175374Sbp		}
43275374Sbp		if (rqp->sr_lerror)
43375374Sbp			smb_iod_removerq(rqp);
43475374Sbp		return rqp->sr_lerror;
43575374Sbp	}
43675374Sbp
43775374Sbp	switch (iod->iod_state) {
43875374Sbp	    case SMBIOD_ST_NOTCONN:
43975374Sbp		return ENOTCONN;
44075374Sbp	    case SMBIOD_ST_DEAD:
44175374Sbp		error = smb_iod_request(vcp->vc_iod, SMBIOD_EV_CONNECT | SMBIOD_EV_SYNC, NULL);
44275374Sbp		if (error)
44375374Sbp			return error;
44475374Sbp		return EXDEV;
44575374Sbp	    default:
44675374Sbp		break;
44775374Sbp	}
44875374Sbp
44975374Sbp	SMB_IOD_RQLOCK(iod);
45075374Sbp	for (;;) {
45175374Sbp		if (vcp->vc_maxmux == 0) {
45275374Sbp			SMBERROR("maxmux == 0\n");
45375374Sbp			break;
45475374Sbp		}
45575374Sbp		if (iod->iod_muxcnt < vcp->vc_maxmux)
45675374Sbp			break;
45775374Sbp		iod->iod_muxwant++;
45875374Sbp		msleep(&iod->iod_muxwant, SMB_IOD_RQLOCKPTR(iod),
45975374Sbp		    PWAIT, "90mux", 0);
46075374Sbp	}
46175374Sbp	iod->iod_muxcnt++;
46275374Sbp	TAILQ_INSERT_TAIL(&iod->iod_rqlist, rqp, sr_link);
46375374Sbp	SMB_IOD_RQUNLOCK(iod);
46475374Sbp	smb_iod_wakeup(iod);
46575374Sbp	return 0;
46675374Sbp}
46775374Sbp
46875374Sbpint
46975374Sbpsmb_iod_removerq(struct smb_rq *rqp)
47075374Sbp{
47175374Sbp	struct smb_vc *vcp = rqp->sr_vc;
47275374Sbp	struct smbiod *iod = vcp->vc_iod;
47375374Sbp
47475374Sbp	SMBIODEBUG("\n");
47575374Sbp	if (rqp->sr_flags & SMBR_INTERNAL) {
47675374Sbp		SMB_IOD_RQLOCK(iod);
47775374Sbp		TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link);
47875374Sbp		SMB_IOD_RQUNLOCK(iod);
47975374Sbp		return 0;
48075374Sbp	}
48175374Sbp	SMB_IOD_RQLOCK(iod);
48275374Sbp	while (rqp->sr_flags & SMBR_XLOCK) {
48375374Sbp		rqp->sr_flags |= SMBR_XLOCKWANT;
48475374Sbp		msleep(rqp, SMB_IOD_RQLOCKPTR(iod), PWAIT, "90xrm", 0);
48575374Sbp	}
48675374Sbp	TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link);
48775374Sbp	iod->iod_muxcnt--;
48875374Sbp	if (iod->iod_muxwant) {
48975374Sbp		iod->iod_muxwant--;
49075374Sbp		wakeup(&iod->iod_muxwant);
49175374Sbp	}
49275374Sbp	SMB_IOD_RQUNLOCK(iod);
49375374Sbp	return 0;
49475374Sbp}
49575374Sbp
49675374Sbpint
49775374Sbpsmb_iod_waitrq(struct smb_rq *rqp)
49875374Sbp{
49975374Sbp	struct smbiod *iod = rqp->sr_vc->vc_iod;
50075374Sbp	int error;
50175374Sbp
50275374Sbp	SMBIODEBUG("\n");
50375374Sbp	if (rqp->sr_flags & SMBR_INTERNAL) {
50475374Sbp		for (;;) {
50575374Sbp			smb_iod_sendall(iod);
50675374Sbp			smb_iod_recvall(iod);
50775374Sbp			if (rqp->sr_rpgen != rqp->sr_rplast)
50875374Sbp				break;
50975374Sbp			tsleep(&iod->iod_flags, PWAIT, "90irq", hz);
51075374Sbp		}
51175374Sbp		smb_iod_removerq(rqp);
51275374Sbp		return rqp->sr_lerror;
51375374Sbp
51475374Sbp	}
51575374Sbp	SMBRQ_SLOCK(rqp);
51675374Sbp	if (rqp->sr_rpgen == rqp->sr_rplast)
51775374Sbp		msleep(&rqp->sr_state, SMBRQ_SLOCKPTR(rqp), PWAIT, "90wrq", 0);
51875374Sbp	rqp->sr_rplast++;
51975374Sbp	SMBRQ_SUNLOCK(rqp);
52075374Sbp	error = rqp->sr_lerror;
52175374Sbp	if (rqp->sr_flags & SMBR_MULTIPACKET) {
52275374Sbp		/*
52375374Sbp		 * If request should stay in the list, then reinsert it
52475374Sbp		 * at the end of queue so other waiters have chance to concur
52575374Sbp		 */
52675374Sbp		SMB_IOD_RQLOCK(iod);
52775374Sbp		TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link);
52875374Sbp		TAILQ_INSERT_TAIL(&iod->iod_rqlist, rqp, sr_link);
52975374Sbp		SMB_IOD_RQUNLOCK(iod);
53075374Sbp	} else
53175374Sbp		smb_iod_removerq(rqp);
53275374Sbp	return error;
53375374Sbp}
53475374Sbp
53575374Sbp
53675374Sbpstatic int
53775374Sbpsmb_iod_sendall(struct smbiod *iod)
53875374Sbp{
53975374Sbp	struct smb_vc *vcp = iod->iod_vc;
54075374Sbp	struct smb_rq *rqp;
54175374Sbp	struct timespec ts, tstimeout;
54275374Sbp	int herror;
54375374Sbp
54475374Sbp	herror = 0;
54575374Sbp	/*
54675374Sbp	 * Loop through the list of requests and send them if possible
54775374Sbp	 */
54875374Sbp	SMB_IOD_RQLOCK(iod);
54975374Sbp	TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) {
55075374Sbp		switch (rqp->sr_state) {
55175374Sbp		    case SMBRQ_NOTSENT:
55275374Sbp			rqp->sr_flags |= SMBR_XLOCK;
55375374Sbp			SMB_IOD_RQUNLOCK(iod);
55475374Sbp			herror = smb_iod_sendrq(iod, rqp);
55575374Sbp			SMB_IOD_RQLOCK(iod);
55675374Sbp			rqp->sr_flags &= ~SMBR_XLOCK;
55775374Sbp			if (rqp->sr_flags & SMBR_XLOCKWANT) {
55875374Sbp				rqp->sr_flags &= ~SMBR_XLOCKWANT;
55975374Sbp				wakeup(rqp);
56075374Sbp			}
56175374Sbp			break;
56275374Sbp		    case SMBRQ_SENT:
56375374Sbp			SMB_TRAN_GETPARAM(vcp, SMBTP_TIMEOUT, &tstimeout);
56475374Sbp			timespecadd(&tstimeout, &tstimeout);
56575374Sbp			getnanotime(&ts);
56675374Sbp			timespecsub(&ts, &tstimeout);
56775374Sbp			if (timespeccmp(&ts, &rqp->sr_timesent, >)) {
56875374Sbp				smb_iod_rqprocessed(rqp, ETIMEDOUT);
56975374Sbp			}
57075374Sbp			break;
57175374Sbp		    default:
57297209Speter			break;
57375374Sbp		}
57475374Sbp		if (herror)
57575374Sbp			break;
57675374Sbp	}
57775374Sbp	SMB_IOD_RQUNLOCK(iod);
57875374Sbp	if (herror == ENOTCONN)
57975374Sbp		smb_iod_dead(iod);
58075374Sbp	return 0;
58175374Sbp}
58275374Sbp
58375374Sbp/*
58475374Sbp * "main" function for smbiod daemon
58575374Sbp */
58675374Sbpstatic __inline void
58775374Sbpsmb_iod_main(struct smbiod *iod)
58875374Sbp{
58975374Sbp/*	struct smb_vc *vcp = iod->iod_vc;*/
59075374Sbp	struct smbiod_event *evp;
59175374Sbp/*	struct timespec tsnow;*/
59275374Sbp	int error;
59375374Sbp
59475374Sbp	SMBIODEBUG("\n");
59575374Sbp	error = 0;
59675374Sbp
59775374Sbp	/*
59875374Sbp	 * Check all interesting events
59975374Sbp	 */
60075374Sbp	for (;;) {
60175374Sbp		SMB_IOD_EVLOCK(iod);
60275374Sbp		evp = STAILQ_FIRST(&iod->iod_evlist);
60375374Sbp		if (evp == NULL) {
60475374Sbp			SMB_IOD_EVUNLOCK(iod);
60575374Sbp			break;
60675374Sbp		}
60775374Sbp		STAILQ_REMOVE_HEAD(&iod->iod_evlist, ev_link);
60875374Sbp		evp->ev_type |= SMBIOD_EV_PROCESSING;
60975374Sbp		SMB_IOD_EVUNLOCK(iod);
61075374Sbp		switch (evp->ev_type & SMBIOD_EV_MASK) {
61175374Sbp		    case SMBIOD_EV_CONNECT:
61275374Sbp			iod->iod_state = SMBIOD_ST_RECONNECT;
61375374Sbp			evp->ev_error = smb_iod_connect(iod);
61475374Sbp			break;
61575374Sbp		    case SMBIOD_EV_DISCONNECT:
61675374Sbp			evp->ev_error = smb_iod_disconnect(iod);
61775374Sbp			break;
61875374Sbp		    case SMBIOD_EV_TREECONNECT:
61975374Sbp			evp->ev_error = smb_iod_treeconnect(iod, evp->ev_ident);
62075374Sbp			break;
62175374Sbp		    case SMBIOD_EV_SHUTDOWN:
62275374Sbp			iod->iod_flags |= SMBIOD_SHUTDOWN;
62375374Sbp			break;
62475374Sbp		    case SMBIOD_EV_NEWRQ:
62575374Sbp			break;
62675374Sbp		}
62775374Sbp		if (evp->ev_type & SMBIOD_EV_SYNC) {
62875374Sbp			SMB_IOD_EVLOCK(iod);
62975374Sbp			wakeup(evp);
63075374Sbp			SMB_IOD_EVUNLOCK(iod);
63175374Sbp		} else
63275374Sbp			free(evp, M_SMBIOD);
63375374Sbp	}
63475374Sbp#if 0
63575374Sbp	if (iod->iod_state == SMBIOD_ST_VCACTIVE) {
63675374Sbp		getnanotime(&tsnow);
63775374Sbp		timespecsub(&tsnow, &iod->iod_pingtimo);
63875374Sbp		if (timespeccmp(&tsnow, &iod->iod_lastrqsent, >)) {
63975374Sbp			smb_smb_echo(vcp, &iod->iod_scred);
64075374Sbp		}
64175374Sbp	}
64275374Sbp#endif
64375374Sbp	smb_iod_sendall(iod);
64475374Sbp	smb_iod_recvall(iod);
64575374Sbp	return;
64675374Sbp}
64775374Sbp
64875374Sbpvoid
64975374Sbpsmb_iod_thread(void *arg)
65075374Sbp{
65175374Sbp	struct smbiod *iod = arg;
65275374Sbp
65375374Sbp	mtx_lock(&Giant);
65487192Sbp	/*
65587192Sbp	 * Here we assume that the thread structure will be the same
65687192Sbp	 * for an entire kthread (kproc, to be more precise) life.
65787192Sbp	 */
65887192Sbp	iod->iod_td = curthread;
65987192Sbp	smb_makescred(&iod->iod_scred, iod->iod_td, NULL);
66075374Sbp	while ((iod->iod_flags & SMBIOD_SHUTDOWN) == 0) {
66175374Sbp		smb_iod_main(iod);
66275374Sbp		SMBIODEBUG("going to sleep for %d ticks\n", iod->iod_sleeptimo);
66375374Sbp/*		mtx_unlock(&Giant, MTX_DEF);*/
66475374Sbp		if (iod->iod_flags & SMBIOD_SHUTDOWN)
66575374Sbp			break;
66675374Sbp		tsleep(&iod->iod_flags, PWAIT, "90idle", iod->iod_sleeptimo);
66775374Sbp	}
66875374Sbp/*	mtx_lock(&Giant, MTX_DEF);*/
66975374Sbp	kthread_exit(0);
67075374Sbp}
67175374Sbp
67275374Sbpint
67375374Sbpsmb_iod_create(struct smb_vc *vcp)
67475374Sbp{
67575374Sbp	struct smbiod *iod;
67675374Sbp	int error;
67775374Sbp
678111119Simp	iod = smb_zmalloc(sizeof(*iod), M_SMBIOD, M_WAITOK);
67975374Sbp	iod->iod_id = smb_iod_next++;
68075374Sbp	iod->iod_state = SMBIOD_ST_NOTCONN;
68175374Sbp	iod->iod_vc = vcp;
68275374Sbp	iod->iod_sleeptimo = hz * SMBIOD_SLEEP_TIMO;
68375374Sbp	iod->iod_pingtimo.tv_sec = SMBIOD_PING_TIMO;
68475374Sbp	getnanotime(&iod->iod_lastrqsent);
68575374Sbp	vcp->vc_iod = iod;
68675374Sbp	smb_sl_init(&iod->iod_rqlock, "90rql");
68775374Sbp	TAILQ_INIT(&iod->iod_rqlist);
68875374Sbp	smb_sl_init(&iod->iod_evlock, "90evl");
68975374Sbp	STAILQ_INIT(&iod->iod_evlist);
69087192Sbp	error = kthread_create(smb_iod_thread, iod, &iod->iod_p,
691104354Sscottl	    RFNOWAIT, 0, "smbiod%d", iod->iod_id);
69275374Sbp	if (error) {
69375374Sbp		SMBERROR("can't start smbiod: %d", error);
69475374Sbp		free(iod, M_SMBIOD);
69575374Sbp		return error;
69675374Sbp	}
69775374Sbp	return 0;
69875374Sbp}
69975374Sbp
70075374Sbpint
70175374Sbpsmb_iod_destroy(struct smbiod *iod)
70275374Sbp{
70375374Sbp	smb_iod_request(iod, SMBIOD_EV_SHUTDOWN | SMBIOD_EV_SYNC, NULL);
70482045Sbp	smb_sl_destroy(&iod->iod_rqlock);
70582045Sbp	smb_sl_destroy(&iod->iod_evlock);
70675374Sbp	free(iod, M_SMBIOD);
70775374Sbp	return 0;
70875374Sbp}
70975374Sbp
71075374Sbpint
71175374Sbpsmb_iod_init(void)
71275374Sbp{
71375374Sbp	return 0;
71475374Sbp}
71575374Sbp
71675374Sbpint
71775374Sbpsmb_iod_done(void)
71875374Sbp{
71975374Sbp	return 0;
72075374Sbp}
72175374Sbp
722