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 *
1475374Sbp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1575374Sbp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1675374Sbp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1775374Sbp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1875374Sbp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1975374Sbp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2075374Sbp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2175374Sbp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2275374Sbp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2375374Sbp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2475374Sbp * SUCH DAMAGE.
2575374Sbp */
26116189Sobrien
27116189Sobrien#include <sys/cdefs.h>
28116189Sobrien__FBSDID("$FreeBSD$");
2975374Sbp
3075374Sbp#include <sys/param.h>
3175374Sbp#include <sys/systm.h>
3295533Smike#include <sys/endian.h>
3375374Sbp#include <sys/proc.h>
3475374Sbp#include <sys/kernel.h>
3575374Sbp#include <sys/kthread.h>
3675374Sbp#include <sys/malloc.h>
3775374Sbp#include <sys/mbuf.h>
3875374Sbp#include <sys/unistd.h>
3975374Sbp
4075374Sbp#include <netsmb/smb.h>
4175374Sbp#include <netsmb/smb_conn.h>
4275374Sbp#include <netsmb/smb_rq.h>
4375374Sbp#include <netsmb/smb_tran.h>
4475374Sbp#include <netsmb/smb_trantcp.h>
4575374Sbp
4675374Sbp
4775374Sbp#define SMBIOD_SLEEP_TIMO	2
4875374Sbp#define	SMBIOD_PING_TIMO	60	/* seconds */
4975374Sbp
5075374Sbp#define	SMB_IOD_EVLOCKPTR(iod)	(&((iod)->iod_evlock))
5175374Sbp#define	SMB_IOD_EVLOCK(iod)	smb_sl_lock(&((iod)->iod_evlock))
5275374Sbp#define	SMB_IOD_EVUNLOCK(iod)	smb_sl_unlock(&((iod)->iod_evlock))
5375374Sbp
5475374Sbp#define	SMB_IOD_RQLOCKPTR(iod)	(&((iod)->iod_rqlock))
5575374Sbp#define	SMB_IOD_RQLOCK(iod)	smb_sl_lock(&((iod)->iod_rqlock))
5675374Sbp#define	SMB_IOD_RQUNLOCK(iod)	smb_sl_unlock(&((iod)->iod_rqlock))
5775374Sbp
5875374Sbp#define	smb_iod_wakeup(iod)	wakeup(&(iod)->iod_flags)
5975374Sbp
6075374Sbp
6175374Sbpstatic MALLOC_DEFINE(M_SMBIOD, "SMBIOD", "SMB network io daemon");
6275374Sbp
6375374Sbpstatic int smb_iod_next;
6475374Sbp
6575374Sbpstatic int  smb_iod_sendall(struct smbiod *iod);
6675374Sbpstatic int  smb_iod_disconnect(struct smbiod *iod);
6775374Sbpstatic void smb_iod_thread(void *);
6875374Sbp
6975374Sbpstatic __inline void
7075374Sbpsmb_iod_rqprocessed(struct smb_rq *rqp, int error)
7175374Sbp{
7275374Sbp	SMBRQ_SLOCK(rqp);
7375374Sbp	rqp->sr_lerror = error;
7475374Sbp	rqp->sr_rpgen++;
7575374Sbp	rqp->sr_state = SMBRQ_NOTIFIED;
7675374Sbp	wakeup(&rqp->sr_state);
7775374Sbp	SMBRQ_SUNLOCK(rqp);
7875374Sbp}
7975374Sbp
8075374Sbpstatic void
8175374Sbpsmb_iod_invrq(struct smbiod *iod)
8275374Sbp{
8375374Sbp	struct smb_rq *rqp;
8475374Sbp
8575374Sbp	/*
8682045Sbp	 * Invalidate all outstanding requests for this connection
8775374Sbp	 */
8875374Sbp	SMB_IOD_RQLOCK(iod);
8975374Sbp	TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) {
9075374Sbp		rqp->sr_flags |= SMBR_RESTART;
9175374Sbp		smb_iod_rqprocessed(rqp, ENOTCONN);
9275374Sbp	}
9375374Sbp	SMB_IOD_RQUNLOCK(iod);
9475374Sbp}
9575374Sbp
9675374Sbpstatic void
9775374Sbpsmb_iod_closetran(struct smbiod *iod)
9875374Sbp{
9975374Sbp	struct smb_vc *vcp = iod->iod_vc;
10087192Sbp	struct thread *td = iod->iod_td;
10175374Sbp
10275374Sbp	if (vcp->vc_tdata == NULL)
10375374Sbp		return;
10487192Sbp	SMB_TRAN_DISCONNECT(vcp, td);
10587192Sbp	SMB_TRAN_DONE(vcp, td);
10675374Sbp	vcp->vc_tdata = NULL;
10775374Sbp}
10875374Sbp
10975374Sbpstatic void
11075374Sbpsmb_iod_dead(struct smbiod *iod)
11175374Sbp{
11275374Sbp	iod->iod_state = SMBIOD_ST_DEAD;
11375374Sbp	smb_iod_closetran(iod);
11475374Sbp	smb_iod_invrq(iod);
11575374Sbp}
11675374Sbp
11775374Sbpstatic int
11875374Sbpsmb_iod_connect(struct smbiod *iod)
11975374Sbp{
12075374Sbp	struct smb_vc *vcp = iod->iod_vc;
12187192Sbp	struct thread *td = iod->iod_td;
12275374Sbp	int error;
12375374Sbp
12475374Sbp	SMBIODEBUG("%d\n", iod->iod_state);
12575374Sbp	switch(iod->iod_state) {
12675374Sbp	    case SMBIOD_ST_VCACTIVE:
12775374Sbp		SMBERROR("called for already opened connection\n");
12875374Sbp		return EISCONN;
12975374Sbp	    case SMBIOD_ST_DEAD:
13075374Sbp		return ENOTCONN;	/* XXX: last error code ? */
13175374Sbp	    default:
13275374Sbp		break;
13375374Sbp	}
13475374Sbp	vcp->vc_genid++;
13575374Sbp	error = 0;
136119376Smarcel
137119376Smarcel	error = (int)SMB_TRAN_CREATE(vcp, td);
138119376Smarcel	if (error)
139119376Smarcel		goto fail;
140119376Smarcel	SMBIODEBUG("tcreate\n");
141119376Smarcel	if (vcp->vc_laddr) {
142119376Smarcel		error = (int)SMB_TRAN_BIND(vcp, vcp->vc_laddr, td);
143119376Smarcel		if (error)
144119376Smarcel			goto fail;
145119376Smarcel	}
146119376Smarcel	SMBIODEBUG("tbind\n");
147119376Smarcel	error = (int)SMB_TRAN_CONNECT(vcp, vcp->vc_paddr, td);
148119376Smarcel	if (error)
149119376Smarcel		goto fail;
150119376Smarcel	SMB_TRAN_SETPARAM(vcp, SMBTP_SELECTID, &iod->iod_flags);
151119376Smarcel	iod->iod_state = SMBIOD_ST_TRANACTIVE;
152119376Smarcel	SMBIODEBUG("tconnect\n");
153119376Smarcel	/* vcp->vc_mid = 0;*/
154119376Smarcel	error = (int)smb_smb_negotiate(vcp, &iod->iod_scred);
155119376Smarcel	if (error)
156119376Smarcel		goto fail;
157119376Smarcel	SMBIODEBUG("snegotiate\n");
158119376Smarcel	error = (int)smb_smb_ssnsetup(vcp, &iod->iod_scred);
159119376Smarcel	if (error)
160119376Smarcel		goto fail;
161119376Smarcel	iod->iod_state = SMBIOD_ST_VCACTIVE;
162119376Smarcel	SMBIODEBUG("completed\n");
163119376Smarcel	smb_iod_invrq(iod);
164119376Smarcel	return (0);
165119376Smarcel
166119376Smarcel fail:
167119376Smarcel	smb_iod_dead(iod);
168119376Smarcel	return (error);
16975374Sbp}
17075374Sbp
17175374Sbpstatic int
17275374Sbpsmb_iod_disconnect(struct smbiod *iod)
17375374Sbp{
17475374Sbp	struct smb_vc *vcp = iod->iod_vc;
17575374Sbp
17675374Sbp	SMBIODEBUG("\n");
17775374Sbp	if (iod->iod_state == SMBIOD_ST_VCACTIVE) {
17875374Sbp		smb_smb_ssnclose(vcp, &iod->iod_scred);
17975374Sbp		iod->iod_state = SMBIOD_ST_TRANACTIVE;
18075374Sbp	}
18175374Sbp	vcp->vc_smbuid = SMB_UID_UNKNOWN;
18275374Sbp	smb_iod_closetran(iod);
18375374Sbp	iod->iod_state = SMBIOD_ST_NOTCONN;
18475374Sbp	return 0;
18575374Sbp}
18675374Sbp
18775374Sbpstatic int
18875374Sbpsmb_iod_treeconnect(struct smbiod *iod, struct smb_share *ssp)
18975374Sbp{
19075374Sbp	int error;
19175374Sbp
19275374Sbp	if (iod->iod_state != SMBIOD_ST_VCACTIVE) {
19375374Sbp		if (iod->iod_state != SMBIOD_ST_DEAD)
19475374Sbp			return ENOTCONN;
19575374Sbp		iod->iod_state = SMBIOD_ST_RECONNECT;
19675374Sbp		error = smb_iod_connect(iod);
19775374Sbp		if (error)
19875374Sbp			return error;
19975374Sbp	}
20075374Sbp	SMBIODEBUG("tree reconnect\n");
20175374Sbp	SMBS_ST_LOCK(ssp);
20275374Sbp	ssp->ss_flags |= SMBS_RECONNECTING;
20375374Sbp	SMBS_ST_UNLOCK(ssp);
20475374Sbp	error = smb_smb_treeconnect(ssp, &iod->iod_scred);
20575374Sbp	SMBS_ST_LOCK(ssp);
20675374Sbp	ssp->ss_flags &= ~SMBS_RECONNECTING;
20775374Sbp	SMBS_ST_UNLOCK(ssp);
20875374Sbp	wakeup(&ssp->ss_vcgenid);
20975374Sbp	return error;
21075374Sbp}
21175374Sbp
21275374Sbpstatic int
21375374Sbpsmb_iod_sendrq(struct smbiod *iod, struct smb_rq *rqp)
21475374Sbp{
21587192Sbp	struct thread *td = iod->iod_td;
21675374Sbp	struct smb_vc *vcp = iod->iod_vc;
21775374Sbp	struct smb_share *ssp = rqp->sr_share;
21875374Sbp	struct mbuf *m;
21975374Sbp	int error;
22075374Sbp
22175374Sbp	SMBIODEBUG("iod_state = %d\n", iod->iod_state);
22275374Sbp	switch (iod->iod_state) {
22375374Sbp	    case SMBIOD_ST_NOTCONN:
22475374Sbp		smb_iod_rqprocessed(rqp, ENOTCONN);
22575374Sbp		return 0;
22675374Sbp	    case SMBIOD_ST_DEAD:
22775374Sbp		iod->iod_state = SMBIOD_ST_RECONNECT;
22875374Sbp		return 0;
22975374Sbp	    case SMBIOD_ST_RECONNECT:
23075374Sbp		return 0;
23175374Sbp	    default:
23275374Sbp		break;
23375374Sbp	}
23475374Sbp	if (rqp->sr_sendcnt == 0) {
23575374Sbp#ifdef movedtoanotherplace
23675374Sbp		if (vcp->vc_maxmux != 0 && iod->iod_muxcnt >= vcp->vc_maxmux)
23775374Sbp			return 0;
23875374Sbp#endif
239161523Smarcel		le16enc(rqp->sr_rqtid, ssp ? ssp->ss_tid : SMB_TID_UNKNOWN);
240161523Smarcel		le16enc(rqp->sr_rquid, vcp ? vcp->vc_smbuid : 0);
24175374Sbp		mb_fixhdr(&rqp->sr_rq);
242124087Stjr		if (vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE)
243124087Stjr			smb_rq_sign(rqp);
24475374Sbp	}
24575374Sbp	if (rqp->sr_sendcnt++ > 5) {
24675374Sbp		rqp->sr_flags |= SMBR_RESTART;
24775374Sbp		smb_iod_rqprocessed(rqp, rqp->sr_lerror);
24875374Sbp		/*
24975374Sbp		 * If all attempts to send a request failed, then
25075374Sbp		 * something is seriously hosed.
25175374Sbp		 */
25275374Sbp		return ENOTCONN;
25375374Sbp	}
25475374Sbp	SMBSDEBUG("M:%04x, P:%04x, U:%04x, T:%04x\n", rqp->sr_mid, 0, 0, 0);
25575374Sbp	m_dumpm(rqp->sr_rq.mb_top);
256243882Sglebius	m = m_copym(rqp->sr_rq.mb_top, 0, M_COPYALL, M_WAITOK);
257177599Sru	error = rqp->sr_lerror = SMB_TRAN_SEND(vcp, m, td);
25875374Sbp	if (error == 0) {
25975374Sbp		getnanotime(&rqp->sr_timesent);
26075374Sbp		iod->iod_lastrqsent = rqp->sr_timesent;
26175374Sbp		rqp->sr_flags |= SMBR_SENT;
26275374Sbp		rqp->sr_state = SMBRQ_SENT;
26375374Sbp		return 0;
26475374Sbp	}
26575374Sbp	/*
26675374Sbp	 * Check for fatal errors
26775374Sbp	 */
26875374Sbp	if (SMB_TRAN_FATAL(vcp, error)) {
26975374Sbp		/*
27075374Sbp		 * No further attempts should be made
27175374Sbp		 */
27275374Sbp		return ENOTCONN;
27375374Sbp	}
27475374Sbp	if (smb_rq_intr(rqp))
27575374Sbp		smb_iod_rqprocessed(rqp, EINTR);
27675374Sbp	return 0;
27775374Sbp}
27875374Sbp
27975374Sbp/*
28075374Sbp * Process incoming packets
28175374Sbp */
28275374Sbpstatic int
28375374Sbpsmb_iod_recvall(struct smbiod *iod)
28475374Sbp{
28575374Sbp	struct smb_vc *vcp = iod->iod_vc;
28687192Sbp	struct thread *td = iod->iod_td;
28775374Sbp	struct smb_rq *rqp;
28875374Sbp	struct mbuf *m;
28975374Sbp	u_char *hp;
29075374Sbp	u_short mid;
29175374Sbp	int error;
29275374Sbp
29375374Sbp	switch (iod->iod_state) {
29475374Sbp	    case SMBIOD_ST_NOTCONN:
29575374Sbp	    case SMBIOD_ST_DEAD:
29675374Sbp	    case SMBIOD_ST_RECONNECT:
29775374Sbp		return 0;
29875374Sbp	    default:
29975374Sbp		break;
30075374Sbp	}
30175374Sbp	for (;;) {
30275374Sbp		m = NULL;
30387192Sbp		error = SMB_TRAN_RECV(vcp, &m, td);
30475374Sbp		if (error == EWOULDBLOCK)
30575374Sbp			break;
30675374Sbp		if (SMB_TRAN_FATAL(vcp, error)) {
30775374Sbp			smb_iod_dead(iod);
30875374Sbp			break;
30975374Sbp		}
31075374Sbp		if (error)
31175374Sbp			break;
31275374Sbp		if (m == NULL) {
31375374Sbp			SMBERROR("tran return NULL without error\n");
31475374Sbp			error = EPIPE;
31575374Sbp			continue;
31675374Sbp		}
31775374Sbp		m = m_pullup(m, SMB_HDRLEN);
31875374Sbp		if (m == NULL)
31975374Sbp			continue;	/* wait for a good packet */
32075374Sbp		/*
32175374Sbp		 * Now we got an entire and possibly invalid SMB packet.
32275374Sbp		 * Be careful while parsing it.
32375374Sbp		 */
32475374Sbp		m_dumpm(m);
32575374Sbp		hp = mtod(m, u_char*);
32675374Sbp		if (bcmp(hp, SMB_SIGNATURE, SMB_SIGLEN) != 0) {
32775374Sbp			m_freem(m);
32875374Sbp			continue;
32975374Sbp		}
33075374Sbp		mid = SMB_HDRMID(hp);
33175374Sbp		SMBSDEBUG("mid %04x\n", (u_int)mid);
33275374Sbp		SMB_IOD_RQLOCK(iod);
33375374Sbp		TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) {
33475374Sbp			if (rqp->sr_mid != mid)
33575374Sbp				continue;
33675374Sbp			SMBRQ_SLOCK(rqp);
33775374Sbp			if (rqp->sr_rp.md_top == NULL) {
33875374Sbp				md_initm(&rqp->sr_rp, m);
33975374Sbp			} else {
34075374Sbp				if (rqp->sr_flags & SMBR_MULTIPACKET) {
34175374Sbp					md_append_record(&rqp->sr_rp, m);
34275374Sbp				} else {
34375374Sbp					SMBRQ_SUNLOCK(rqp);
34475374Sbp					SMBERROR("duplicate response %d (ignored)\n", mid);
34575374Sbp					break;
34675374Sbp				}
34775374Sbp			}
34875374Sbp			SMBRQ_SUNLOCK(rqp);
34975374Sbp			smb_iod_rqprocessed(rqp, 0);
35075374Sbp			break;
35175374Sbp		}
35275374Sbp		SMB_IOD_RQUNLOCK(iod);
35375374Sbp		if (rqp == NULL) {
35475374Sbp			SMBERROR("drop resp with mid %d\n", (u_int)mid);
35575374Sbp/*			smb_printrqlist(vcp);*/
35675374Sbp			m_freem(m);
35775374Sbp		}
35875374Sbp	}
35975374Sbp	/*
36075374Sbp	 * check for interrupts
36175374Sbp	 */
36275374Sbp	SMB_IOD_RQLOCK(iod);
36375374Sbp	TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) {
364112888Sjeff		if (smb_td_intr(rqp->sr_cred->scr_td)) {
36575374Sbp			smb_iod_rqprocessed(rqp, EINTR);
36675374Sbp		}
36775374Sbp	}
36875374Sbp	SMB_IOD_RQUNLOCK(iod);
36975374Sbp	return 0;
37075374Sbp}
37175374Sbp
37275374Sbpint
37375374Sbpsmb_iod_request(struct smbiod *iod, int event, void *ident)
37475374Sbp{
37575374Sbp	struct smbiod_event *evp;
37675374Sbp	int error;
37775374Sbp
37875374Sbp	SMBIODEBUG("\n");
379111119Simp	evp = smb_zmalloc(sizeof(*evp), M_SMBIOD, M_WAITOK);
38075374Sbp	evp->ev_type = event;
38175374Sbp	evp->ev_ident = ident;
38275374Sbp	SMB_IOD_EVLOCK(iod);
38375374Sbp	STAILQ_INSERT_TAIL(&iod->iod_evlist, evp, ev_link);
38475374Sbp	if ((event & SMBIOD_EV_SYNC) == 0) {
38575374Sbp		SMB_IOD_EVUNLOCK(iod);
38675374Sbp		smb_iod_wakeup(iod);
38775374Sbp		return 0;
38875374Sbp	}
38975374Sbp	smb_iod_wakeup(iod);
39075374Sbp	msleep(evp, SMB_IOD_EVLOCKPTR(iod), PWAIT | PDROP, "90evw", 0);
39175374Sbp	error = evp->ev_error;
39275374Sbp	free(evp, M_SMBIOD);
39375374Sbp	return error;
39475374Sbp}
39575374Sbp
39675374Sbp/*
39775374Sbp * Place request in the queue.
39875374Sbp * Request from smbiod have a high priority.
39975374Sbp */
40075374Sbpint
40175374Sbpsmb_iod_addrq(struct smb_rq *rqp)
40275374Sbp{
40375374Sbp	struct smb_vc *vcp = rqp->sr_vc;
40475374Sbp	struct smbiod *iod = vcp->vc_iod;
40575374Sbp	int error;
40675374Sbp
40775374Sbp	SMBIODEBUG("\n");
408116339Stjr	if (rqp->sr_cred->scr_td != NULL &&
409116339Stjr	    rqp->sr_cred->scr_td->td_proc == iod->iod_p) {
41075374Sbp		rqp->sr_flags |= SMBR_INTERNAL;
41175374Sbp		SMB_IOD_RQLOCK(iod);
41275374Sbp		TAILQ_INSERT_HEAD(&iod->iod_rqlist, rqp, sr_link);
41375374Sbp		SMB_IOD_RQUNLOCK(iod);
41475374Sbp		for (;;) {
41575374Sbp			if (smb_iod_sendrq(iod, rqp) != 0) {
41675374Sbp				smb_iod_dead(iod);
41775374Sbp				break;
41875374Sbp			}
41975374Sbp			/*
42075374Sbp			 * we don't need to lock state field here
42175374Sbp			 */
42275374Sbp			if (rqp->sr_state != SMBRQ_NOTSENT)
42375374Sbp				break;
42475374Sbp			tsleep(&iod->iod_flags, PWAIT, "90sndw", hz);
42575374Sbp		}
42675374Sbp		if (rqp->sr_lerror)
42775374Sbp			smb_iod_removerq(rqp);
42875374Sbp		return rqp->sr_lerror;
42975374Sbp	}
43075374Sbp
43175374Sbp	switch (iod->iod_state) {
43275374Sbp	    case SMBIOD_ST_NOTCONN:
43375374Sbp		return ENOTCONN;
43475374Sbp	    case SMBIOD_ST_DEAD:
43575374Sbp		error = smb_iod_request(vcp->vc_iod, SMBIOD_EV_CONNECT | SMBIOD_EV_SYNC, NULL);
43675374Sbp		if (error)
43775374Sbp			return error;
43875374Sbp		return EXDEV;
43975374Sbp	    default:
44075374Sbp		break;
44175374Sbp	}
44275374Sbp
44375374Sbp	SMB_IOD_RQLOCK(iod);
44475374Sbp	for (;;) {
44575374Sbp		if (vcp->vc_maxmux == 0) {
44675374Sbp			SMBERROR("maxmux == 0\n");
44775374Sbp			break;
44875374Sbp		}
44975374Sbp		if (iod->iod_muxcnt < vcp->vc_maxmux)
45075374Sbp			break;
45175374Sbp		iod->iod_muxwant++;
45275374Sbp		msleep(&iod->iod_muxwant, SMB_IOD_RQLOCKPTR(iod),
45375374Sbp		    PWAIT, "90mux", 0);
45475374Sbp	}
45575374Sbp	iod->iod_muxcnt++;
45675374Sbp	TAILQ_INSERT_TAIL(&iod->iod_rqlist, rqp, sr_link);
45775374Sbp	SMB_IOD_RQUNLOCK(iod);
45875374Sbp	smb_iod_wakeup(iod);
45975374Sbp	return 0;
46075374Sbp}
46175374Sbp
46275374Sbpint
46375374Sbpsmb_iod_removerq(struct smb_rq *rqp)
46475374Sbp{
46575374Sbp	struct smb_vc *vcp = rqp->sr_vc;
46675374Sbp	struct smbiod *iod = vcp->vc_iod;
46775374Sbp
46875374Sbp	SMBIODEBUG("\n");
46975374Sbp	if (rqp->sr_flags & SMBR_INTERNAL) {
47075374Sbp		SMB_IOD_RQLOCK(iod);
47175374Sbp		TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link);
47275374Sbp		SMB_IOD_RQUNLOCK(iod);
47375374Sbp		return 0;
47475374Sbp	}
47575374Sbp	SMB_IOD_RQLOCK(iod);
47675374Sbp	while (rqp->sr_flags & SMBR_XLOCK) {
47775374Sbp		rqp->sr_flags |= SMBR_XLOCKWANT;
47875374Sbp		msleep(rqp, SMB_IOD_RQLOCKPTR(iod), PWAIT, "90xrm", 0);
47975374Sbp	}
48075374Sbp	TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link);
48175374Sbp	iod->iod_muxcnt--;
48275374Sbp	if (iod->iod_muxwant) {
48375374Sbp		iod->iod_muxwant--;
48475374Sbp		wakeup(&iod->iod_muxwant);
48575374Sbp	}
48675374Sbp	SMB_IOD_RQUNLOCK(iod);
48775374Sbp	return 0;
48875374Sbp}
48975374Sbp
49075374Sbpint
49175374Sbpsmb_iod_waitrq(struct smb_rq *rqp)
49275374Sbp{
49375374Sbp	struct smbiod *iod = rqp->sr_vc->vc_iod;
49475374Sbp	int error;
49575374Sbp
49675374Sbp	SMBIODEBUG("\n");
49775374Sbp	if (rqp->sr_flags & SMBR_INTERNAL) {
49875374Sbp		for (;;) {
49975374Sbp			smb_iod_sendall(iod);
50075374Sbp			smb_iod_recvall(iod);
50175374Sbp			if (rqp->sr_rpgen != rqp->sr_rplast)
50275374Sbp				break;
50375374Sbp			tsleep(&iod->iod_flags, PWAIT, "90irq", hz);
50475374Sbp		}
50575374Sbp		smb_iod_removerq(rqp);
50675374Sbp		return rqp->sr_lerror;
50775374Sbp
50875374Sbp	}
50975374Sbp	SMBRQ_SLOCK(rqp);
51075374Sbp	if (rqp->sr_rpgen == rqp->sr_rplast)
51175374Sbp		msleep(&rqp->sr_state, SMBRQ_SLOCKPTR(rqp), PWAIT, "90wrq", 0);
51275374Sbp	rqp->sr_rplast++;
51375374Sbp	SMBRQ_SUNLOCK(rqp);
51475374Sbp	error = rqp->sr_lerror;
51575374Sbp	if (rqp->sr_flags & SMBR_MULTIPACKET) {
51675374Sbp		/*
51775374Sbp		 * If request should stay in the list, then reinsert it
51875374Sbp		 * at the end of queue so other waiters have chance to concur
51975374Sbp		 */
52075374Sbp		SMB_IOD_RQLOCK(iod);
52175374Sbp		TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link);
52275374Sbp		TAILQ_INSERT_TAIL(&iod->iod_rqlist, rqp, sr_link);
52375374Sbp		SMB_IOD_RQUNLOCK(iod);
52475374Sbp	} else
52575374Sbp		smb_iod_removerq(rqp);
52675374Sbp	return error;
52775374Sbp}
52875374Sbp
52975374Sbp
53075374Sbpstatic int
53175374Sbpsmb_iod_sendall(struct smbiod *iod)
53275374Sbp{
53375374Sbp	struct smb_vc *vcp = iod->iod_vc;
53475374Sbp	struct smb_rq *rqp;
53575374Sbp	struct timespec ts, tstimeout;
53675374Sbp	int herror;
53775374Sbp
53875374Sbp	herror = 0;
53975374Sbp	/*
54075374Sbp	 * Loop through the list of requests and send them if possible
54175374Sbp	 */
54275374Sbp	SMB_IOD_RQLOCK(iod);
54375374Sbp	TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) {
54475374Sbp		switch (rqp->sr_state) {
54575374Sbp		    case SMBRQ_NOTSENT:
54675374Sbp			rqp->sr_flags |= SMBR_XLOCK;
54775374Sbp			SMB_IOD_RQUNLOCK(iod);
54875374Sbp			herror = smb_iod_sendrq(iod, rqp);
54975374Sbp			SMB_IOD_RQLOCK(iod);
55075374Sbp			rqp->sr_flags &= ~SMBR_XLOCK;
55175374Sbp			if (rqp->sr_flags & SMBR_XLOCKWANT) {
55275374Sbp				rqp->sr_flags &= ~SMBR_XLOCKWANT;
55375374Sbp				wakeup(rqp);
55475374Sbp			}
55575374Sbp			break;
55675374Sbp		    case SMBRQ_SENT:
55775374Sbp			SMB_TRAN_GETPARAM(vcp, SMBTP_TIMEOUT, &tstimeout);
55875374Sbp			timespecadd(&tstimeout, &tstimeout);
55975374Sbp			getnanotime(&ts);
56075374Sbp			timespecsub(&ts, &tstimeout);
56175374Sbp			if (timespeccmp(&ts, &rqp->sr_timesent, >)) {
56275374Sbp				smb_iod_rqprocessed(rqp, ETIMEDOUT);
56375374Sbp			}
56475374Sbp			break;
56575374Sbp		    default:
56697209Speter			break;
56775374Sbp		}
56875374Sbp		if (herror)
56975374Sbp			break;
57075374Sbp	}
57175374Sbp	SMB_IOD_RQUNLOCK(iod);
57275374Sbp	if (herror == ENOTCONN)
57375374Sbp		smb_iod_dead(iod);
57475374Sbp	return 0;
57575374Sbp}
57675374Sbp
57775374Sbp/*
57875374Sbp * "main" function for smbiod daemon
57975374Sbp */
58075374Sbpstatic __inline void
58175374Sbpsmb_iod_main(struct smbiod *iod)
58275374Sbp{
58375374Sbp/*	struct smb_vc *vcp = iod->iod_vc;*/
58475374Sbp	struct smbiod_event *evp;
58575374Sbp/*	struct timespec tsnow;*/
58675374Sbp	int error;
58775374Sbp
58875374Sbp	SMBIODEBUG("\n");
58975374Sbp	error = 0;
59075374Sbp
59175374Sbp	/*
59275374Sbp	 * Check all interesting events
59375374Sbp	 */
59475374Sbp	for (;;) {
59575374Sbp		SMB_IOD_EVLOCK(iod);
59675374Sbp		evp = STAILQ_FIRST(&iod->iod_evlist);
59775374Sbp		if (evp == NULL) {
59875374Sbp			SMB_IOD_EVUNLOCK(iod);
59975374Sbp			break;
60075374Sbp		}
60175374Sbp		STAILQ_REMOVE_HEAD(&iod->iod_evlist, ev_link);
60275374Sbp		evp->ev_type |= SMBIOD_EV_PROCESSING;
60375374Sbp		SMB_IOD_EVUNLOCK(iod);
60475374Sbp		switch (evp->ev_type & SMBIOD_EV_MASK) {
60575374Sbp		    case SMBIOD_EV_CONNECT:
60675374Sbp			iod->iod_state = SMBIOD_ST_RECONNECT;
60775374Sbp			evp->ev_error = smb_iod_connect(iod);
60875374Sbp			break;
60975374Sbp		    case SMBIOD_EV_DISCONNECT:
61075374Sbp			evp->ev_error = smb_iod_disconnect(iod);
61175374Sbp			break;
61275374Sbp		    case SMBIOD_EV_TREECONNECT:
61375374Sbp			evp->ev_error = smb_iod_treeconnect(iod, evp->ev_ident);
61475374Sbp			break;
61575374Sbp		    case SMBIOD_EV_SHUTDOWN:
61675374Sbp			iod->iod_flags |= SMBIOD_SHUTDOWN;
61775374Sbp			break;
61875374Sbp		    case SMBIOD_EV_NEWRQ:
61975374Sbp			break;
62075374Sbp		}
62175374Sbp		if (evp->ev_type & SMBIOD_EV_SYNC) {
62275374Sbp			SMB_IOD_EVLOCK(iod);
62375374Sbp			wakeup(evp);
62475374Sbp			SMB_IOD_EVUNLOCK(iod);
62575374Sbp		} else
62675374Sbp			free(evp, M_SMBIOD);
62775374Sbp	}
62875374Sbp#if 0
62975374Sbp	if (iod->iod_state == SMBIOD_ST_VCACTIVE) {
63075374Sbp		getnanotime(&tsnow);
63175374Sbp		timespecsub(&tsnow, &iod->iod_pingtimo);
63275374Sbp		if (timespeccmp(&tsnow, &iod->iod_lastrqsent, >)) {
63375374Sbp			smb_smb_echo(vcp, &iod->iod_scred);
63475374Sbp		}
63575374Sbp	}
63675374Sbp#endif
63775374Sbp	smb_iod_sendall(iod);
63875374Sbp	smb_iod_recvall(iod);
63975374Sbp	return;
64075374Sbp}
64175374Sbp
64275374Sbpvoid
64375374Sbpsmb_iod_thread(void *arg)
64475374Sbp{
64575374Sbp	struct smbiod *iod = arg;
64675374Sbp
647177654Sattilio	mtx_lock(&Giant);
648177654Sattilio
64987192Sbp	/*
65087192Sbp	 * Here we assume that the thread structure will be the same
65187192Sbp	 * for an entire kthread (kproc, to be more precise) life.
65287192Sbp	 */
65387192Sbp	iod->iod_td = curthread;
65487192Sbp	smb_makescred(&iod->iod_scred, iod->iod_td, NULL);
65575374Sbp	while ((iod->iod_flags & SMBIOD_SHUTDOWN) == 0) {
65675374Sbp		smb_iod_main(iod);
65775374Sbp		SMBIODEBUG("going to sleep for %d ticks\n", iod->iod_sleeptimo);
65875374Sbp		if (iod->iod_flags & SMBIOD_SHUTDOWN)
65975374Sbp			break;
66075374Sbp		tsleep(&iod->iod_flags, PWAIT, "90idle", iod->iod_sleeptimo);
66175374Sbp	}
662291489Srmacklem
663291489Srmacklem	/* We can now safely destroy the mutexes and free the iod structure. */
664291489Srmacklem	smb_sl_destroy(&iod->iod_rqlock);
665291489Srmacklem	smb_sl_destroy(&iod->iod_evlock);
666291489Srmacklem	free(iod, M_SMBIOD);
667177654Sattilio	mtx_unlock(&Giant);
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);
693291655Srmacklem		vcp->vc_iod = NULL;
694291655Srmacklem		smb_sl_destroy(&iod->iod_rqlock);
695291655Srmacklem		smb_sl_destroy(&iod->iod_evlock);
69675374Sbp		free(iod, M_SMBIOD);
69775374Sbp		return error;
69875374Sbp	}
69975374Sbp	return 0;
70075374Sbp}
70175374Sbp
70275374Sbpint
70375374Sbpsmb_iod_destroy(struct smbiod *iod)
70475374Sbp{
70575374Sbp	smb_iod_request(iod, SMBIOD_EV_SHUTDOWN | SMBIOD_EV_SYNC, NULL);
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