smb_iod.c revision 177599
1139823Simp/*-
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 177599 2008-03-25 09:39:02Z ru $");
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
247161523Smarcel		le16enc(rqp->sr_rqtid, ssp ? ssp->ss_tid : SMB_TID_UNKNOWN);
248161523Smarcel		le16enc(rqp->sr_rquid, vcp ? vcp->vc_smbuid : 0);
24975374Sbp		mb_fixhdr(&rqp->sr_rq);
250124087Stjr		if (vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE)
251124087Stjr			smb_rq_sign(rqp);
25275374Sbp	}
25375374Sbp	if (rqp->sr_sendcnt++ > 5) {
25475374Sbp		rqp->sr_flags |= SMBR_RESTART;
25575374Sbp		smb_iod_rqprocessed(rqp, rqp->sr_lerror);
25675374Sbp		/*
25775374Sbp		 * If all attempts to send a request failed, then
25875374Sbp		 * something is seriously hosed.
25975374Sbp		 */
26075374Sbp		return ENOTCONN;
26175374Sbp	}
26275374Sbp	SMBSDEBUG("M:%04x, P:%04x, U:%04x, T:%04x\n", rqp->sr_mid, 0, 0, 0);
26375374Sbp	m_dumpm(rqp->sr_rq.mb_top);
264177599Sru	m = m_copym(rqp->sr_rq.mb_top, 0, M_COPYALL, M_WAIT);
265177599Sru	error = rqp->sr_lerror = SMB_TRAN_SEND(vcp, m, td);
26675374Sbp	if (error == 0) {
26775374Sbp		getnanotime(&rqp->sr_timesent);
26875374Sbp		iod->iod_lastrqsent = rqp->sr_timesent;
26975374Sbp		rqp->sr_flags |= SMBR_SENT;
27075374Sbp		rqp->sr_state = SMBRQ_SENT;
27175374Sbp		return 0;
27275374Sbp	}
27375374Sbp	/*
27475374Sbp	 * Check for fatal errors
27575374Sbp	 */
27675374Sbp	if (SMB_TRAN_FATAL(vcp, error)) {
27775374Sbp		/*
27875374Sbp		 * No further attempts should be made
27975374Sbp		 */
28075374Sbp		return ENOTCONN;
28175374Sbp	}
28275374Sbp	if (smb_rq_intr(rqp))
28375374Sbp		smb_iod_rqprocessed(rqp, EINTR);
28475374Sbp	return 0;
28575374Sbp}
28675374Sbp
28775374Sbp/*
28875374Sbp * Process incoming packets
28975374Sbp */
29075374Sbpstatic int
29175374Sbpsmb_iod_recvall(struct smbiod *iod)
29275374Sbp{
29375374Sbp	struct smb_vc *vcp = iod->iod_vc;
29487192Sbp	struct thread *td = iod->iod_td;
29575374Sbp	struct smb_rq *rqp;
29675374Sbp	struct mbuf *m;
29775374Sbp	u_char *hp;
29875374Sbp	u_short mid;
29975374Sbp	int error;
30075374Sbp
30175374Sbp	switch (iod->iod_state) {
30275374Sbp	    case SMBIOD_ST_NOTCONN:
30375374Sbp	    case SMBIOD_ST_DEAD:
30475374Sbp	    case SMBIOD_ST_RECONNECT:
30575374Sbp		return 0;
30675374Sbp	    default:
30775374Sbp		break;
30875374Sbp	}
30975374Sbp	for (;;) {
31075374Sbp		m = NULL;
31187192Sbp		error = SMB_TRAN_RECV(vcp, &m, td);
31275374Sbp		if (error == EWOULDBLOCK)
31375374Sbp			break;
31475374Sbp		if (SMB_TRAN_FATAL(vcp, error)) {
31575374Sbp			smb_iod_dead(iod);
31675374Sbp			break;
31775374Sbp		}
31875374Sbp		if (error)
31975374Sbp			break;
32075374Sbp		if (m == NULL) {
32175374Sbp			SMBERROR("tran return NULL without error\n");
32275374Sbp			error = EPIPE;
32375374Sbp			continue;
32475374Sbp		}
32575374Sbp		m = m_pullup(m, SMB_HDRLEN);
32675374Sbp		if (m == NULL)
32775374Sbp			continue;	/* wait for a good packet */
32875374Sbp		/*
32975374Sbp		 * Now we got an entire and possibly invalid SMB packet.
33075374Sbp		 * Be careful while parsing it.
33175374Sbp		 */
33275374Sbp		m_dumpm(m);
33375374Sbp		hp = mtod(m, u_char*);
33475374Sbp		if (bcmp(hp, SMB_SIGNATURE, SMB_SIGLEN) != 0) {
33575374Sbp			m_freem(m);
33675374Sbp			continue;
33775374Sbp		}
33875374Sbp		mid = SMB_HDRMID(hp);
33975374Sbp		SMBSDEBUG("mid %04x\n", (u_int)mid);
34075374Sbp		SMB_IOD_RQLOCK(iod);
34175374Sbp		TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) {
34275374Sbp			if (rqp->sr_mid != mid)
34375374Sbp				continue;
34475374Sbp			SMBRQ_SLOCK(rqp);
34575374Sbp			if (rqp->sr_rp.md_top == NULL) {
34675374Sbp				md_initm(&rqp->sr_rp, m);
34775374Sbp			} else {
34875374Sbp				if (rqp->sr_flags & SMBR_MULTIPACKET) {
34975374Sbp					md_append_record(&rqp->sr_rp, m);
35075374Sbp				} else {
35175374Sbp					SMBRQ_SUNLOCK(rqp);
35275374Sbp					SMBERROR("duplicate response %d (ignored)\n", mid);
35375374Sbp					break;
35475374Sbp				}
35575374Sbp			}
35675374Sbp			SMBRQ_SUNLOCK(rqp);
35775374Sbp			smb_iod_rqprocessed(rqp, 0);
35875374Sbp			break;
35975374Sbp		}
36075374Sbp		SMB_IOD_RQUNLOCK(iod);
36175374Sbp		if (rqp == NULL) {
36275374Sbp			SMBERROR("drop resp with mid %d\n", (u_int)mid);
36375374Sbp/*			smb_printrqlist(vcp);*/
36475374Sbp			m_freem(m);
36575374Sbp		}
36675374Sbp	}
36775374Sbp	/*
36875374Sbp	 * check for interrupts
36975374Sbp	 */
37075374Sbp	SMB_IOD_RQLOCK(iod);
37175374Sbp	TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) {
372112888Sjeff		if (smb_td_intr(rqp->sr_cred->scr_td)) {
37375374Sbp			smb_iod_rqprocessed(rqp, EINTR);
37475374Sbp		}
37575374Sbp	}
37675374Sbp	SMB_IOD_RQUNLOCK(iod);
37775374Sbp	return 0;
37875374Sbp}
37975374Sbp
38075374Sbpint
38175374Sbpsmb_iod_request(struct smbiod *iod, int event, void *ident)
38275374Sbp{
38375374Sbp	struct smbiod_event *evp;
38475374Sbp	int error;
38575374Sbp
38675374Sbp	SMBIODEBUG("\n");
387111119Simp	evp = smb_zmalloc(sizeof(*evp), M_SMBIOD, M_WAITOK);
38875374Sbp	evp->ev_type = event;
38975374Sbp	evp->ev_ident = ident;
39075374Sbp	SMB_IOD_EVLOCK(iod);
39175374Sbp	STAILQ_INSERT_TAIL(&iod->iod_evlist, evp, ev_link);
39275374Sbp	if ((event & SMBIOD_EV_SYNC) == 0) {
39375374Sbp		SMB_IOD_EVUNLOCK(iod);
39475374Sbp		smb_iod_wakeup(iod);
39575374Sbp		return 0;
39675374Sbp	}
39775374Sbp	smb_iod_wakeup(iod);
39875374Sbp	msleep(evp, SMB_IOD_EVLOCKPTR(iod), PWAIT | PDROP, "90evw", 0);
39975374Sbp	error = evp->ev_error;
40075374Sbp	free(evp, M_SMBIOD);
40175374Sbp	return error;
40275374Sbp}
40375374Sbp
40475374Sbp/*
40575374Sbp * Place request in the queue.
40675374Sbp * Request from smbiod have a high priority.
40775374Sbp */
40875374Sbpint
40975374Sbpsmb_iod_addrq(struct smb_rq *rqp)
41075374Sbp{
41175374Sbp	struct smb_vc *vcp = rqp->sr_vc;
41275374Sbp	struct smbiod *iod = vcp->vc_iod;
41375374Sbp	int error;
41475374Sbp
41575374Sbp	SMBIODEBUG("\n");
416116339Stjr	if (rqp->sr_cred->scr_td != NULL &&
417116339Stjr	    rqp->sr_cred->scr_td->td_proc == iod->iod_p) {
41875374Sbp		rqp->sr_flags |= SMBR_INTERNAL;
41975374Sbp		SMB_IOD_RQLOCK(iod);
42075374Sbp		TAILQ_INSERT_HEAD(&iod->iod_rqlist, rqp, sr_link);
42175374Sbp		SMB_IOD_RQUNLOCK(iod);
42275374Sbp		for (;;) {
42375374Sbp			if (smb_iod_sendrq(iod, rqp) != 0) {
42475374Sbp				smb_iod_dead(iod);
42575374Sbp				break;
42675374Sbp			}
42775374Sbp			/*
42875374Sbp			 * we don't need to lock state field here
42975374Sbp			 */
43075374Sbp			if (rqp->sr_state != SMBRQ_NOTSENT)
43175374Sbp				break;
43275374Sbp			tsleep(&iod->iod_flags, PWAIT, "90sndw", hz);
43375374Sbp		}
43475374Sbp		if (rqp->sr_lerror)
43575374Sbp			smb_iod_removerq(rqp);
43675374Sbp		return rqp->sr_lerror;
43775374Sbp	}
43875374Sbp
43975374Sbp	switch (iod->iod_state) {
44075374Sbp	    case SMBIOD_ST_NOTCONN:
44175374Sbp		return ENOTCONN;
44275374Sbp	    case SMBIOD_ST_DEAD:
44375374Sbp		error = smb_iod_request(vcp->vc_iod, SMBIOD_EV_CONNECT | SMBIOD_EV_SYNC, NULL);
44475374Sbp		if (error)
44575374Sbp			return error;
44675374Sbp		return EXDEV;
44775374Sbp	    default:
44875374Sbp		break;
44975374Sbp	}
45075374Sbp
45175374Sbp	SMB_IOD_RQLOCK(iod);
45275374Sbp	for (;;) {
45375374Sbp		if (vcp->vc_maxmux == 0) {
45475374Sbp			SMBERROR("maxmux == 0\n");
45575374Sbp			break;
45675374Sbp		}
45775374Sbp		if (iod->iod_muxcnt < vcp->vc_maxmux)
45875374Sbp			break;
45975374Sbp		iod->iod_muxwant++;
46075374Sbp		msleep(&iod->iod_muxwant, SMB_IOD_RQLOCKPTR(iod),
46175374Sbp		    PWAIT, "90mux", 0);
46275374Sbp	}
46375374Sbp	iod->iod_muxcnt++;
46475374Sbp	TAILQ_INSERT_TAIL(&iod->iod_rqlist, rqp, sr_link);
46575374Sbp	SMB_IOD_RQUNLOCK(iod);
46675374Sbp	smb_iod_wakeup(iod);
46775374Sbp	return 0;
46875374Sbp}
46975374Sbp
47075374Sbpint
47175374Sbpsmb_iod_removerq(struct smb_rq *rqp)
47275374Sbp{
47375374Sbp	struct smb_vc *vcp = rqp->sr_vc;
47475374Sbp	struct smbiod *iod = vcp->vc_iod;
47575374Sbp
47675374Sbp	SMBIODEBUG("\n");
47775374Sbp	if (rqp->sr_flags & SMBR_INTERNAL) {
47875374Sbp		SMB_IOD_RQLOCK(iod);
47975374Sbp		TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link);
48075374Sbp		SMB_IOD_RQUNLOCK(iod);
48175374Sbp		return 0;
48275374Sbp	}
48375374Sbp	SMB_IOD_RQLOCK(iod);
48475374Sbp	while (rqp->sr_flags & SMBR_XLOCK) {
48575374Sbp		rqp->sr_flags |= SMBR_XLOCKWANT;
48675374Sbp		msleep(rqp, SMB_IOD_RQLOCKPTR(iod), PWAIT, "90xrm", 0);
48775374Sbp	}
48875374Sbp	TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link);
48975374Sbp	iod->iod_muxcnt--;
49075374Sbp	if (iod->iod_muxwant) {
49175374Sbp		iod->iod_muxwant--;
49275374Sbp		wakeup(&iod->iod_muxwant);
49375374Sbp	}
49475374Sbp	SMB_IOD_RQUNLOCK(iod);
49575374Sbp	return 0;
49675374Sbp}
49775374Sbp
49875374Sbpint
49975374Sbpsmb_iod_waitrq(struct smb_rq *rqp)
50075374Sbp{
50175374Sbp	struct smbiod *iod = rqp->sr_vc->vc_iod;
50275374Sbp	int error;
50375374Sbp
50475374Sbp	SMBIODEBUG("\n");
50575374Sbp	if (rqp->sr_flags & SMBR_INTERNAL) {
50675374Sbp		for (;;) {
50775374Sbp			smb_iod_sendall(iod);
50875374Sbp			smb_iod_recvall(iod);
50975374Sbp			if (rqp->sr_rpgen != rqp->sr_rplast)
51075374Sbp				break;
51175374Sbp			tsleep(&iod->iod_flags, PWAIT, "90irq", hz);
51275374Sbp		}
51375374Sbp		smb_iod_removerq(rqp);
51475374Sbp		return rqp->sr_lerror;
51575374Sbp
51675374Sbp	}
51775374Sbp	SMBRQ_SLOCK(rqp);
51875374Sbp	if (rqp->sr_rpgen == rqp->sr_rplast)
51975374Sbp		msleep(&rqp->sr_state, SMBRQ_SLOCKPTR(rqp), PWAIT, "90wrq", 0);
52075374Sbp	rqp->sr_rplast++;
52175374Sbp	SMBRQ_SUNLOCK(rqp);
52275374Sbp	error = rqp->sr_lerror;
52375374Sbp	if (rqp->sr_flags & SMBR_MULTIPACKET) {
52475374Sbp		/*
52575374Sbp		 * If request should stay in the list, then reinsert it
52675374Sbp		 * at the end of queue so other waiters have chance to concur
52775374Sbp		 */
52875374Sbp		SMB_IOD_RQLOCK(iod);
52975374Sbp		TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link);
53075374Sbp		TAILQ_INSERT_TAIL(&iod->iod_rqlist, rqp, sr_link);
53175374Sbp		SMB_IOD_RQUNLOCK(iod);
53275374Sbp	} else
53375374Sbp		smb_iod_removerq(rqp);
53475374Sbp	return error;
53575374Sbp}
53675374Sbp
53775374Sbp
53875374Sbpstatic int
53975374Sbpsmb_iod_sendall(struct smbiod *iod)
54075374Sbp{
54175374Sbp	struct smb_vc *vcp = iod->iod_vc;
54275374Sbp	struct smb_rq *rqp;
54375374Sbp	struct timespec ts, tstimeout;
54475374Sbp	int herror;
54575374Sbp
54675374Sbp	herror = 0;
54775374Sbp	/*
54875374Sbp	 * Loop through the list of requests and send them if possible
54975374Sbp	 */
55075374Sbp	SMB_IOD_RQLOCK(iod);
55175374Sbp	TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) {
55275374Sbp		switch (rqp->sr_state) {
55375374Sbp		    case SMBRQ_NOTSENT:
55475374Sbp			rqp->sr_flags |= SMBR_XLOCK;
55575374Sbp			SMB_IOD_RQUNLOCK(iod);
55675374Sbp			herror = smb_iod_sendrq(iod, rqp);
55775374Sbp			SMB_IOD_RQLOCK(iod);
55875374Sbp			rqp->sr_flags &= ~SMBR_XLOCK;
55975374Sbp			if (rqp->sr_flags & SMBR_XLOCKWANT) {
56075374Sbp				rqp->sr_flags &= ~SMBR_XLOCKWANT;
56175374Sbp				wakeup(rqp);
56275374Sbp			}
56375374Sbp			break;
56475374Sbp		    case SMBRQ_SENT:
56575374Sbp			SMB_TRAN_GETPARAM(vcp, SMBTP_TIMEOUT, &tstimeout);
56675374Sbp			timespecadd(&tstimeout, &tstimeout);
56775374Sbp			getnanotime(&ts);
56875374Sbp			timespecsub(&ts, &tstimeout);
56975374Sbp			if (timespeccmp(&ts, &rqp->sr_timesent, >)) {
57075374Sbp				smb_iod_rqprocessed(rqp, ETIMEDOUT);
57175374Sbp			}
57275374Sbp			break;
57375374Sbp		    default:
57497209Speter			break;
57575374Sbp		}
57675374Sbp		if (herror)
57775374Sbp			break;
57875374Sbp	}
57975374Sbp	SMB_IOD_RQUNLOCK(iod);
58075374Sbp	if (herror == ENOTCONN)
58175374Sbp		smb_iod_dead(iod);
58275374Sbp	return 0;
58375374Sbp}
58475374Sbp
58575374Sbp/*
58675374Sbp * "main" function for smbiod daemon
58775374Sbp */
58875374Sbpstatic __inline void
58975374Sbpsmb_iod_main(struct smbiod *iod)
59075374Sbp{
59175374Sbp/*	struct smb_vc *vcp = iod->iod_vc;*/
59275374Sbp	struct smbiod_event *evp;
59375374Sbp/*	struct timespec tsnow;*/
59475374Sbp	int error;
59575374Sbp
59675374Sbp	SMBIODEBUG("\n");
59775374Sbp	error = 0;
59875374Sbp
59975374Sbp	/*
60075374Sbp	 * Check all interesting events
60175374Sbp	 */
60275374Sbp	for (;;) {
60375374Sbp		SMB_IOD_EVLOCK(iod);
60475374Sbp		evp = STAILQ_FIRST(&iod->iod_evlist);
60575374Sbp		if (evp == NULL) {
60675374Sbp			SMB_IOD_EVUNLOCK(iod);
60775374Sbp			break;
60875374Sbp		}
60975374Sbp		STAILQ_REMOVE_HEAD(&iod->iod_evlist, ev_link);
61075374Sbp		evp->ev_type |= SMBIOD_EV_PROCESSING;
61175374Sbp		SMB_IOD_EVUNLOCK(iod);
61275374Sbp		switch (evp->ev_type & SMBIOD_EV_MASK) {
61375374Sbp		    case SMBIOD_EV_CONNECT:
61475374Sbp			iod->iod_state = SMBIOD_ST_RECONNECT;
61575374Sbp			evp->ev_error = smb_iod_connect(iod);
61675374Sbp			break;
61775374Sbp		    case SMBIOD_EV_DISCONNECT:
61875374Sbp			evp->ev_error = smb_iod_disconnect(iod);
61975374Sbp			break;
62075374Sbp		    case SMBIOD_EV_TREECONNECT:
62175374Sbp			evp->ev_error = smb_iod_treeconnect(iod, evp->ev_ident);
62275374Sbp			break;
62375374Sbp		    case SMBIOD_EV_SHUTDOWN:
62475374Sbp			iod->iod_flags |= SMBIOD_SHUTDOWN;
62575374Sbp			break;
62675374Sbp		    case SMBIOD_EV_NEWRQ:
62775374Sbp			break;
62875374Sbp		}
62975374Sbp		if (evp->ev_type & SMBIOD_EV_SYNC) {
63075374Sbp			SMB_IOD_EVLOCK(iod);
63175374Sbp			wakeup(evp);
63275374Sbp			SMB_IOD_EVUNLOCK(iod);
63375374Sbp		} else
63475374Sbp			free(evp, M_SMBIOD);
63575374Sbp	}
63675374Sbp#if 0
63775374Sbp	if (iod->iod_state == SMBIOD_ST_VCACTIVE) {
63875374Sbp		getnanotime(&tsnow);
63975374Sbp		timespecsub(&tsnow, &iod->iod_pingtimo);
64075374Sbp		if (timespeccmp(&tsnow, &iod->iod_lastrqsent, >)) {
64175374Sbp			smb_smb_echo(vcp, &iod->iod_scred);
64275374Sbp		}
64375374Sbp	}
64475374Sbp#endif
64575374Sbp	smb_iod_sendall(iod);
64675374Sbp	smb_iod_recvall(iod);
64775374Sbp	return;
64875374Sbp}
64975374Sbp
65075374Sbpvoid
65175374Sbpsmb_iod_thread(void *arg)
65275374Sbp{
65375374Sbp	struct smbiod *iod = arg;
65475374Sbp
65587192Sbp	/*
65687192Sbp	 * Here we assume that the thread structure will be the same
65787192Sbp	 * for an entire kthread (kproc, to be more precise) life.
65887192Sbp	 */
65987192Sbp	iod->iod_td = curthread;
66087192Sbp	smb_makescred(&iod->iod_scred, iod->iod_td, NULL);
66175374Sbp	while ((iod->iod_flags & SMBIOD_SHUTDOWN) == 0) {
66275374Sbp		smb_iod_main(iod);
66375374Sbp		SMBIODEBUG("going to sleep for %d ticks\n", iod->iod_sleeptimo);
66475374Sbp		if (iod->iod_flags & SMBIOD_SHUTDOWN)
66575374Sbp			break;
66675374Sbp		tsleep(&iod->iod_flags, PWAIT, "90idle", iod->iod_sleeptimo);
66775374Sbp	}
668172836Sjulian	kproc_exit(0);
66975374Sbp}
67075374Sbp
67175374Sbpint
67275374Sbpsmb_iod_create(struct smb_vc *vcp)
67375374Sbp{
67475374Sbp	struct smbiod *iod;
67575374Sbp	int error;
67675374Sbp
677111119Simp	iod = smb_zmalloc(sizeof(*iod), M_SMBIOD, M_WAITOK);
67875374Sbp	iod->iod_id = smb_iod_next++;
67975374Sbp	iod->iod_state = SMBIOD_ST_NOTCONN;
68075374Sbp	iod->iod_vc = vcp;
68175374Sbp	iod->iod_sleeptimo = hz * SMBIOD_SLEEP_TIMO;
68275374Sbp	iod->iod_pingtimo.tv_sec = SMBIOD_PING_TIMO;
68375374Sbp	getnanotime(&iod->iod_lastrqsent);
68475374Sbp	vcp->vc_iod = iod;
68575374Sbp	smb_sl_init(&iod->iod_rqlock, "90rql");
68675374Sbp	TAILQ_INIT(&iod->iod_rqlist);
68775374Sbp	smb_sl_init(&iod->iod_evlock, "90evl");
68875374Sbp	STAILQ_INIT(&iod->iod_evlist);
689172836Sjulian	error = kproc_create(smb_iod_thread, iod, &iod->iod_p,
690104354Sscottl	    RFNOWAIT, 0, "smbiod%d", iod->iod_id);
69175374Sbp	if (error) {
69275374Sbp		SMBERROR("can't start smbiod: %d", error);
69375374Sbp		free(iod, M_SMBIOD);
69475374Sbp		return error;
69575374Sbp	}
69675374Sbp	return 0;
69775374Sbp}
69875374Sbp
69975374Sbpint
70075374Sbpsmb_iod_destroy(struct smbiod *iod)
70175374Sbp{
70275374Sbp	smb_iod_request(iod, SMBIOD_EV_SHUTDOWN | SMBIOD_EV_SYNC, NULL);
70382045Sbp	smb_sl_destroy(&iod->iod_rqlock);
70482045Sbp	smb_sl_destroy(&iod->iod_evlock);
70575374Sbp	free(iod, M_SMBIOD);
70675374Sbp	return 0;
70775374Sbp}
70875374Sbp
70975374Sbpint
71075374Sbpsmb_iod_init(void)
71175374Sbp{
71275374Sbp	return 0;
71375374Sbp}
71475374Sbp
71575374Sbpint
71675374Sbpsmb_iod_done(void)
71775374Sbp{
71875374Sbp	return 0;
71975374Sbp}
72075374Sbp
721