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