smb_iod.c revision 97209
1193326Sed/* 2193326Sed * Copyright (c) 2000-2001 Boris Popov 3193326Sed * All rights reserved. 4193326Sed * 5193326Sed * Redistribution and use in source and binary forms, with or without 6193326Sed * modification, are permitted provided that the following conditions 7193326Sed * are met: 8193326Sed * 1. Redistributions of source code must retain the above copyright 9193326Sed * notice, this list of conditions and the following disclaimer. 10193326Sed * 2. Redistributions in binary form must reproduce the above copyright 11193326Sed * notice, this list of conditions and the following disclaimer in the 12193326Sed * documentation and/or other materials provided with the distribution. 13193326Sed * 3. All advertising materials mentioning features or use of this software 14239462Sdim * must display the following acknowledgement: 15249423Sdim * This product includes software developed by Boris Popov. 16193326Sed * 4. Neither the name of the author nor the names of any co-contributors 17195341Sed * may be used to endorse or promote products derived from this software 18193326Sed * without specific prior written permission. 19204643Srdivacky * 20249423Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21193326Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22193326Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23207619Srdivacky * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24193326Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25193326Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26193326Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27193326Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28239462Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29239462Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30239462Sdim * SUCH DAMAGE. 31239462Sdim * 32239462Sdim * $FreeBSD: head/sys/netsmb/smb_iod.c 97209 2002-05-24 05:40:51Z peter $ 33239462Sdim */ 34239462Sdim 35239462Sdim#include <sys/param.h> 36239462Sdim#include <sys/systm.h> 37239462Sdim#include <sys/endian.h> 38239462Sdim#include <sys/proc.h> 39239462Sdim#include <sys/kernel.h> 40239462Sdim#include <sys/kthread.h> 41239462Sdim#include <sys/malloc.h> 42239462Sdim#include <sys/mbuf.h> 43207619Srdivacky#include <sys/unistd.h> 44207619Srdivacky 45207619Srdivacky#include <netsmb/smb.h> 46207619Srdivacky#include <netsmb/smb_conn.h> 47207619Srdivacky#include <netsmb/smb_rq.h> 48207619Srdivacky#include <netsmb/smb_tran.h> 49218893Sdim#include <netsmb/smb_trantcp.h> 50218893Sdim 51218893Sdim 52218893Sdim#define SMBIOD_SLEEP_TIMO 2 53193326Sed#define SMBIOD_PING_TIMO 60 /* seconds */ 54193326Sed 55243830Sdim#define SMB_IOD_EVLOCKPTR(iod) (&((iod)->iod_evlock)) 56243830Sdim#define SMB_IOD_EVLOCK(iod) smb_sl_lock(&((iod)->iod_evlock)) 57243830Sdim#define SMB_IOD_EVUNLOCK(iod) smb_sl_unlock(&((iod)->iod_evlock)) 58243830Sdim 59243830Sdim#define SMB_IOD_RQLOCKPTR(iod) (&((iod)->iod_rqlock)) 60243830Sdim#define SMB_IOD_RQLOCK(iod) smb_sl_lock(&((iod)->iod_rqlock)) 61243830Sdim#define SMB_IOD_RQUNLOCK(iod) smb_sl_unlock(&((iod)->iod_rqlock)) 62243830Sdim 63243830Sdim#define smb_iod_wakeup(iod) wakeup(&(iod)->iod_flags) 64243830Sdim 65243830Sdim 66243830Sdimstatic MALLOC_DEFINE(M_SMBIOD, "SMBIOD", "SMB network io daemon"); 67243830Sdim 68243830Sdimstatic int smb_iod_next; 69243830Sdim 70243830Sdimstatic int smb_iod_sendall(struct smbiod *iod); 71243830Sdimstatic int smb_iod_disconnect(struct smbiod *iod); 72243830Sdimstatic void smb_iod_thread(void *); 73243830Sdim 74243830Sdimstatic __inline void 75210299Sedsmb_iod_rqprocessed(struct smb_rq *rqp, int error) 76249423Sdim{ 77249423Sdim SMBRQ_SLOCK(rqp); 78193326Sed rqp->sr_lerror = error; 79193326Sed rqp->sr_rpgen++; 80193326Sed rqp->sr_state = SMBRQ_NOTIFIED; 81203955Srdivacky wakeup(&rqp->sr_state); 82234353Sdim SMBRQ_SUNLOCK(rqp); 83234353Sdim} 84243830Sdim 85234353Sdimstatic void 86234353Sdimsmb_iod_invrq(struct smbiod *iod) 87234353Sdim{ 88234353Sdim struct smb_rq *rqp; 89243830Sdim 90218893Sdim /* 91218893Sdim * Invalidate all outstanding requests for this connection 92224145Sdim */ 93218893Sdim SMB_IOD_RQLOCK(iod); 94234353Sdim TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) { 95234353Sdim if (rqp->sr_flags & SMBR_INTERNAL) 96243830Sdim SMBRQ_SUNLOCK(rqp); 97234353Sdim rqp->sr_flags |= SMBR_RESTART; 98234353Sdim smb_iod_rqprocessed(rqp, ENOTCONN); 99234353Sdim } 100234353Sdim SMB_IOD_RQUNLOCK(iod); 101243830Sdim} 102193326Sed 103218893Sdimstatic void 104224145Sdimsmb_iod_closetran(struct smbiod *iod) 105224145Sdim{ 106224145Sdim struct smb_vc *vcp = iod->iod_vc; 107218893Sdim struct thread *td = iod->iod_td; 108218893Sdim 109218893Sdim if (vcp->vc_tdata == NULL) 110193326Sed return; 111218893Sdim SMB_TRAN_DISCONNECT(vcp, td); 112218893Sdim SMB_TRAN_DONE(vcp, td); 113234353Sdim vcp->vc_tdata = NULL; 114234353Sdim} 115224145Sdim 116234353Sdimstatic void 117234353Sdimsmb_iod_dead(struct smbiod *iod) 118218893Sdim{ 119218893Sdim iod->iod_state = SMBIOD_ST_DEAD; 120234353Sdim smb_iod_closetran(iod); 121218893Sdim smb_iod_invrq(iod); 122218893Sdim} 123243830Sdim 124234353Sdimstatic int 125224145Sdimsmb_iod_connect(struct smbiod *iod) 126234353Sdim{ 127218893Sdim struct smb_vc *vcp = iod->iod_vc; 128218893Sdim struct thread *td = iod->iod_td; 129234353Sdim int error; 130218893Sdim 131243830Sdim SMBIODEBUG("%d\n", iod->iod_state); 132243830Sdim switch(iod->iod_state) { 133243830Sdim case SMBIOD_ST_VCACTIVE: 134243830Sdim SMBERROR("called for already opened connection\n"); 135243830Sdim return EISCONN; 136243830Sdim case SMBIOD_ST_DEAD: 137243830Sdim return ENOTCONN; /* XXX: last error code ? */ 138243830Sdim default: 139193326Sed break; 140193326Sed } 141208600Srdivacky vcp->vc_genid++; 142234353Sdim error = 0; 143208600Srdivacky itry { 144208600Srdivacky ithrow(SMB_TRAN_CREATE(vcp, td)); 145208600Srdivacky SMBIODEBUG("tcreate\n"); 146234353Sdim if (vcp->vc_laddr) { 147234353Sdim ithrow(SMB_TRAN_BIND(vcp, vcp->vc_laddr, td)); 148208600Srdivacky } 149208600Srdivacky SMBIODEBUG("tbind\n"); 150208600Srdivacky ithrow(SMB_TRAN_CONNECT(vcp, vcp->vc_paddr, td)); 151221345Sdim SMB_TRAN_SETPARAM(vcp, SMBTP_SELECTID, &iod->iod_flags); 152221345Sdim iod->iod_state = SMBIOD_ST_TRANACTIVE; 153221345Sdim SMBIODEBUG("tconnect\n"); 154221345Sdim/* vcp->vc_mid = 0;*/ 155208600Srdivacky ithrow(smb_smb_negotiate(vcp, &iod->iod_scred)); 156193326Sed SMBIODEBUG("snegotiate\n"); 157218893Sdim ithrow(smb_smb_ssnsetup(vcp, &iod->iod_scred)); 158218893Sdim iod->iod_state = SMBIOD_ST_VCACTIVE; 159218893Sdim SMBIODEBUG("completed\n"); 160218893Sdim smb_iod_invrq(iod); 161193326Sed } icatch(error) { 162218893Sdim smb_iod_dead(iod); 163218893Sdim } ifinally { 164218893Sdim } iendtry; 165218893Sdim return error; 166198092Srdivacky} 167198092Srdivacky 168218893Sdimstatic int 169204643Srdivackysmb_iod_disconnect(struct smbiod *iod) 170204643Srdivacky{ 171204643Srdivacky struct smb_vc *vcp = iod->iod_vc; 172208600Srdivacky 173204643Srdivacky SMBIODEBUG("\n"); 174204643Srdivacky if (iod->iod_state == SMBIOD_ST_VCACTIVE) { 175218893Sdim smb_smb_ssnclose(vcp, &iod->iod_scred); 176219077Sdim iod->iod_state = SMBIOD_ST_TRANACTIVE; 177219077Sdim } 178219077Sdim vcp->vc_smbuid = SMB_UID_UNKNOWN; 179219077Sdim smb_iod_closetran(iod); 180218893Sdim iod->iod_state = SMBIOD_ST_NOTCONN; 181249423Sdim return 0; 182249423Sdim} 183218893Sdim 184218893Sdimstatic int 185218893Sdimsmb_iod_treeconnect(struct smbiod *iod, struct smb_share *ssp) 186218893Sdim{ 187218893Sdim int error; 188218893Sdim 189224145Sdim if (iod->iod_state != SMBIOD_ST_VCACTIVE) { 190224145Sdim if (iod->iod_state != SMBIOD_ST_DEAD) 191224145Sdim return ENOTCONN; 192224145Sdim iod->iod_state = SMBIOD_ST_RECONNECT; 193224145Sdim error = smb_iod_connect(iod); 194224145Sdim if (error) 195224145Sdim return error; 196224145Sdim } 197218893Sdim SMBIODEBUG("tree reconnect\n"); 198218893Sdim SMBS_ST_LOCK(ssp); 199219077Sdim ssp->ss_flags |= SMBS_RECONNECTING; 200219077Sdim SMBS_ST_UNLOCK(ssp); 201219077Sdim error = smb_smb_treeconnect(ssp, &iod->iod_scred); 202218893Sdim SMBS_ST_LOCK(ssp); 203218893Sdim ssp->ss_flags &= ~SMBS_RECONNECTING; 204218893Sdim SMBS_ST_UNLOCK(ssp); 205218893Sdim wakeup(&ssp->ss_vcgenid); 206218893Sdim return error; 207218893Sdim} 208219077Sdim 209218893Sdimstatic int 210218893Sdimsmb_iod_sendrq(struct smbiod *iod, struct smb_rq *rqp) 211218893Sdim{ 212204643Srdivacky struct thread *td = iod->iod_td; 213204643Srdivacky struct smb_vc *vcp = iod->iod_vc; 214204643Srdivacky struct smb_share *ssp = rqp->sr_share; 215204643Srdivacky struct mbuf *m; 216204643Srdivacky int error; 217204643Srdivacky 218204643Srdivacky SMBIODEBUG("iod_state = %d\n", iod->iod_state); 219249423Sdim switch (iod->iod_state) { 220204643Srdivacky case SMBIOD_ST_NOTCONN: 221204643Srdivacky smb_iod_rqprocessed(rqp, ENOTCONN); 222208600Srdivacky return 0; 223249423Sdim case SMBIOD_ST_DEAD: 224204643Srdivacky iod->iod_state = SMBIOD_ST_RECONNECT; 225204643Srdivacky return 0; 226199990Srdivacky case SMBIOD_ST_RECONNECT: 227199990Srdivacky return 0; 228218893Sdim default: 229203955Srdivacky break; 230221345Sdim } 231234353Sdim if (rqp->sr_sendcnt == 0) { 232212904Sdim#ifdef movedtoanotherplace 233212904Sdim if (vcp->vc_maxmux != 0 && iod->iod_muxcnt >= vcp->vc_maxmux) 234234353Sdim return 0; 235234353Sdim#endif 236234353Sdim *rqp->sr_rqtid = htoles(ssp ? ssp->ss_tid : SMB_TID_UNKNOWN); 237199990Srdivacky *rqp->sr_rquid = htoles(vcp ? vcp->vc_smbuid : 0); 238234353Sdim mb_fixhdr(&rqp->sr_rq); 239234353Sdim } 240234353Sdim if (rqp->sr_sendcnt++ > 5) { 241234353Sdim rqp->sr_flags |= SMBR_RESTART; 242234353Sdim smb_iod_rqprocessed(rqp, rqp->sr_lerror); 243234353Sdim /* 244234353Sdim * If all attempts to send a request failed, then 245243830Sdim * something is seriously hosed. 246199990Srdivacky */ 247199990Srdivacky return ENOTCONN; 248210299Sed } 249234353Sdim SMBSDEBUG("M:%04x, P:%04x, U:%04x, T:%04x\n", rqp->sr_mid, 0, 0, 0); 250234353Sdim m_dumpm(rqp->sr_rq.mb_top); 251218893Sdim m = m_copym(rqp->sr_rq.mb_top, 0, M_COPYALL, M_TRYWAIT); 252210299Sed error = rqp->sr_lerror = m ? SMB_TRAN_SEND(vcp, m, td) : ENOBUFS; 253234353Sdim if (error == 0) { 254234353Sdim getnanotime(&rqp->sr_timesent); 255210299Sed iod->iod_lastrqsent = rqp->sr_timesent; 256218893Sdim rqp->sr_flags |= SMBR_SENT; 257210299Sed rqp->sr_state = SMBRQ_SENT; 258234353Sdim return 0; 259210299Sed } 260210299Sed /* 261210299Sed * Check for fatal errors 262218893Sdim */ 263221345Sdim if (SMB_TRAN_FATAL(vcp, error)) { 264234353Sdim /* 265212904Sdim * No further attempts should be made 266218893Sdim */ 267208600Srdivacky return ENOTCONN; 268218893Sdim } 269218893Sdim if (smb_rq_intr(rqp)) 270224145Sdim smb_iod_rqprocessed(rqp, EINTR); 271218893Sdim return 0; 272218893Sdim} 273218893Sdim 274224145Sdim/* 275224145Sdim * Process incoming packets 276224145Sdim */ 277224145Sdimstatic int 278218893Sdimsmb_iod_recvall(struct smbiod *iod) 279218893Sdim{ 280221345Sdim struct smb_vc *vcp = iod->iod_vc; 281221345Sdim struct thread *td = iod->iod_td; 282221345Sdim struct smb_rq *rqp; 283234353Sdim struct mbuf *m; 284234353Sdim u_char *hp; 285234353Sdim u_short mid; 286208600Srdivacky int error; 287210299Sed 288208600Srdivacky switch (iod->iod_state) { 289218893Sdim case SMBIOD_ST_NOTCONN: 290218893Sdim case SMBIOD_ST_DEAD: 291218893Sdim case SMBIOD_ST_RECONNECT: 292218893Sdim return 0; 293218893Sdim default: 294218893Sdim break; 295239462Sdim } 296218893Sdim for (;;) { 297218893Sdim m = NULL; 298218893Sdim error = SMB_TRAN_RECV(vcp, &m, td); 299208600Srdivacky if (error == EWOULDBLOCK) 300208600Srdivacky break; 301218893Sdim if (SMB_TRAN_FATAL(vcp, error)) { 302208600Srdivacky smb_iod_dead(iod); 303210299Sed break; 304208600Srdivacky } 305208600Srdivacky if (error) 306218893Sdim break; 307218893Sdim if (m == NULL) { 308218893Sdim SMBERROR("tran return NULL without error\n"); 309218893Sdim error = EPIPE; 310218893Sdim continue; 311224145Sdim } 312218893Sdim m = m_pullup(m, SMB_HDRLEN); 313234353Sdim if (m == NULL) 314234353Sdim continue; /* wait for a good packet */ 315234353Sdim /* 316234353Sdim * Now we got an entire and possibly invalid SMB packet. 317210299Sed * Be careful while parsing it. 318218893Sdim */ 319224145Sdim m_dumpm(m); 320224145Sdim hp = mtod(m, u_char*); 321224145Sdim if (bcmp(hp, SMB_SIGNATURE, SMB_SIGLEN) != 0) { 322224145Sdim m_freem(m); 323224145Sdim continue; 324218893Sdim } 325218893Sdim mid = SMB_HDRMID(hp); 326234353Sdim SMBSDEBUG("mid %04x\n", (u_int)mid); 327234353Sdim SMB_IOD_RQLOCK(iod); 328218893Sdim TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) { 329199990Srdivacky if (rqp->sr_mid != mid) 330218893Sdim continue; 331218893Sdim SMBRQ_SLOCK(rqp); 332218893Sdim if (rqp->sr_rp.md_top == NULL) { 333199990Srdivacky md_initm(&rqp->sr_rp, m); 334218893Sdim } else { 335218893Sdim if (rqp->sr_flags & SMBR_MULTIPACKET) { 336218893Sdim md_append_record(&rqp->sr_rp, m); 337218893Sdim } else { 338218893Sdim SMBRQ_SUNLOCK(rqp); 339218893Sdim SMBERROR("duplicate response %d (ignored)\n", mid); 340218893Sdim break; 341218893Sdim } 342218893Sdim } 343218893Sdim SMBRQ_SUNLOCK(rqp); 344218893Sdim smb_iod_rqprocessed(rqp, 0); 345218893Sdim break; 346218893Sdim } 347199990Srdivacky SMB_IOD_RQUNLOCK(iod); 348199990Srdivacky if (rqp == NULL) { 349207619Srdivacky SMBERROR("drop resp with mid %d\n", (u_int)mid); 350207619Srdivacky/* smb_printrqlist(vcp);*/ 351207619Srdivacky m_freem(m); 352207619Srdivacky } 353207619Srdivacky } 354207619Srdivacky /* 355207619Srdivacky * check for interrupts 356218893Sdim */ 357218893Sdim SMB_IOD_RQLOCK(iod); 358219077Sdim TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) { 359234353Sdim if (smb_proc_intr(rqp->sr_cred->scr_td->td_proc)) { 360218893Sdim smb_iod_rqprocessed(rqp, EINTR); 361218893Sdim } 362218893Sdim } 363218893Sdim SMB_IOD_RQUNLOCK(iod); 364224145Sdim return 0; 365224145Sdim} 366224145Sdim 367218893Sdimint 368219077Sdimsmb_iod_request(struct smbiod *iod, int event, void *ident) 369219077Sdim{ 370219077Sdim struct smbiod_event *evp; 371219077Sdim int error; 372234353Sdim 373218893Sdim SMBIODEBUG("\n"); 374218893Sdim evp = smb_zmalloc(sizeof(*evp), M_SMBIOD, M_WAITOK); 375218893Sdim evp->ev_type = event; 376224145Sdim evp->ev_ident = ident; 377218893Sdim SMB_IOD_EVLOCK(iod); 378218893Sdim STAILQ_INSERT_TAIL(&iod->iod_evlist, evp, ev_link); 379234353Sdim if ((event & SMBIOD_EV_SYNC) == 0) { 380234353Sdim SMB_IOD_EVUNLOCK(iod); 381234353Sdim smb_iod_wakeup(iod); 382234353Sdim return 0; 383218893Sdim } 384234353Sdim smb_iod_wakeup(iod); 385234353Sdim msleep(evp, SMB_IOD_EVLOCKPTR(iod), PWAIT | PDROP, "90evw", 0); 386218893Sdim error = evp->ev_error; 387193326Sed free(evp, M_SMBIOD); 388193326Sed return error; 389199990Srdivacky} 390199990Srdivacky 391219077Sdim/* 392234353Sdim * Place request in the queue. 393212904Sdim * Request from smbiod have a high priority. 394199990Srdivacky */ 395199990Srdivackyint 396218893Sdimsmb_iod_addrq(struct smb_rq *rqp) 397234353Sdim{ 398234353Sdim struct smb_vc *vcp = rqp->sr_vc; 399234353Sdim struct smbiod *iod = vcp->vc_iod; 400199990Srdivacky int error; 401234353Sdim 402234353Sdim SMBIODEBUG("\n"); 403195341Sed if (rqp->sr_cred->scr_td->td_proc == iod->iod_p) { 404195341Sed rqp->sr_flags |= SMBR_INTERNAL; 405210299Sed SMB_IOD_RQLOCK(iod); 406210299Sed TAILQ_INSERT_HEAD(&iod->iod_rqlist, rqp, sr_link); 407234353Sdim SMB_IOD_RQUNLOCK(iod); 408210299Sed for (;;) { 409210299Sed if (smb_iod_sendrq(iod, rqp) != 0) { 410234353Sdim smb_iod_dead(iod); 411234353Sdim break; 412210299Sed } 413234353Sdim /* 414219077Sdim * we don't need to lock state field here 415234353Sdim */ 416218893Sdim if (rqp->sr_state != SMBRQ_NOTSENT) 417234353Sdim break; 418218893Sdim tsleep(&iod->iod_flags, PWAIT, "90sndw", hz); 419210299Sed } 420210299Sed if (rqp->sr_lerror) 421249423Sdim smb_iod_removerq(rqp); 422219077Sdim return rqp->sr_lerror; 423249423Sdim } 424249423Sdim 425249423Sdim switch (iod->iod_state) { 426219077Sdim case SMBIOD_ST_NOTCONN: 427249423Sdim return ENOTCONN; 428249423Sdim case SMBIOD_ST_DEAD: 429249423Sdim error = smb_iod_request(vcp->vc_iod, SMBIOD_EV_CONNECT | SMBIOD_EV_SYNC, NULL); 430249423Sdim if (error) 431218893Sdim return error; 432249423Sdim return EXDEV; 433195341Sed default: 434218893Sdim break; 435218893Sdim } 436218893Sdim 437218893Sdim SMB_IOD_RQLOCK(iod); 438218893Sdim for (;;) { 439218893Sdim if (vcp->vc_maxmux == 0) { 440218893Sdim SMBERROR("maxmux == 0\n"); 441218893Sdim break; 442212904Sdim } 443212904Sdim if (iod->iod_muxcnt < vcp->vc_maxmux) 444193326Sed break; 445193326Sed iod->iod_muxwant++; 446249423Sdim msleep(&iod->iod_muxwant, SMB_IOD_RQLOCKPTR(iod), 447201361Srdivacky PWAIT, "90mux", 0); 448201361Srdivacky } 449239462Sdim iod->iod_muxcnt++; 450193326Sed TAILQ_INSERT_TAIL(&iod->iod_rqlist, rqp, sr_link); 451193326Sed SMB_IOD_RQUNLOCK(iod); 452193326Sed smb_iod_wakeup(iod); 453193326Sed return 0; 454239462Sdim} 455193326Sed 456193326Sedint 457239462Sdimsmb_iod_removerq(struct smb_rq *rqp) 458221345Sdim{ 459221345Sdim struct smb_vc *vcp = rqp->sr_vc; 460193326Sed struct smbiod *iod = vcp->vc_iod; 461239462Sdim 462193326Sed SMBIODEBUG("\n"); 463239462Sdim if (rqp->sr_flags & SMBR_INTERNAL) { 464193326Sed SMB_IOD_RQLOCK(iod); 465239462Sdim TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link); 466193326Sed SMB_IOD_RQUNLOCK(iod); 467239462Sdim return 0; 468193326Sed } 469239462Sdim SMB_IOD_RQLOCK(iod); 470193326Sed while (rqp->sr_flags & SMBR_XLOCK) { 471193326Sed rqp->sr_flags |= SMBR_XLOCKWANT; 472193326Sed msleep(rqp, SMB_IOD_RQLOCKPTR(iod), PWAIT, "90xrm", 0); 473221345Sdim } 474239462Sdim TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link); 475239462Sdim iod->iod_muxcnt--; 476193326Sed if (iod->iod_muxwant) { 477239462Sdim iod->iod_muxwant--; 478239462Sdim wakeup(&iod->iod_muxwant); 479239462Sdim } 480193326Sed SMB_IOD_RQUNLOCK(iod); 481193326Sed return 0; 482193326Sed} 483193326Sed 484193326Sedint 485221345Sdimsmb_iod_waitrq(struct smb_rq *rqp) 486221345Sdim{ 487221345Sdim struct smbiod *iod = rqp->sr_vc->vc_iod; 488221345Sdim int error; 489221345Sdim 490221345Sdim SMBIODEBUG("\n"); 491221345Sdim if (rqp->sr_flags & SMBR_INTERNAL) { 492221345Sdim for (;;) { 493221345Sdim smb_iod_sendall(iod); 494221345Sdim smb_iod_recvall(iod); 495239462Sdim if (rqp->sr_rpgen != rqp->sr_rplast) 496218893Sdim break; 497218893Sdim tsleep(&iod->iod_flags, PWAIT, "90irq", hz); 498218893Sdim } 499218893Sdim smb_iod_removerq(rqp); 500218893Sdim return rqp->sr_lerror; 501218893Sdim 502218893Sdim } 503218893Sdim SMBRQ_SLOCK(rqp); 504218893Sdim if (rqp->sr_rpgen == rqp->sr_rplast) 505218893Sdim msleep(&rqp->sr_state, SMBRQ_SLOCKPTR(rqp), PWAIT, "90wrq", 0); 506199482Srdivacky rqp->sr_rplast++; 507193326Sed SMBRQ_SUNLOCK(rqp); 508193326Sed error = rqp->sr_lerror; 509193326Sed if (rqp->sr_flags & SMBR_MULTIPACKET) { 510193326Sed /* 511193326Sed * If request should stay in the list, then reinsert it 512193326Sed * at the end of queue so other waiters have chance to concur 513193326Sed */ 514193326Sed SMB_IOD_RQLOCK(iod); 515193326Sed TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link); 516193326Sed TAILQ_INSERT_TAIL(&iod->iod_rqlist, rqp, sr_link); 517193326Sed SMB_IOD_RQUNLOCK(iod); 518193326Sed } else 519193326Sed smb_iod_removerq(rqp); 520193326Sed return error; 521193326Sed} 522193326Sed 523193326Sed 524212904Sdimstatic int 525218893Sdimsmb_iod_sendall(struct smbiod *iod) 526212904Sdim{ 527212904Sdim struct smb_vc *vcp = iod->iod_vc; 528212904Sdim struct smb_rq *rqp; 529218893Sdim struct timespec ts, tstimeout; 530249423Sdim int herror; 531249423Sdim 532212904Sdim herror = 0; 533212904Sdim /* 534212904Sdim * Loop through the list of requests and send them if possible 535212904Sdim */ 536218893Sdim SMB_IOD_RQLOCK(iod); 537249423Sdim TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) { 538212904Sdim switch (rqp->sr_state) { 539212904Sdim case SMBRQ_NOTSENT: 540212904Sdim rqp->sr_flags |= SMBR_XLOCK; 541212904Sdim SMB_IOD_RQUNLOCK(iod); 542212904Sdim herror = smb_iod_sendrq(iod, rqp); 543212904Sdim SMB_IOD_RQLOCK(iod); 544212904Sdim rqp->sr_flags &= ~SMBR_XLOCK; 545212904Sdim if (rqp->sr_flags & SMBR_XLOCKWANT) { 546212904Sdim rqp->sr_flags &= ~SMBR_XLOCKWANT; 547212904Sdim wakeup(rqp); 548212904Sdim } 549212904Sdim break; 550218893Sdim case SMBRQ_SENT: 551212904Sdim SMB_TRAN_GETPARAM(vcp, SMBTP_TIMEOUT, &tstimeout); 552212904Sdim timespecadd(&tstimeout, &tstimeout); 553212904Sdim getnanotime(&ts); 554218893Sdim timespecsub(&ts, &tstimeout); 555249423Sdim if (timespeccmp(&ts, &rqp->sr_timesent, >)) { 556249423Sdim smb_iod_rqprocessed(rqp, ETIMEDOUT); 557212904Sdim } 558212904Sdim break; 559212904Sdim default: 560212904Sdim break; 561218893Sdim } 562249423Sdim if (herror) 563212904Sdim break; 564212904Sdim } 565212904Sdim SMB_IOD_RQUNLOCK(iod); 566212904Sdim if (herror == ENOTCONN) 567212904Sdim smb_iod_dead(iod); 568212904Sdim return 0; 569212904Sdim} 570212904Sdim 571212904Sdim/* 572212904Sdim * "main" function for smbiod daemon 573212904Sdim */ 574221345Sdimstatic __inline void 575221345Sdimsmb_iod_main(struct smbiod *iod) 576221345Sdim{ 577221345Sdim/* struct smb_vc *vcp = iod->iod_vc;*/ 578221345Sdim struct smbiod_event *evp; 579221345Sdim/* struct timespec tsnow;*/ 580221345Sdim int error; 581221345Sdim 582221345Sdim SMBIODEBUG("\n"); 583221345Sdim error = 0; 584221345Sdim 585221345Sdim /* 586221345Sdim * Check all interesting events 587221345Sdim */ 588221345Sdim for (;;) { 589221345Sdim SMB_IOD_EVLOCK(iod); 590221345Sdim evp = STAILQ_FIRST(&iod->iod_evlist); 591221345Sdim if (evp == NULL) { 592239462Sdim SMB_IOD_EVUNLOCK(iod); 593239462Sdim break; 594239462Sdim } 595221345Sdim STAILQ_REMOVE_HEAD(&iod->iod_evlist, ev_link); 596221345Sdim evp->ev_type |= SMBIOD_EV_PROCESSING; 597221345Sdim SMB_IOD_EVUNLOCK(iod); 598221345Sdim switch (evp->ev_type & SMBIOD_EV_MASK) { 599221345Sdim case SMBIOD_EV_CONNECT: 600221345Sdim iod->iod_state = SMBIOD_ST_RECONNECT; 601221345Sdim evp->ev_error = smb_iod_connect(iod); 602221345Sdim break; 603221345Sdim case SMBIOD_EV_DISCONNECT: 604221345Sdim evp->ev_error = smb_iod_disconnect(iod); 605221345Sdim break; 606221345Sdim case SMBIOD_EV_TREECONNECT: 607212904Sdim evp->ev_error = smb_iod_treeconnect(iod, evp->ev_ident); 608218893Sdim break; 609218893Sdim case SMBIOD_EV_SHUTDOWN: 610212904Sdim iod->iod_flags |= SMBIOD_SHUTDOWN; 611218893Sdim break; 612249423Sdim case SMBIOD_EV_NEWRQ: 613249423Sdim break; 614212904Sdim } 615212904Sdim if (evp->ev_type & SMBIOD_EV_SYNC) { 616212904Sdim SMB_IOD_EVLOCK(iod); 617212904Sdim wakeup(evp); 618218893Sdim SMB_IOD_EVUNLOCK(iod); 619249423Sdim } else 620212904Sdim free(evp, M_SMBIOD); 621212904Sdim } 622212904Sdim#if 0 623212904Sdim if (iod->iod_state == SMBIOD_ST_VCACTIVE) { 624212904Sdim getnanotime(&tsnow); 625212904Sdim timespecsub(&tsnow, &iod->iod_pingtimo); 626212904Sdim if (timespeccmp(&tsnow, &iod->iod_lastrqsent, >)) { 627212904Sdim smb_smb_echo(vcp, &iod->iod_scred); 628212904Sdim } 629212904Sdim } 630212904Sdim#endif 631218893Sdim smb_iod_sendall(iod); 632218893Sdim smb_iod_recvall(iod); 633212904Sdim return; 634218893Sdim} 635249423Sdim 636249423Sdimvoid 637249423Sdimsmb_iod_thread(void *arg) 638212904Sdim{ 639212904Sdim struct smbiod *iod = arg; 640212904Sdim 641212904Sdim mtx_lock(&Giant); 642212904Sdim /* 643212904Sdim * Here we assume that the thread structure will be the same 644212904Sdim * for an entire kthread (kproc, to be more precise) life. 645218893Sdim */ 646212904Sdim iod->iod_td = curthread; 647212904Sdim smb_makescred(&iod->iod_scred, iod->iod_td, NULL); 648212904Sdim while ((iod->iod_flags & SMBIOD_SHUTDOWN) == 0) { 649212904Sdim smb_iod_main(iod); 650212904Sdim SMBIODEBUG("going to sleep for %d ticks\n", iod->iod_sleeptimo); 651212904Sdim/* mtx_unlock(&Giant, MTX_DEF);*/ 652212904Sdim if (iod->iod_flags & SMBIOD_SHUTDOWN) 653218893Sdim break; 654212904Sdim tsleep(&iod->iod_flags, PWAIT, "90idle", iod->iod_sleeptimo); 655212904Sdim } 656212904Sdim/* mtx_lock(&Giant, MTX_DEF);*/ 657212904Sdim kthread_exit(0); 658212904Sdim} 659212904Sdim 660212904Sdimint 661212904Sdimsmb_iod_create(struct smb_vc *vcp) 662212904Sdim{ 663212904Sdim struct smbiod *iod; 664212904Sdim int error; 665234353Sdim 666234353Sdim iod = smb_zmalloc(sizeof(*iod), M_SMBIOD, M_WAITOK); 667234353Sdim iod->iod_id = smb_iod_next++; 668234353Sdim iod->iod_state = SMBIOD_ST_NOTCONN; 669234353Sdim iod->iod_vc = vcp; 670234353Sdim iod->iod_sleeptimo = hz * SMBIOD_SLEEP_TIMO; 671212904Sdim iod->iod_pingtimo.tv_sec = SMBIOD_PING_TIMO; 672234353Sdim getnanotime(&iod->iod_lastrqsent); 673234353Sdim vcp->vc_iod = iod; 674234353Sdim smb_sl_init(&iod->iod_rqlock, "90rql"); 675234353Sdim TAILQ_INIT(&iod->iod_rqlist); 676234353Sdim smb_sl_init(&iod->iod_evlock, "90evl"); 677234353Sdim STAILQ_INIT(&iod->iod_evlist); 678234353Sdim error = kthread_create(smb_iod_thread, iod, &iod->iod_p, 679234353Sdim RFNOWAIT, "smbiod%d", iod->iod_id); 680234353Sdim if (error) { 681234353Sdim SMBERROR("can't start smbiod: %d", error); 682234353Sdim free(iod, M_SMBIOD); 683234353Sdim return error; 684234353Sdim } 685234353Sdim return 0; 686234353Sdim} 687234353Sdim 688234353Sdimint 689234353Sdimsmb_iod_destroy(struct smbiod *iod) 690234353Sdim{ 691234353Sdim smb_iod_request(iod, SMBIOD_EV_SHUTDOWN | SMBIOD_EV_SYNC, NULL); 692234353Sdim smb_sl_destroy(&iod->iod_rqlock); 693234353Sdim smb_sl_destroy(&iod->iod_evlock); 694234353Sdim free(iod, M_SMBIOD); 695234353Sdim return 0; 696234353Sdim} 697234353Sdim 698234353Sdimint 699201361Srdivackysmb_iod_init(void) 700201361Srdivacky{ 701201361Srdivacky return 0; 702201361Srdivacky} 703201361Srdivacky 704201361Srdivackyint 705201361Srdivackysmb_iod_done(void) 706201361Srdivacky{ 707198092Srdivacky return 0; 708193326Sed} 709193326Sed 710193326Sed