smb_iod.c revision 87565
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 *
3275374Sbp * $FreeBSD: head/sys/netsmb/smb_iod.c 87565 2001-12-09 17:48:08Z arr $
3375374Sbp */
3475374Sbp
3575374Sbp#include <sys/param.h>
3675374Sbp#include <sys/systm.h>
3775374Sbp#include <sys/proc.h>
3875374Sbp#include <sys/kernel.h>
3975374Sbp#include <sys/kthread.h>
4075374Sbp#include <sys/malloc.h>
4175374Sbp#include <sys/mbuf.h>
4275374Sbp#include <sys/unistd.h>
4375374Sbp
4475374Sbp#include <netsmb/smb.h>
4575374Sbp#include <netsmb/smb_conn.h>
4675374Sbp#include <netsmb/smb_rq.h>
4775374Sbp#include <netsmb/smb_tran.h>
4875374Sbp#include <netsmb/smb_trantcp.h>
4975374Sbp
5075374Sbp
5175374Sbp#define SMBIOD_SLEEP_TIMO	2
5275374Sbp#define	SMBIOD_PING_TIMO	60	/* seconds */
5375374Sbp
5475374Sbp#define	SMB_IOD_EVLOCKPTR(iod)	(&((iod)->iod_evlock))
5575374Sbp#define	SMB_IOD_EVLOCK(iod)	smb_sl_lock(&((iod)->iod_evlock))
5675374Sbp#define	SMB_IOD_EVUNLOCK(iod)	smb_sl_unlock(&((iod)->iod_evlock))
5775374Sbp
5875374Sbp#define	SMB_IOD_RQLOCKPTR(iod)	(&((iod)->iod_rqlock))
5975374Sbp#define	SMB_IOD_RQLOCK(iod)	smb_sl_lock(&((iod)->iod_rqlock))
6075374Sbp#define	SMB_IOD_RQUNLOCK(iod)	smb_sl_unlock(&((iod)->iod_rqlock))
6175374Sbp
6275374Sbp#define	smb_iod_wakeup(iod)	wakeup(&(iod)->iod_flags)
6375374Sbp
6475374Sbp
6575374Sbpstatic MALLOC_DEFINE(M_SMBIOD, "SMBIOD", "SMB network io daemon");
6675374Sbp
6775374Sbpstatic int smb_iod_next;
6875374Sbp
6975374Sbpstatic int  smb_iod_sendall(struct smbiod *iod);
7075374Sbpstatic int  smb_iod_disconnect(struct smbiod *iod);
7175374Sbpstatic void smb_iod_thread(void *);
7275374Sbp
7375374Sbpstatic __inline void
7475374Sbpsmb_iod_rqprocessed(struct smb_rq *rqp, int error)
7575374Sbp{
7675374Sbp	SMBRQ_SLOCK(rqp);
7775374Sbp	rqp->sr_lerror = error;
7875374Sbp	rqp->sr_rpgen++;
7975374Sbp	rqp->sr_state = SMBRQ_NOTIFIED;
8075374Sbp	wakeup(&rqp->sr_state);
8175374Sbp	SMBRQ_SUNLOCK(rqp);
8275374Sbp}
8375374Sbp
8475374Sbpstatic void
8575374Sbpsmb_iod_invrq(struct smbiod *iod)
8675374Sbp{
8775374Sbp	struct smb_rq *rqp;
8875374Sbp
8975374Sbp	/*
9082045Sbp	 * Invalidate all outstanding requests for this connection
9175374Sbp	 */
9275374Sbp	SMB_IOD_RQLOCK(iod);
9375374Sbp	TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) {
9475374Sbp		if (rqp->sr_flags & SMBR_INTERNAL)
9575374Sbp			SMBRQ_SUNLOCK(rqp);
9675374Sbp		rqp->sr_flags |= SMBR_RESTART;
9775374Sbp		smb_iod_rqprocessed(rqp, ENOTCONN);
9875374Sbp	}
9975374Sbp	SMB_IOD_RQUNLOCK(iod);
10075374Sbp}
10175374Sbp
10275374Sbpstatic void
10375374Sbpsmb_iod_closetran(struct smbiod *iod)
10475374Sbp{
10575374Sbp	struct smb_vc *vcp = iod->iod_vc;
10687192Sbp	struct thread *td = iod->iod_td;
10775374Sbp
10875374Sbp	if (vcp->vc_tdata == NULL)
10975374Sbp		return;
11087192Sbp	SMB_TRAN_DISCONNECT(vcp, td);
11187192Sbp	SMB_TRAN_DONE(vcp, td);
11275374Sbp	vcp->vc_tdata = NULL;
11375374Sbp}
11475374Sbp
11575374Sbpstatic void
11675374Sbpsmb_iod_dead(struct smbiod *iod)
11775374Sbp{
11875374Sbp	iod->iod_state = SMBIOD_ST_DEAD;
11975374Sbp	smb_iod_closetran(iod);
12075374Sbp	smb_iod_invrq(iod);
12175374Sbp}
12275374Sbp
12375374Sbpstatic int
12475374Sbpsmb_iod_connect(struct smbiod *iod)
12575374Sbp{
12675374Sbp	struct smb_vc *vcp = iod->iod_vc;
12787192Sbp	struct thread *td = iod->iod_td;
12875374Sbp	int error;
12975374Sbp
13075374Sbp	SMBIODEBUG("%d\n", iod->iod_state);
13175374Sbp	switch(iod->iod_state) {
13275374Sbp	    case SMBIOD_ST_VCACTIVE:
13375374Sbp		SMBERROR("called for already opened connection\n");
13475374Sbp		return EISCONN;
13575374Sbp	    case SMBIOD_ST_DEAD:
13675374Sbp		return ENOTCONN;	/* XXX: last error code ? */
13775374Sbp	    default:
13875374Sbp		break;
13975374Sbp	}
14075374Sbp	vcp->vc_genid++;
14175374Sbp	error = 0;
14275374Sbp	itry {
14387192Sbp		ithrow(SMB_TRAN_CREATE(vcp, td));
14475374Sbp		SMBIODEBUG("tcreate\n");
14575374Sbp		if (vcp->vc_laddr) {
14687192Sbp			ithrow(SMB_TRAN_BIND(vcp, vcp->vc_laddr, td));
14775374Sbp		}
14875374Sbp		SMBIODEBUG("tbind\n");
14987192Sbp		ithrow(SMB_TRAN_CONNECT(vcp, vcp->vc_paddr, td));
15075374Sbp		SMB_TRAN_SETPARAM(vcp, SMBTP_SELECTID, &iod->iod_flags);
15175374Sbp		iod->iod_state = SMBIOD_ST_TRANACTIVE;
15275374Sbp		SMBIODEBUG("tconnect\n");
15375374Sbp/*		vcp->vc_mid = 0;*/
15475374Sbp		ithrow(smb_smb_negotiate(vcp, &iod->iod_scred));
15575374Sbp		SMBIODEBUG("snegotiate\n");
15675374Sbp		ithrow(smb_smb_ssnsetup(vcp, &iod->iod_scred));
15775374Sbp		iod->iod_state = SMBIOD_ST_VCACTIVE;
15875374Sbp		SMBIODEBUG("completed\n");
15975374Sbp		smb_iod_invrq(iod);
16075374Sbp	} icatch(error) {
16175374Sbp		smb_iod_dead(iod);
16275374Sbp	} ifinally {
16375374Sbp	} iendtry;
16475374Sbp	return error;
16575374Sbp}
16675374Sbp
16775374Sbpstatic int
16875374Sbpsmb_iod_disconnect(struct smbiod *iod)
16975374Sbp{
17075374Sbp	struct smb_vc *vcp = iod->iod_vc;
17175374Sbp
17275374Sbp	SMBIODEBUG("\n");
17375374Sbp	if (iod->iod_state == SMBIOD_ST_VCACTIVE) {
17475374Sbp		smb_smb_ssnclose(vcp, &iod->iod_scred);
17575374Sbp		iod->iod_state = SMBIOD_ST_TRANACTIVE;
17675374Sbp	}
17775374Sbp	vcp->vc_smbuid = SMB_UID_UNKNOWN;
17875374Sbp	smb_iod_closetran(iod);
17975374Sbp	iod->iod_state = SMBIOD_ST_NOTCONN;
18075374Sbp	return 0;
18175374Sbp}
18275374Sbp
18375374Sbpstatic int
18475374Sbpsmb_iod_treeconnect(struct smbiod *iod, struct smb_share *ssp)
18575374Sbp{
18675374Sbp	int error;
18775374Sbp
18875374Sbp	if (iod->iod_state != SMBIOD_ST_VCACTIVE) {
18975374Sbp		if (iod->iod_state != SMBIOD_ST_DEAD)
19075374Sbp			return ENOTCONN;
19175374Sbp		iod->iod_state = SMBIOD_ST_RECONNECT;
19275374Sbp		error = smb_iod_connect(iod);
19375374Sbp		if (error)
19475374Sbp			return error;
19575374Sbp	}
19675374Sbp	SMBIODEBUG("tree reconnect\n");
19775374Sbp	SMBS_ST_LOCK(ssp);
19875374Sbp	ssp->ss_flags |= SMBS_RECONNECTING;
19975374Sbp	SMBS_ST_UNLOCK(ssp);
20075374Sbp	error = smb_smb_treeconnect(ssp, &iod->iod_scred);
20175374Sbp	SMBS_ST_LOCK(ssp);
20275374Sbp	ssp->ss_flags &= ~SMBS_RECONNECTING;
20375374Sbp	SMBS_ST_UNLOCK(ssp);
20475374Sbp	wakeup(&ssp->ss_vcgenid);
20575374Sbp	return error;
20675374Sbp}
20775374Sbp
20875374Sbpstatic int
20975374Sbpsmb_iod_sendrq(struct smbiod *iod, struct smb_rq *rqp)
21075374Sbp{
21187192Sbp	struct thread *td = iod->iod_td;
21275374Sbp	struct smb_vc *vcp = iod->iod_vc;
21375374Sbp	struct smb_share *ssp = rqp->sr_share;
21475374Sbp	struct mbuf *m;
21575374Sbp	int error;
21675374Sbp
21775374Sbp	SMBIODEBUG("iod_state = %d\n", iod->iod_state);
21875374Sbp	switch (iod->iod_state) {
21975374Sbp	    case SMBIOD_ST_NOTCONN:
22075374Sbp		smb_iod_rqprocessed(rqp, ENOTCONN);
22175374Sbp		return 0;
22275374Sbp	    case SMBIOD_ST_DEAD:
22375374Sbp		iod->iod_state = SMBIOD_ST_RECONNECT;
22475374Sbp		return 0;
22575374Sbp	    case SMBIOD_ST_RECONNECT:
22675374Sbp		return 0;
22775374Sbp	    default:
22875374Sbp		break;
22975374Sbp	}
23075374Sbp	if (rqp->sr_sendcnt == 0) {
23175374Sbp#ifdef movedtoanotherplace
23275374Sbp		if (vcp->vc_maxmux != 0 && iod->iod_muxcnt >= vcp->vc_maxmux)
23375374Sbp			return 0;
23475374Sbp#endif
23575374Sbp		*rqp->sr_rqtid = htoles(ssp ? ssp->ss_tid : SMB_TID_UNKNOWN);
23675374Sbp		*rqp->sr_rquid = htoles(vcp ? vcp->vc_smbuid : 0);
23775374Sbp		mb_fixhdr(&rqp->sr_rq);
23875374Sbp	}
23975374Sbp	if (rqp->sr_sendcnt++ > 5) {
24075374Sbp		rqp->sr_flags |= SMBR_RESTART;
24175374Sbp		smb_iod_rqprocessed(rqp, rqp->sr_lerror);
24275374Sbp		/*
24375374Sbp		 * If all attempts to send a request failed, then
24475374Sbp		 * something is seriously hosed.
24575374Sbp		 */
24675374Sbp		return ENOTCONN;
24775374Sbp	}
24875374Sbp	SMBSDEBUG("M:%04x, P:%04x, U:%04x, T:%04x\n", rqp->sr_mid, 0, 0, 0);
24975374Sbp	m_dumpm(rqp->sr_rq.mb_top);
25087565Sarr	m = m_copym(rqp->sr_rq.mb_top, 0, M_COPYALL, M_TRYWAIT);
25187192Sbp	error = rqp->sr_lerror = m ? SMB_TRAN_SEND(vcp, m, td) : ENOBUFS;
25275374Sbp	if (error == 0) {
25375374Sbp		getnanotime(&rqp->sr_timesent);
25475374Sbp		iod->iod_lastrqsent = rqp->sr_timesent;
25575374Sbp		rqp->sr_flags |= SMBR_SENT;
25675374Sbp		rqp->sr_state = SMBRQ_SENT;
25775374Sbp		return 0;
25875374Sbp	}
25975374Sbp	/*
26075374Sbp	 * Check for fatal errors
26175374Sbp	 */
26275374Sbp	if (SMB_TRAN_FATAL(vcp, error)) {
26375374Sbp		/*
26475374Sbp		 * No further attempts should be made
26575374Sbp		 */
26675374Sbp		return ENOTCONN;
26775374Sbp	}
26875374Sbp	if (smb_rq_intr(rqp))
26975374Sbp		smb_iod_rqprocessed(rqp, EINTR);
27075374Sbp	return 0;
27175374Sbp}
27275374Sbp
27375374Sbp/*
27475374Sbp * Process incoming packets
27575374Sbp */
27675374Sbpstatic int
27775374Sbpsmb_iod_recvall(struct smbiod *iod)
27875374Sbp{
27975374Sbp	struct smb_vc *vcp = iod->iod_vc;
28087192Sbp	struct thread *td = iod->iod_td;
28175374Sbp	struct smb_rq *rqp;
28275374Sbp	struct mbuf *m;
28375374Sbp	u_char *hp;
28475374Sbp	u_short mid;
28575374Sbp	int error;
28675374Sbp
28775374Sbp	switch (iod->iod_state) {
28875374Sbp	    case SMBIOD_ST_NOTCONN:
28975374Sbp	    case SMBIOD_ST_DEAD:
29075374Sbp	    case SMBIOD_ST_RECONNECT:
29175374Sbp		return 0;
29275374Sbp	    default:
29375374Sbp		break;
29475374Sbp	}
29575374Sbp	for (;;) {
29675374Sbp		m = NULL;
29787192Sbp		error = SMB_TRAN_RECV(vcp, &m, td);
29875374Sbp		if (error == EWOULDBLOCK)
29975374Sbp			break;
30075374Sbp		if (SMB_TRAN_FATAL(vcp, error)) {
30175374Sbp			smb_iod_dead(iod);
30275374Sbp			break;
30375374Sbp		}
30475374Sbp		if (error)
30575374Sbp			break;
30675374Sbp		if (m == NULL) {
30775374Sbp			SMBERROR("tran return NULL without error\n");
30875374Sbp			error = EPIPE;
30975374Sbp			continue;
31075374Sbp		}
31175374Sbp		m = m_pullup(m, SMB_HDRLEN);
31275374Sbp		if (m == NULL)
31375374Sbp			continue;	/* wait for a good packet */
31475374Sbp		/*
31575374Sbp		 * Now we got an entire and possibly invalid SMB packet.
31675374Sbp		 * Be careful while parsing it.
31775374Sbp		 */
31875374Sbp		m_dumpm(m);
31975374Sbp		hp = mtod(m, u_char*);
32075374Sbp		if (bcmp(hp, SMB_SIGNATURE, SMB_SIGLEN) != 0) {
32175374Sbp			m_freem(m);
32275374Sbp			continue;
32375374Sbp		}
32475374Sbp		mid = SMB_HDRMID(hp);
32575374Sbp		SMBSDEBUG("mid %04x\n", (u_int)mid);
32675374Sbp		SMB_IOD_RQLOCK(iod);
32775374Sbp		TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) {
32875374Sbp			if (rqp->sr_mid != mid)
32975374Sbp				continue;
33075374Sbp			SMBRQ_SLOCK(rqp);
33175374Sbp			if (rqp->sr_rp.md_top == NULL) {
33275374Sbp				md_initm(&rqp->sr_rp, m);
33375374Sbp			} else {
33475374Sbp				if (rqp->sr_flags & SMBR_MULTIPACKET) {
33575374Sbp					md_append_record(&rqp->sr_rp, m);
33675374Sbp				} else {
33775374Sbp					SMBRQ_SUNLOCK(rqp);
33875374Sbp					SMBERROR("duplicate response %d (ignored)\n", mid);
33975374Sbp					break;
34075374Sbp				}
34175374Sbp			}
34275374Sbp			SMBRQ_SUNLOCK(rqp);
34375374Sbp			smb_iod_rqprocessed(rqp, 0);
34475374Sbp			break;
34575374Sbp		}
34675374Sbp		SMB_IOD_RQUNLOCK(iod);
34775374Sbp		if (rqp == NULL) {
34875374Sbp			SMBERROR("drop resp with mid %d\n", (u_int)mid);
34975374Sbp/*			smb_printrqlist(vcp);*/
35075374Sbp			m_freem(m);
35175374Sbp		}
35275374Sbp	}
35375374Sbp	/*
35475374Sbp	 * check for interrupts
35575374Sbp	 */
35675374Sbp	SMB_IOD_RQLOCK(iod);
35775374Sbp	TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) {
35887192Sbp		if (smb_proc_intr(rqp->sr_cred->scr_td->td_proc)) {
35975374Sbp			smb_iod_rqprocessed(rqp, EINTR);
36075374Sbp		}
36175374Sbp	}
36275374Sbp	SMB_IOD_RQUNLOCK(iod);
36375374Sbp	return 0;
36475374Sbp}
36575374Sbp
36675374Sbpint
36775374Sbpsmb_iod_request(struct smbiod *iod, int event, void *ident)
36875374Sbp{
36975374Sbp	struct smbiod_event *evp;
37075374Sbp	int error;
37175374Sbp
37275374Sbp	SMBIODEBUG("\n");
37375374Sbp	evp = smb_zmalloc(sizeof(*evp), M_SMBIOD, M_WAITOK);
37475374Sbp	evp->ev_type = event;
37575374Sbp	evp->ev_ident = ident;
37675374Sbp	SMB_IOD_EVLOCK(iod);
37775374Sbp	STAILQ_INSERT_TAIL(&iod->iod_evlist, evp, ev_link);
37875374Sbp	if ((event & SMBIOD_EV_SYNC) == 0) {
37975374Sbp		SMB_IOD_EVUNLOCK(iod);
38075374Sbp		smb_iod_wakeup(iod);
38175374Sbp		return 0;
38275374Sbp	}
38375374Sbp	smb_iod_wakeup(iod);
38475374Sbp	msleep(evp, SMB_IOD_EVLOCKPTR(iod), PWAIT | PDROP, "90evw", 0);
38575374Sbp	error = evp->ev_error;
38675374Sbp	free(evp, M_SMBIOD);
38775374Sbp	return error;
38875374Sbp}
38975374Sbp
39075374Sbp/*
39175374Sbp * Place request in the queue.
39275374Sbp * Request from smbiod have a high priority.
39375374Sbp */
39475374Sbpint
39575374Sbpsmb_iod_addrq(struct smb_rq *rqp)
39675374Sbp{
39775374Sbp	struct smb_vc *vcp = rqp->sr_vc;
39875374Sbp	struct smbiod *iod = vcp->vc_iod;
39975374Sbp	int error;
40075374Sbp
40175374Sbp	SMBIODEBUG("\n");
40287192Sbp	if (rqp->sr_cred->scr_td->td_proc == iod->iod_p) {
40375374Sbp		rqp->sr_flags |= SMBR_INTERNAL;
40475374Sbp		SMB_IOD_RQLOCK(iod);
40575374Sbp		TAILQ_INSERT_HEAD(&iod->iod_rqlist, rqp, sr_link);
40675374Sbp		SMB_IOD_RQUNLOCK(iod);
40775374Sbp		for (;;) {
40875374Sbp			if (smb_iod_sendrq(iod, rqp) != 0) {
40975374Sbp				smb_iod_dead(iod);
41075374Sbp				break;
41175374Sbp			}
41275374Sbp			/*
41375374Sbp			 * we don't need to lock state field here
41475374Sbp			 */
41575374Sbp			if (rqp->sr_state != SMBRQ_NOTSENT)
41675374Sbp				break;
41775374Sbp			tsleep(&iod->iod_flags, PWAIT, "90sndw", hz);
41875374Sbp		}
41975374Sbp		if (rqp->sr_lerror)
42075374Sbp			smb_iod_removerq(rqp);
42175374Sbp		return rqp->sr_lerror;
42275374Sbp	}
42375374Sbp
42475374Sbp	switch (iod->iod_state) {
42575374Sbp	    case SMBIOD_ST_NOTCONN:
42675374Sbp		return ENOTCONN;
42775374Sbp	    case SMBIOD_ST_DEAD:
42875374Sbp		error = smb_iod_request(vcp->vc_iod, SMBIOD_EV_CONNECT | SMBIOD_EV_SYNC, NULL);
42975374Sbp		if (error)
43075374Sbp			return error;
43175374Sbp		return EXDEV;
43275374Sbp	    default:
43375374Sbp		break;
43475374Sbp	}
43575374Sbp
43675374Sbp	SMB_IOD_RQLOCK(iod);
43775374Sbp	for (;;) {
43875374Sbp		if (vcp->vc_maxmux == 0) {
43975374Sbp			SMBERROR("maxmux == 0\n");
44075374Sbp			break;
44175374Sbp		}
44275374Sbp		if (iod->iod_muxcnt < vcp->vc_maxmux)
44375374Sbp			break;
44475374Sbp		iod->iod_muxwant++;
44575374Sbp		msleep(&iod->iod_muxwant, SMB_IOD_RQLOCKPTR(iod),
44675374Sbp		    PWAIT, "90mux", 0);
44775374Sbp	}
44875374Sbp	iod->iod_muxcnt++;
44975374Sbp	TAILQ_INSERT_TAIL(&iod->iod_rqlist, rqp, sr_link);
45075374Sbp	SMB_IOD_RQUNLOCK(iod);
45175374Sbp	smb_iod_wakeup(iod);
45275374Sbp	return 0;
45375374Sbp}
45475374Sbp
45575374Sbpint
45675374Sbpsmb_iod_removerq(struct smb_rq *rqp)
45775374Sbp{
45875374Sbp	struct smb_vc *vcp = rqp->sr_vc;
45975374Sbp	struct smbiod *iod = vcp->vc_iod;
46075374Sbp
46175374Sbp	SMBIODEBUG("\n");
46275374Sbp	if (rqp->sr_flags & SMBR_INTERNAL) {
46375374Sbp		SMB_IOD_RQLOCK(iod);
46475374Sbp		TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link);
46575374Sbp		SMB_IOD_RQUNLOCK(iod);
46675374Sbp		return 0;
46775374Sbp	}
46875374Sbp	SMB_IOD_RQLOCK(iod);
46975374Sbp	while (rqp->sr_flags & SMBR_XLOCK) {
47075374Sbp		rqp->sr_flags |= SMBR_XLOCKWANT;
47175374Sbp		msleep(rqp, SMB_IOD_RQLOCKPTR(iod), PWAIT, "90xrm", 0);
47275374Sbp	}
47375374Sbp	TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link);
47475374Sbp	iod->iod_muxcnt--;
47575374Sbp	if (iod->iod_muxwant) {
47675374Sbp		iod->iod_muxwant--;
47775374Sbp		wakeup(&iod->iod_muxwant);
47875374Sbp	}
47975374Sbp	SMB_IOD_RQUNLOCK(iod);
48075374Sbp	return 0;
48175374Sbp}
48275374Sbp
48375374Sbpint
48475374Sbpsmb_iod_waitrq(struct smb_rq *rqp)
48575374Sbp{
48675374Sbp	struct smbiod *iod = rqp->sr_vc->vc_iod;
48775374Sbp	int error;
48875374Sbp
48975374Sbp	SMBIODEBUG("\n");
49075374Sbp	if (rqp->sr_flags & SMBR_INTERNAL) {
49175374Sbp		for (;;) {
49275374Sbp			smb_iod_sendall(iod);
49375374Sbp			smb_iod_recvall(iod);
49475374Sbp			if (rqp->sr_rpgen != rqp->sr_rplast)
49575374Sbp				break;
49675374Sbp			tsleep(&iod->iod_flags, PWAIT, "90irq", hz);
49775374Sbp		}
49875374Sbp		smb_iod_removerq(rqp);
49975374Sbp		return rqp->sr_lerror;
50075374Sbp
50175374Sbp	}
50275374Sbp	SMBRQ_SLOCK(rqp);
50375374Sbp	if (rqp->sr_rpgen == rqp->sr_rplast)
50475374Sbp		msleep(&rqp->sr_state, SMBRQ_SLOCKPTR(rqp), PWAIT, "90wrq", 0);
50575374Sbp	rqp->sr_rplast++;
50675374Sbp	SMBRQ_SUNLOCK(rqp);
50775374Sbp	error = rqp->sr_lerror;
50875374Sbp	if (rqp->sr_flags & SMBR_MULTIPACKET) {
50975374Sbp		/*
51075374Sbp		 * If request should stay in the list, then reinsert it
51175374Sbp		 * at the end of queue so other waiters have chance to concur
51275374Sbp		 */
51375374Sbp		SMB_IOD_RQLOCK(iod);
51475374Sbp		TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link);
51575374Sbp		TAILQ_INSERT_TAIL(&iod->iod_rqlist, rqp, sr_link);
51675374Sbp		SMB_IOD_RQUNLOCK(iod);
51775374Sbp	} else
51875374Sbp		smb_iod_removerq(rqp);
51975374Sbp	return error;
52075374Sbp}
52175374Sbp
52275374Sbp
52375374Sbpstatic int
52475374Sbpsmb_iod_sendall(struct smbiod *iod)
52575374Sbp{
52675374Sbp	struct smb_vc *vcp = iod->iod_vc;
52775374Sbp	struct smb_rq *rqp;
52875374Sbp	struct timespec ts, tstimeout;
52975374Sbp	int herror;
53075374Sbp
53175374Sbp	herror = 0;
53275374Sbp	/*
53375374Sbp	 * Loop through the list of requests and send them if possible
53475374Sbp	 */
53575374Sbp	SMB_IOD_RQLOCK(iod);
53675374Sbp	TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) {
53775374Sbp		switch (rqp->sr_state) {
53875374Sbp		    case SMBRQ_NOTSENT:
53975374Sbp			rqp->sr_flags |= SMBR_XLOCK;
54075374Sbp			SMB_IOD_RQUNLOCK(iod);
54175374Sbp			herror = smb_iod_sendrq(iod, rqp);
54275374Sbp			SMB_IOD_RQLOCK(iod);
54375374Sbp			rqp->sr_flags &= ~SMBR_XLOCK;
54475374Sbp			if (rqp->sr_flags & SMBR_XLOCKWANT) {
54575374Sbp				rqp->sr_flags &= ~SMBR_XLOCKWANT;
54675374Sbp				wakeup(rqp);
54775374Sbp			}
54875374Sbp			break;
54975374Sbp		    case SMBRQ_SENT:
55075374Sbp			SMB_TRAN_GETPARAM(vcp, SMBTP_TIMEOUT, &tstimeout);
55175374Sbp			timespecadd(&tstimeout, &tstimeout);
55275374Sbp			getnanotime(&ts);
55375374Sbp			timespecsub(&ts, &tstimeout);
55475374Sbp			if (timespeccmp(&ts, &rqp->sr_timesent, >)) {
55575374Sbp				smb_iod_rqprocessed(rqp, ETIMEDOUT);
55675374Sbp			}
55775374Sbp			break;
55875374Sbp		    default:
55975374Sbp		}
56075374Sbp		if (herror)
56175374Sbp			break;
56275374Sbp	}
56375374Sbp	SMB_IOD_RQUNLOCK(iod);
56475374Sbp	if (herror == ENOTCONN)
56575374Sbp		smb_iod_dead(iod);
56675374Sbp	return 0;
56775374Sbp}
56875374Sbp
56975374Sbp/*
57075374Sbp * "main" function for smbiod daemon
57175374Sbp */
57275374Sbpstatic __inline void
57375374Sbpsmb_iod_main(struct smbiod *iod)
57475374Sbp{
57575374Sbp/*	struct smb_vc *vcp = iod->iod_vc;*/
57675374Sbp	struct smbiod_event *evp;
57775374Sbp/*	struct timespec tsnow;*/
57875374Sbp	int error;
57975374Sbp
58075374Sbp	SMBIODEBUG("\n");
58175374Sbp	error = 0;
58275374Sbp
58375374Sbp	/*
58475374Sbp	 * Check all interesting events
58575374Sbp	 */
58675374Sbp	for (;;) {
58775374Sbp		SMB_IOD_EVLOCK(iod);
58875374Sbp		evp = STAILQ_FIRST(&iod->iod_evlist);
58975374Sbp		if (evp == NULL) {
59075374Sbp			SMB_IOD_EVUNLOCK(iod);
59175374Sbp			break;
59275374Sbp		}
59375374Sbp		STAILQ_REMOVE_HEAD(&iod->iod_evlist, ev_link);
59475374Sbp		evp->ev_type |= SMBIOD_EV_PROCESSING;
59575374Sbp		SMB_IOD_EVUNLOCK(iod);
59675374Sbp		switch (evp->ev_type & SMBIOD_EV_MASK) {
59775374Sbp		    case SMBIOD_EV_CONNECT:
59875374Sbp			iod->iod_state = SMBIOD_ST_RECONNECT;
59975374Sbp			evp->ev_error = smb_iod_connect(iod);
60075374Sbp			break;
60175374Sbp		    case SMBIOD_EV_DISCONNECT:
60275374Sbp			evp->ev_error = smb_iod_disconnect(iod);
60375374Sbp			break;
60475374Sbp		    case SMBIOD_EV_TREECONNECT:
60575374Sbp			evp->ev_error = smb_iod_treeconnect(iod, evp->ev_ident);
60675374Sbp			break;
60775374Sbp		    case SMBIOD_EV_SHUTDOWN:
60875374Sbp			iod->iod_flags |= SMBIOD_SHUTDOWN;
60975374Sbp			break;
61075374Sbp		    case SMBIOD_EV_NEWRQ:
61175374Sbp			break;
61275374Sbp		}
61375374Sbp		if (evp->ev_type & SMBIOD_EV_SYNC) {
61475374Sbp			SMB_IOD_EVLOCK(iod);
61575374Sbp			wakeup(evp);
61675374Sbp			SMB_IOD_EVUNLOCK(iod);
61775374Sbp		} else
61875374Sbp			free(evp, M_SMBIOD);
61975374Sbp	}
62075374Sbp#if 0
62175374Sbp	if (iod->iod_state == SMBIOD_ST_VCACTIVE) {
62275374Sbp		getnanotime(&tsnow);
62375374Sbp		timespecsub(&tsnow, &iod->iod_pingtimo);
62475374Sbp		if (timespeccmp(&tsnow, &iod->iod_lastrqsent, >)) {
62575374Sbp			smb_smb_echo(vcp, &iod->iod_scred);
62675374Sbp		}
62775374Sbp	}
62875374Sbp#endif
62975374Sbp	smb_iod_sendall(iod);
63075374Sbp	smb_iod_recvall(iod);
63175374Sbp	return;
63275374Sbp}
63375374Sbp
63475374Sbpvoid
63575374Sbpsmb_iod_thread(void *arg)
63675374Sbp{
63775374Sbp	struct smbiod *iod = arg;
63875374Sbp
63975374Sbp	mtx_lock(&Giant);
64087192Sbp	/*
64187192Sbp	 * Here we assume that the thread structure will be the same
64287192Sbp	 * for an entire kthread (kproc, to be more precise) life.
64387192Sbp	 */
64487192Sbp	iod->iod_td = curthread;
64587192Sbp	smb_makescred(&iod->iod_scred, iod->iod_td, NULL);
64675374Sbp	while ((iod->iod_flags & SMBIOD_SHUTDOWN) == 0) {
64775374Sbp		smb_iod_main(iod);
64875374Sbp		SMBIODEBUG("going to sleep for %d ticks\n", iod->iod_sleeptimo);
64975374Sbp/*		mtx_unlock(&Giant, MTX_DEF);*/
65075374Sbp		if (iod->iod_flags & SMBIOD_SHUTDOWN)
65175374Sbp			break;
65275374Sbp		tsleep(&iod->iod_flags, PWAIT, "90idle", iod->iod_sleeptimo);
65375374Sbp	}
65475374Sbp/*	mtx_lock(&Giant, MTX_DEF);*/
65575374Sbp	kthread_exit(0);
65675374Sbp}
65775374Sbp
65875374Sbpint
65975374Sbpsmb_iod_create(struct smb_vc *vcp)
66075374Sbp{
66175374Sbp	struct smbiod *iod;
66275374Sbp	int error;
66375374Sbp
66475374Sbp	iod = smb_zmalloc(sizeof(*iod), M_SMBIOD, M_WAITOK);
66575374Sbp	iod->iod_id = smb_iod_next++;
66675374Sbp	iod->iod_state = SMBIOD_ST_NOTCONN;
66775374Sbp	iod->iod_vc = vcp;
66875374Sbp	iod->iod_sleeptimo = hz * SMBIOD_SLEEP_TIMO;
66975374Sbp	iod->iod_pingtimo.tv_sec = SMBIOD_PING_TIMO;
67075374Sbp	getnanotime(&iod->iod_lastrqsent);
67175374Sbp	vcp->vc_iod = iod;
67275374Sbp	smb_sl_init(&iod->iod_rqlock, "90rql");
67375374Sbp	TAILQ_INIT(&iod->iod_rqlist);
67475374Sbp	smb_sl_init(&iod->iod_evlock, "90evl");
67575374Sbp	STAILQ_INIT(&iod->iod_evlist);
67687192Sbp	error = kthread_create(smb_iod_thread, iod, &iod->iod_p,
67775374Sbp	    RFNOWAIT, "smbiod%d", iod->iod_id);
67875374Sbp	if (error) {
67975374Sbp		SMBERROR("can't start smbiod: %d", error);
68075374Sbp		free(iod, M_SMBIOD);
68175374Sbp		return error;
68275374Sbp	}
68375374Sbp	return 0;
68475374Sbp}
68575374Sbp
68675374Sbpint
68775374Sbpsmb_iod_destroy(struct smbiod *iod)
68875374Sbp{
68975374Sbp	smb_iod_request(iod, SMBIOD_EV_SHUTDOWN | SMBIOD_EV_SYNC, NULL);
69082045Sbp	smb_sl_destroy(&iod->iod_rqlock);
69182045Sbp	smb_sl_destroy(&iod->iod_evlock);
69275374Sbp	free(iod, M_SMBIOD);
69375374Sbp	return 0;
69475374Sbp}
69575374Sbp
69675374Sbpint
69775374Sbpsmb_iod_init(void)
69875374Sbp{
69975374Sbp	return 0;
70075374Sbp}
70175374Sbp
70275374Sbpint
70375374Sbpsmb_iod_done(void)
70475374Sbp{
70575374Sbp	return 0;
70675374Sbp}
70775374Sbp
708