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