1681a5bbeSBoris Popov /* 2681a5bbeSBoris Popov * Copyright (c) 2000-2001 Boris Popov 3681a5bbeSBoris Popov * All rights reserved. 4681a5bbeSBoris Popov * 5681a5bbeSBoris Popov * Redistribution and use in source and binary forms, with or without 6681a5bbeSBoris Popov * modification, are permitted provided that the following conditions 7681a5bbeSBoris Popov * are met: 8681a5bbeSBoris Popov * 1. Redistributions of source code must retain the above copyright 9681a5bbeSBoris Popov * notice, this list of conditions and the following disclaimer. 10681a5bbeSBoris Popov * 2. Redistributions in binary form must reproduce the above copyright 11681a5bbeSBoris Popov * notice, this list of conditions and the following disclaimer in the 12681a5bbeSBoris Popov * documentation and/or other materials provided with the distribution. 13681a5bbeSBoris Popov * 3. All advertising materials mentioning features or use of this software 14681a5bbeSBoris Popov * must display the following acknowledgement: 15681a5bbeSBoris Popov * This product includes software developed by Boris Popov. 16681a5bbeSBoris Popov * 4. Neither the name of the author nor the names of any co-contributors 17681a5bbeSBoris Popov * may be used to endorse or promote products derived from this software 18681a5bbeSBoris Popov * without specific prior written permission. 19681a5bbeSBoris Popov * 20681a5bbeSBoris Popov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21681a5bbeSBoris Popov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22681a5bbeSBoris Popov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23681a5bbeSBoris Popov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24681a5bbeSBoris Popov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25681a5bbeSBoris Popov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26681a5bbeSBoris Popov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27681a5bbeSBoris Popov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28681a5bbeSBoris Popov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29681a5bbeSBoris Popov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30681a5bbeSBoris Popov * SUCH DAMAGE. 31681a5bbeSBoris Popov * 32681a5bbeSBoris Popov * $FreeBSD$ 33681a5bbeSBoris Popov */ 34681a5bbeSBoris Popov 35681a5bbeSBoris Popov #include <sys/param.h> 36681a5bbeSBoris Popov #include <sys/systm.h> 37681a5bbeSBoris Popov #include <sys/proc.h> 38681a5bbeSBoris Popov #include <sys/kernel.h> 39681a5bbeSBoris Popov #include <sys/kthread.h> 40681a5bbeSBoris Popov #include <sys/malloc.h> 41681a5bbeSBoris Popov #include <sys/mbuf.h> 42681a5bbeSBoris Popov #include <sys/unistd.h> 43681a5bbeSBoris Popov 44681a5bbeSBoris Popov #include <netsmb/smb.h> 45681a5bbeSBoris Popov #include <netsmb/smb_conn.h> 46681a5bbeSBoris Popov #include <netsmb/smb_rq.h> 47681a5bbeSBoris Popov #include <netsmb/smb_tran.h> 48681a5bbeSBoris Popov #include <netsmb/smb_trantcp.h> 49681a5bbeSBoris Popov 50681a5bbeSBoris Popov 51681a5bbeSBoris Popov #define SMBIOD_SLEEP_TIMO 2 52681a5bbeSBoris Popov #define SMBIOD_PING_TIMO 60 /* seconds */ 53681a5bbeSBoris Popov 54681a5bbeSBoris Popov #define SMB_IOD_EVLOCKPTR(iod) (&((iod)->iod_evlock)) 55681a5bbeSBoris Popov #define SMB_IOD_EVLOCK(iod) smb_sl_lock(&((iod)->iod_evlock)) 56681a5bbeSBoris Popov #define SMB_IOD_EVUNLOCK(iod) smb_sl_unlock(&((iod)->iod_evlock)) 57681a5bbeSBoris Popov 58681a5bbeSBoris Popov #define SMB_IOD_RQLOCKPTR(iod) (&((iod)->iod_rqlock)) 59681a5bbeSBoris Popov #define SMB_IOD_RQLOCK(iod) smb_sl_lock(&((iod)->iod_rqlock)) 60681a5bbeSBoris Popov #define SMB_IOD_RQUNLOCK(iod) smb_sl_unlock(&((iod)->iod_rqlock)) 61681a5bbeSBoris Popov 62681a5bbeSBoris Popov #define smb_iod_wakeup(iod) wakeup(&(iod)->iod_flags) 63681a5bbeSBoris Popov 64681a5bbeSBoris Popov 65681a5bbeSBoris Popov static MALLOC_DEFINE(M_SMBIOD, "SMBIOD", "SMB network io daemon"); 66681a5bbeSBoris Popov 67681a5bbeSBoris Popov static int smb_iod_next; 68681a5bbeSBoris Popov 69681a5bbeSBoris Popov static int smb_iod_sendall(struct smbiod *iod); 70681a5bbeSBoris Popov static int smb_iod_disconnect(struct smbiod *iod); 71681a5bbeSBoris Popov static void smb_iod_thread(void *); 72681a5bbeSBoris Popov 73681a5bbeSBoris Popov static __inline void 74681a5bbeSBoris Popov smb_iod_rqprocessed(struct smb_rq *rqp, int error) 75681a5bbeSBoris Popov { 76681a5bbeSBoris Popov SMBRQ_SLOCK(rqp); 77681a5bbeSBoris Popov rqp->sr_lerror = error; 78681a5bbeSBoris Popov rqp->sr_rpgen++; 79681a5bbeSBoris Popov rqp->sr_state = SMBRQ_NOTIFIED; 80681a5bbeSBoris Popov wakeup(&rqp->sr_state); 81681a5bbeSBoris Popov SMBRQ_SUNLOCK(rqp); 82681a5bbeSBoris Popov } 83681a5bbeSBoris Popov 84681a5bbeSBoris Popov static void 85681a5bbeSBoris Popov smb_iod_invrq(struct smbiod *iod) 86681a5bbeSBoris Popov { 87681a5bbeSBoris Popov struct smb_rq *rqp; 88681a5bbeSBoris Popov 89681a5bbeSBoris Popov /* 90681a5bbeSBoris Popov * Invalidate all outstanding requests for this connection 91681a5bbeSBoris Popov */ 92681a5bbeSBoris Popov SMB_IOD_RQLOCK(iod); 93681a5bbeSBoris Popov TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) { 94681a5bbeSBoris Popov if (rqp->sr_flags & SMBR_INTERNAL) 95681a5bbeSBoris Popov SMBRQ_SUNLOCK(rqp); 96681a5bbeSBoris Popov rqp->sr_flags |= SMBR_RESTART; 97681a5bbeSBoris Popov smb_iod_rqprocessed(rqp, ENOTCONN); 98681a5bbeSBoris Popov } 99681a5bbeSBoris Popov SMB_IOD_RQUNLOCK(iod); 100681a5bbeSBoris Popov } 101681a5bbeSBoris Popov 102681a5bbeSBoris Popov static void 103681a5bbeSBoris Popov smb_iod_closetran(struct smbiod *iod) 104681a5bbeSBoris Popov { 105681a5bbeSBoris Popov struct smb_vc *vcp = iod->iod_vc; 106fce6fbfaSBoris Popov struct thread *td = iod->iod_td; 107681a5bbeSBoris Popov 108681a5bbeSBoris Popov if (vcp->vc_tdata == NULL) 109681a5bbeSBoris Popov return; 110fce6fbfaSBoris Popov SMB_TRAN_DISCONNECT(vcp, td); 111fce6fbfaSBoris Popov SMB_TRAN_DONE(vcp, td); 112681a5bbeSBoris Popov vcp->vc_tdata = NULL; 113681a5bbeSBoris Popov } 114681a5bbeSBoris Popov 115681a5bbeSBoris Popov static void 116681a5bbeSBoris Popov smb_iod_dead(struct smbiod *iod) 117681a5bbeSBoris Popov { 118681a5bbeSBoris Popov iod->iod_state = SMBIOD_ST_DEAD; 119681a5bbeSBoris Popov smb_iod_closetran(iod); 120681a5bbeSBoris Popov smb_iod_invrq(iod); 121681a5bbeSBoris Popov } 122681a5bbeSBoris Popov 123681a5bbeSBoris Popov static int 124681a5bbeSBoris Popov smb_iod_connect(struct smbiod *iod) 125681a5bbeSBoris Popov { 126681a5bbeSBoris Popov struct smb_vc *vcp = iod->iod_vc; 127fce6fbfaSBoris Popov struct thread *td = iod->iod_td; 128681a5bbeSBoris Popov int error; 129681a5bbeSBoris Popov 130681a5bbeSBoris Popov SMBIODEBUG("%d\n", iod->iod_state); 131681a5bbeSBoris Popov switch(iod->iod_state) { 132681a5bbeSBoris Popov case SMBIOD_ST_VCACTIVE: 133681a5bbeSBoris Popov SMBERROR("called for already opened connection\n"); 134681a5bbeSBoris Popov return EISCONN; 135681a5bbeSBoris Popov case SMBIOD_ST_DEAD: 136681a5bbeSBoris Popov return ENOTCONN; /* XXX: last error code ? */ 137681a5bbeSBoris Popov default: 138681a5bbeSBoris Popov break; 139681a5bbeSBoris Popov } 140681a5bbeSBoris Popov vcp->vc_genid++; 141681a5bbeSBoris Popov error = 0; 142681a5bbeSBoris Popov itry { 143fce6fbfaSBoris Popov ithrow(SMB_TRAN_CREATE(vcp, td)); 144681a5bbeSBoris Popov SMBIODEBUG("tcreate\n"); 145681a5bbeSBoris Popov if (vcp->vc_laddr) { 146fce6fbfaSBoris Popov ithrow(SMB_TRAN_BIND(vcp, vcp->vc_laddr, td)); 147681a5bbeSBoris Popov } 148681a5bbeSBoris Popov SMBIODEBUG("tbind\n"); 149fce6fbfaSBoris Popov ithrow(SMB_TRAN_CONNECT(vcp, vcp->vc_paddr, td)); 150681a5bbeSBoris Popov SMB_TRAN_SETPARAM(vcp, SMBTP_SELECTID, &iod->iod_flags); 151681a5bbeSBoris Popov iod->iod_state = SMBIOD_ST_TRANACTIVE; 152681a5bbeSBoris Popov SMBIODEBUG("tconnect\n"); 153681a5bbeSBoris Popov /* vcp->vc_mid = 0;*/ 154681a5bbeSBoris Popov ithrow(smb_smb_negotiate(vcp, &iod->iod_scred)); 155681a5bbeSBoris Popov SMBIODEBUG("snegotiate\n"); 156681a5bbeSBoris Popov ithrow(smb_smb_ssnsetup(vcp, &iod->iod_scred)); 157681a5bbeSBoris Popov iod->iod_state = SMBIOD_ST_VCACTIVE; 158681a5bbeSBoris Popov SMBIODEBUG("completed\n"); 159681a5bbeSBoris Popov smb_iod_invrq(iod); 160681a5bbeSBoris Popov } icatch(error) { 161681a5bbeSBoris Popov smb_iod_dead(iod); 162681a5bbeSBoris Popov } ifinally { 163681a5bbeSBoris Popov } iendtry; 164681a5bbeSBoris Popov return error; 165681a5bbeSBoris Popov } 166681a5bbeSBoris Popov 167681a5bbeSBoris Popov static int 168681a5bbeSBoris Popov smb_iod_disconnect(struct smbiod *iod) 169681a5bbeSBoris Popov { 170681a5bbeSBoris Popov struct smb_vc *vcp = iod->iod_vc; 171681a5bbeSBoris Popov 172681a5bbeSBoris Popov SMBIODEBUG("\n"); 173681a5bbeSBoris Popov if (iod->iod_state == SMBIOD_ST_VCACTIVE) { 174681a5bbeSBoris Popov smb_smb_ssnclose(vcp, &iod->iod_scred); 175681a5bbeSBoris Popov iod->iod_state = SMBIOD_ST_TRANACTIVE; 176681a5bbeSBoris Popov } 177681a5bbeSBoris Popov vcp->vc_smbuid = SMB_UID_UNKNOWN; 178681a5bbeSBoris Popov smb_iod_closetran(iod); 179681a5bbeSBoris Popov iod->iod_state = SMBIOD_ST_NOTCONN; 180681a5bbeSBoris Popov return 0; 181681a5bbeSBoris Popov } 182681a5bbeSBoris Popov 183681a5bbeSBoris Popov static int 184681a5bbeSBoris Popov smb_iod_treeconnect(struct smbiod *iod, struct smb_share *ssp) 185681a5bbeSBoris Popov { 186681a5bbeSBoris Popov int error; 187681a5bbeSBoris Popov 188681a5bbeSBoris Popov if (iod->iod_state != SMBIOD_ST_VCACTIVE) { 189681a5bbeSBoris Popov if (iod->iod_state != SMBIOD_ST_DEAD) 190681a5bbeSBoris Popov return ENOTCONN; 191681a5bbeSBoris Popov iod->iod_state = SMBIOD_ST_RECONNECT; 192681a5bbeSBoris Popov error = smb_iod_connect(iod); 193681a5bbeSBoris Popov if (error) 194681a5bbeSBoris Popov return error; 195681a5bbeSBoris Popov } 196681a5bbeSBoris Popov SMBIODEBUG("tree reconnect\n"); 197681a5bbeSBoris Popov SMBS_ST_LOCK(ssp); 198681a5bbeSBoris Popov ssp->ss_flags |= SMBS_RECONNECTING; 199681a5bbeSBoris Popov SMBS_ST_UNLOCK(ssp); 200681a5bbeSBoris Popov error = smb_smb_treeconnect(ssp, &iod->iod_scred); 201681a5bbeSBoris Popov SMBS_ST_LOCK(ssp); 202681a5bbeSBoris Popov ssp->ss_flags &= ~SMBS_RECONNECTING; 203681a5bbeSBoris Popov SMBS_ST_UNLOCK(ssp); 204681a5bbeSBoris Popov wakeup(&ssp->ss_vcgenid); 205681a5bbeSBoris Popov return error; 206681a5bbeSBoris Popov } 207681a5bbeSBoris Popov 208681a5bbeSBoris Popov static int 209681a5bbeSBoris Popov smb_iod_sendrq(struct smbiod *iod, struct smb_rq *rqp) 210681a5bbeSBoris Popov { 211fce6fbfaSBoris Popov struct thread *td = iod->iod_td; 212681a5bbeSBoris Popov struct smb_vc *vcp = iod->iod_vc; 213681a5bbeSBoris Popov struct smb_share *ssp = rqp->sr_share; 214681a5bbeSBoris Popov struct mbuf *m; 215681a5bbeSBoris Popov int error; 216681a5bbeSBoris Popov 217681a5bbeSBoris Popov SMBIODEBUG("iod_state = %d\n", iod->iod_state); 218681a5bbeSBoris Popov switch (iod->iod_state) { 219681a5bbeSBoris Popov case SMBIOD_ST_NOTCONN: 220681a5bbeSBoris Popov smb_iod_rqprocessed(rqp, ENOTCONN); 221681a5bbeSBoris Popov return 0; 222681a5bbeSBoris Popov case SMBIOD_ST_DEAD: 223681a5bbeSBoris Popov iod->iod_state = SMBIOD_ST_RECONNECT; 224681a5bbeSBoris Popov return 0; 225681a5bbeSBoris Popov case SMBIOD_ST_RECONNECT: 226681a5bbeSBoris Popov return 0; 227681a5bbeSBoris Popov default: 228681a5bbeSBoris Popov break; 229681a5bbeSBoris Popov } 230681a5bbeSBoris Popov if (rqp->sr_sendcnt == 0) { 231681a5bbeSBoris Popov #ifdef movedtoanotherplace 232681a5bbeSBoris Popov if (vcp->vc_maxmux != 0 && iod->iod_muxcnt >= vcp->vc_maxmux) 233681a5bbeSBoris Popov return 0; 234681a5bbeSBoris Popov #endif 235681a5bbeSBoris Popov *rqp->sr_rqtid = htoles(ssp ? ssp->ss_tid : SMB_TID_UNKNOWN); 236681a5bbeSBoris Popov *rqp->sr_rquid = htoles(vcp ? vcp->vc_smbuid : 0); 237681a5bbeSBoris Popov mb_fixhdr(&rqp->sr_rq); 238681a5bbeSBoris Popov } 239681a5bbeSBoris Popov if (rqp->sr_sendcnt++ > 5) { 240681a5bbeSBoris Popov rqp->sr_flags |= SMBR_RESTART; 241681a5bbeSBoris Popov smb_iod_rqprocessed(rqp, rqp->sr_lerror); 242681a5bbeSBoris Popov /* 243681a5bbeSBoris Popov * If all attempts to send a request failed, then 244681a5bbeSBoris Popov * something is seriously hosed. 245681a5bbeSBoris Popov */ 246681a5bbeSBoris Popov return ENOTCONN; 247681a5bbeSBoris Popov } 248681a5bbeSBoris Popov SMBSDEBUG("M:%04x, P:%04x, U:%04x, T:%04x\n", rqp->sr_mid, 0, 0, 0); 249681a5bbeSBoris Popov m_dumpm(rqp->sr_rq.mb_top); 250681a5bbeSBoris Popov m = m_copym(rqp->sr_rq.mb_top, 0, M_COPYALL, M_WAIT); 251fce6fbfaSBoris Popov error = rqp->sr_lerror = m ? SMB_TRAN_SEND(vcp, m, td) : ENOBUFS; 252681a5bbeSBoris Popov if (error == 0) { 253681a5bbeSBoris Popov getnanotime(&rqp->sr_timesent); 254681a5bbeSBoris Popov iod->iod_lastrqsent = rqp->sr_timesent; 255681a5bbeSBoris Popov rqp->sr_flags |= SMBR_SENT; 256681a5bbeSBoris Popov rqp->sr_state = SMBRQ_SENT; 257681a5bbeSBoris Popov return 0; 258681a5bbeSBoris Popov } 259681a5bbeSBoris Popov /* 260681a5bbeSBoris Popov * Check for fatal errors 261681a5bbeSBoris Popov */ 262681a5bbeSBoris Popov if (SMB_TRAN_FATAL(vcp, error)) { 263681a5bbeSBoris Popov /* 264681a5bbeSBoris Popov * No further attempts should be made 265681a5bbeSBoris Popov */ 266681a5bbeSBoris Popov return ENOTCONN; 267681a5bbeSBoris Popov } 268681a5bbeSBoris Popov if (smb_rq_intr(rqp)) 269681a5bbeSBoris Popov smb_iod_rqprocessed(rqp, EINTR); 270681a5bbeSBoris Popov return 0; 271681a5bbeSBoris Popov } 272681a5bbeSBoris Popov 273681a5bbeSBoris Popov /* 274681a5bbeSBoris Popov * Process incoming packets 275681a5bbeSBoris Popov */ 276681a5bbeSBoris Popov static int 277681a5bbeSBoris Popov smb_iod_recvall(struct smbiod *iod) 278681a5bbeSBoris Popov { 279681a5bbeSBoris Popov struct smb_vc *vcp = iod->iod_vc; 280fce6fbfaSBoris Popov struct thread *td = iod->iod_td; 281681a5bbeSBoris Popov struct smb_rq *rqp; 282681a5bbeSBoris Popov struct mbuf *m; 283681a5bbeSBoris Popov u_char *hp; 284681a5bbeSBoris Popov u_short mid; 285681a5bbeSBoris Popov int error; 286681a5bbeSBoris Popov 287681a5bbeSBoris Popov switch (iod->iod_state) { 288681a5bbeSBoris Popov case SMBIOD_ST_NOTCONN: 289681a5bbeSBoris Popov case SMBIOD_ST_DEAD: 290681a5bbeSBoris Popov case SMBIOD_ST_RECONNECT: 291681a5bbeSBoris Popov return 0; 292681a5bbeSBoris Popov default: 293681a5bbeSBoris Popov break; 294681a5bbeSBoris Popov } 295681a5bbeSBoris Popov for (;;) { 296681a5bbeSBoris Popov m = NULL; 297fce6fbfaSBoris Popov error = SMB_TRAN_RECV(vcp, &m, td); 298681a5bbeSBoris Popov if (error == EWOULDBLOCK) 299681a5bbeSBoris Popov break; 300681a5bbeSBoris Popov if (SMB_TRAN_FATAL(vcp, error)) { 301681a5bbeSBoris Popov smb_iod_dead(iod); 302681a5bbeSBoris Popov break; 303681a5bbeSBoris Popov } 304681a5bbeSBoris Popov if (error) 305681a5bbeSBoris Popov break; 306681a5bbeSBoris Popov if (m == NULL) { 307681a5bbeSBoris Popov SMBERROR("tran return NULL without error\n"); 308681a5bbeSBoris Popov error = EPIPE; 309681a5bbeSBoris Popov continue; 310681a5bbeSBoris Popov } 311681a5bbeSBoris Popov m = m_pullup(m, SMB_HDRLEN); 312681a5bbeSBoris Popov if (m == NULL) 313681a5bbeSBoris Popov continue; /* wait for a good packet */ 314681a5bbeSBoris Popov /* 315681a5bbeSBoris Popov * Now we got an entire and possibly invalid SMB packet. 316681a5bbeSBoris Popov * Be careful while parsing it. 317681a5bbeSBoris Popov */ 318681a5bbeSBoris Popov m_dumpm(m); 319681a5bbeSBoris Popov hp = mtod(m, u_char*); 320681a5bbeSBoris Popov if (bcmp(hp, SMB_SIGNATURE, SMB_SIGLEN) != 0) { 321681a5bbeSBoris Popov m_freem(m); 322681a5bbeSBoris Popov continue; 323681a5bbeSBoris Popov } 324681a5bbeSBoris Popov mid = SMB_HDRMID(hp); 325681a5bbeSBoris Popov SMBSDEBUG("mid %04x\n", (u_int)mid); 326681a5bbeSBoris Popov SMB_IOD_RQLOCK(iod); 327681a5bbeSBoris Popov TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) { 328681a5bbeSBoris Popov if (rqp->sr_mid != mid) 329681a5bbeSBoris Popov continue; 330681a5bbeSBoris Popov SMBRQ_SLOCK(rqp); 331681a5bbeSBoris Popov if (rqp->sr_rp.md_top == NULL) { 332681a5bbeSBoris Popov md_initm(&rqp->sr_rp, m); 333681a5bbeSBoris Popov } else { 334681a5bbeSBoris Popov if (rqp->sr_flags & SMBR_MULTIPACKET) { 335681a5bbeSBoris Popov md_append_record(&rqp->sr_rp, m); 336681a5bbeSBoris Popov } else { 337681a5bbeSBoris Popov SMBRQ_SUNLOCK(rqp); 338681a5bbeSBoris Popov SMBERROR("duplicate response %d (ignored)\n", mid); 339681a5bbeSBoris Popov break; 340681a5bbeSBoris Popov } 341681a5bbeSBoris Popov } 342681a5bbeSBoris Popov SMBRQ_SUNLOCK(rqp); 343681a5bbeSBoris Popov smb_iod_rqprocessed(rqp, 0); 344681a5bbeSBoris Popov break; 345681a5bbeSBoris Popov } 346681a5bbeSBoris Popov SMB_IOD_RQUNLOCK(iod); 347681a5bbeSBoris Popov if (rqp == NULL) { 348681a5bbeSBoris Popov SMBERROR("drop resp with mid %d\n", (u_int)mid); 349681a5bbeSBoris Popov /* smb_printrqlist(vcp);*/ 350681a5bbeSBoris Popov m_freem(m); 351681a5bbeSBoris Popov } 352681a5bbeSBoris Popov } 353681a5bbeSBoris Popov /* 354681a5bbeSBoris Popov * check for interrupts 355681a5bbeSBoris Popov */ 356681a5bbeSBoris Popov SMB_IOD_RQLOCK(iod); 357681a5bbeSBoris Popov TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) { 358fce6fbfaSBoris Popov if (smb_proc_intr(rqp->sr_cred->scr_td->td_proc)) { 359681a5bbeSBoris Popov smb_iod_rqprocessed(rqp, EINTR); 360681a5bbeSBoris Popov } 361681a5bbeSBoris Popov } 362681a5bbeSBoris Popov SMB_IOD_RQUNLOCK(iod); 363681a5bbeSBoris Popov return 0; 364681a5bbeSBoris Popov } 365681a5bbeSBoris Popov 366681a5bbeSBoris Popov int 367681a5bbeSBoris Popov smb_iod_request(struct smbiod *iod, int event, void *ident) 368681a5bbeSBoris Popov { 369681a5bbeSBoris Popov struct smbiod_event *evp; 370681a5bbeSBoris Popov int error; 371681a5bbeSBoris Popov 372681a5bbeSBoris Popov SMBIODEBUG("\n"); 373681a5bbeSBoris Popov evp = smb_zmalloc(sizeof(*evp), M_SMBIOD, M_WAITOK); 374681a5bbeSBoris Popov evp->ev_type = event; 375681a5bbeSBoris Popov evp->ev_ident = ident; 376681a5bbeSBoris Popov SMB_IOD_EVLOCK(iod); 377681a5bbeSBoris Popov STAILQ_INSERT_TAIL(&iod->iod_evlist, evp, ev_link); 378681a5bbeSBoris Popov if ((event & SMBIOD_EV_SYNC) == 0) { 379681a5bbeSBoris Popov SMB_IOD_EVUNLOCK(iod); 380681a5bbeSBoris Popov smb_iod_wakeup(iod); 381681a5bbeSBoris Popov return 0; 382681a5bbeSBoris Popov } 383681a5bbeSBoris Popov smb_iod_wakeup(iod); 384681a5bbeSBoris Popov msleep(evp, SMB_IOD_EVLOCKPTR(iod), PWAIT | PDROP, "90evw", 0); 385681a5bbeSBoris Popov error = evp->ev_error; 386681a5bbeSBoris Popov free(evp, M_SMBIOD); 387681a5bbeSBoris Popov return error; 388681a5bbeSBoris Popov } 389681a5bbeSBoris Popov 390681a5bbeSBoris Popov /* 391681a5bbeSBoris Popov * Place request in the queue. 392681a5bbeSBoris Popov * Request from smbiod have a high priority. 393681a5bbeSBoris Popov */ 394681a5bbeSBoris Popov int 395681a5bbeSBoris Popov smb_iod_addrq(struct smb_rq *rqp) 396681a5bbeSBoris Popov { 397681a5bbeSBoris Popov struct smb_vc *vcp = rqp->sr_vc; 398681a5bbeSBoris Popov struct smbiod *iod = vcp->vc_iod; 399681a5bbeSBoris Popov int error; 400681a5bbeSBoris Popov 401681a5bbeSBoris Popov SMBIODEBUG("\n"); 402fce6fbfaSBoris Popov if (rqp->sr_cred->scr_td->td_proc == iod->iod_p) { 403681a5bbeSBoris Popov rqp->sr_flags |= SMBR_INTERNAL; 404681a5bbeSBoris Popov SMB_IOD_RQLOCK(iod); 405681a5bbeSBoris Popov TAILQ_INSERT_HEAD(&iod->iod_rqlist, rqp, sr_link); 406681a5bbeSBoris Popov SMB_IOD_RQUNLOCK(iod); 407681a5bbeSBoris Popov for (;;) { 408681a5bbeSBoris Popov if (smb_iod_sendrq(iod, rqp) != 0) { 409681a5bbeSBoris Popov smb_iod_dead(iod); 410681a5bbeSBoris Popov break; 411681a5bbeSBoris Popov } 412681a5bbeSBoris Popov /* 413681a5bbeSBoris Popov * we don't need to lock state field here 414681a5bbeSBoris Popov */ 415681a5bbeSBoris Popov if (rqp->sr_state != SMBRQ_NOTSENT) 416681a5bbeSBoris Popov break; 417681a5bbeSBoris Popov tsleep(&iod->iod_flags, PWAIT, "90sndw", hz); 418681a5bbeSBoris Popov } 419681a5bbeSBoris Popov if (rqp->sr_lerror) 420681a5bbeSBoris Popov smb_iod_removerq(rqp); 421681a5bbeSBoris Popov return rqp->sr_lerror; 422681a5bbeSBoris Popov } 423681a5bbeSBoris Popov 424681a5bbeSBoris Popov switch (iod->iod_state) { 425681a5bbeSBoris Popov case SMBIOD_ST_NOTCONN: 426681a5bbeSBoris Popov return ENOTCONN; 427681a5bbeSBoris Popov case SMBIOD_ST_DEAD: 428681a5bbeSBoris Popov error = smb_iod_request(vcp->vc_iod, SMBIOD_EV_CONNECT | SMBIOD_EV_SYNC, NULL); 429681a5bbeSBoris Popov if (error) 430681a5bbeSBoris Popov return error; 431681a5bbeSBoris Popov return EXDEV; 432681a5bbeSBoris Popov default: 433681a5bbeSBoris Popov break; 434681a5bbeSBoris Popov } 435681a5bbeSBoris Popov 436681a5bbeSBoris Popov SMB_IOD_RQLOCK(iod); 437681a5bbeSBoris Popov for (;;) { 438681a5bbeSBoris Popov if (vcp->vc_maxmux == 0) { 439681a5bbeSBoris Popov SMBERROR("maxmux == 0\n"); 440681a5bbeSBoris Popov break; 441681a5bbeSBoris Popov } 442681a5bbeSBoris Popov if (iod->iod_muxcnt < vcp->vc_maxmux) 443681a5bbeSBoris Popov break; 444681a5bbeSBoris Popov iod->iod_muxwant++; 445681a5bbeSBoris Popov msleep(&iod->iod_muxwant, SMB_IOD_RQLOCKPTR(iod), 446681a5bbeSBoris Popov PWAIT, "90mux", 0); 447681a5bbeSBoris Popov } 448681a5bbeSBoris Popov iod->iod_muxcnt++; 449681a5bbeSBoris Popov TAILQ_INSERT_TAIL(&iod->iod_rqlist, rqp, sr_link); 450681a5bbeSBoris Popov SMB_IOD_RQUNLOCK(iod); 451681a5bbeSBoris Popov smb_iod_wakeup(iod); 452681a5bbeSBoris Popov return 0; 453681a5bbeSBoris Popov } 454681a5bbeSBoris Popov 455681a5bbeSBoris Popov int 456681a5bbeSBoris Popov smb_iod_removerq(struct smb_rq *rqp) 457681a5bbeSBoris Popov { 458681a5bbeSBoris Popov struct smb_vc *vcp = rqp->sr_vc; 459681a5bbeSBoris Popov struct smbiod *iod = vcp->vc_iod; 460681a5bbeSBoris Popov 461681a5bbeSBoris Popov SMBIODEBUG("\n"); 462681a5bbeSBoris Popov if (rqp->sr_flags & SMBR_INTERNAL) { 463681a5bbeSBoris Popov SMB_IOD_RQLOCK(iod); 464681a5bbeSBoris Popov TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link); 465681a5bbeSBoris Popov SMB_IOD_RQUNLOCK(iod); 466681a5bbeSBoris Popov return 0; 467681a5bbeSBoris Popov } 468681a5bbeSBoris Popov SMB_IOD_RQLOCK(iod); 469681a5bbeSBoris Popov while (rqp->sr_flags & SMBR_XLOCK) { 470681a5bbeSBoris Popov rqp->sr_flags |= SMBR_XLOCKWANT; 471681a5bbeSBoris Popov msleep(rqp, SMB_IOD_RQLOCKPTR(iod), PWAIT, "90xrm", 0); 472681a5bbeSBoris Popov } 473681a5bbeSBoris Popov TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link); 474681a5bbeSBoris Popov iod->iod_muxcnt--; 475681a5bbeSBoris Popov if (iod->iod_muxwant) { 476681a5bbeSBoris Popov iod->iod_muxwant--; 477681a5bbeSBoris Popov wakeup(&iod->iod_muxwant); 478681a5bbeSBoris Popov } 479681a5bbeSBoris Popov SMB_IOD_RQUNLOCK(iod); 480681a5bbeSBoris Popov return 0; 481681a5bbeSBoris Popov } 482681a5bbeSBoris Popov 483681a5bbeSBoris Popov int 484681a5bbeSBoris Popov smb_iod_waitrq(struct smb_rq *rqp) 485681a5bbeSBoris Popov { 486681a5bbeSBoris Popov struct smbiod *iod = rqp->sr_vc->vc_iod; 487681a5bbeSBoris Popov int error; 488681a5bbeSBoris Popov 489681a5bbeSBoris Popov SMBIODEBUG("\n"); 490681a5bbeSBoris Popov if (rqp->sr_flags & SMBR_INTERNAL) { 491681a5bbeSBoris Popov for (;;) { 492681a5bbeSBoris Popov smb_iod_sendall(iod); 493681a5bbeSBoris Popov smb_iod_recvall(iod); 494681a5bbeSBoris Popov if (rqp->sr_rpgen != rqp->sr_rplast) 495681a5bbeSBoris Popov break; 496681a5bbeSBoris Popov tsleep(&iod->iod_flags, PWAIT, "90irq", hz); 497681a5bbeSBoris Popov } 498681a5bbeSBoris Popov smb_iod_removerq(rqp); 499681a5bbeSBoris Popov return rqp->sr_lerror; 500681a5bbeSBoris Popov 501681a5bbeSBoris Popov } 502681a5bbeSBoris Popov SMBRQ_SLOCK(rqp); 503681a5bbeSBoris Popov if (rqp->sr_rpgen == rqp->sr_rplast) 504681a5bbeSBoris Popov msleep(&rqp->sr_state, SMBRQ_SLOCKPTR(rqp), PWAIT, "90wrq", 0); 505681a5bbeSBoris Popov rqp->sr_rplast++; 506681a5bbeSBoris Popov SMBRQ_SUNLOCK(rqp); 507681a5bbeSBoris Popov error = rqp->sr_lerror; 508681a5bbeSBoris Popov if (rqp->sr_flags & SMBR_MULTIPACKET) { 509681a5bbeSBoris Popov /* 510681a5bbeSBoris Popov * If request should stay in the list, then reinsert it 511681a5bbeSBoris Popov * at the end of queue so other waiters have chance to concur 512681a5bbeSBoris Popov */ 513681a5bbeSBoris Popov SMB_IOD_RQLOCK(iod); 514681a5bbeSBoris Popov TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link); 515681a5bbeSBoris Popov TAILQ_INSERT_TAIL(&iod->iod_rqlist, rqp, sr_link); 516681a5bbeSBoris Popov SMB_IOD_RQUNLOCK(iod); 517681a5bbeSBoris Popov } else 518681a5bbeSBoris Popov smb_iod_removerq(rqp); 519681a5bbeSBoris Popov return error; 520681a5bbeSBoris Popov } 521681a5bbeSBoris Popov 522681a5bbeSBoris Popov 523681a5bbeSBoris Popov static int 524681a5bbeSBoris Popov smb_iod_sendall(struct smbiod *iod) 525681a5bbeSBoris Popov { 526681a5bbeSBoris Popov struct smb_vc *vcp = iod->iod_vc; 527681a5bbeSBoris Popov struct smb_rq *rqp; 528681a5bbeSBoris Popov struct timespec ts, tstimeout; 529681a5bbeSBoris Popov int herror; 530681a5bbeSBoris Popov 531681a5bbeSBoris Popov herror = 0; 532681a5bbeSBoris Popov /* 533681a5bbeSBoris Popov * Loop through the list of requests and send them if possible 534681a5bbeSBoris Popov */ 535681a5bbeSBoris Popov SMB_IOD_RQLOCK(iod); 536681a5bbeSBoris Popov TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) { 537681a5bbeSBoris Popov switch (rqp->sr_state) { 538681a5bbeSBoris Popov case SMBRQ_NOTSENT: 539681a5bbeSBoris Popov rqp->sr_flags |= SMBR_XLOCK; 540681a5bbeSBoris Popov SMB_IOD_RQUNLOCK(iod); 541681a5bbeSBoris Popov herror = smb_iod_sendrq(iod, rqp); 542681a5bbeSBoris Popov SMB_IOD_RQLOCK(iod); 543681a5bbeSBoris Popov rqp->sr_flags &= ~SMBR_XLOCK; 544681a5bbeSBoris Popov if (rqp->sr_flags & SMBR_XLOCKWANT) { 545681a5bbeSBoris Popov rqp->sr_flags &= ~SMBR_XLOCKWANT; 546681a5bbeSBoris Popov wakeup(rqp); 547681a5bbeSBoris Popov } 548681a5bbeSBoris Popov break; 549681a5bbeSBoris Popov case SMBRQ_SENT: 550681a5bbeSBoris Popov SMB_TRAN_GETPARAM(vcp, SMBTP_TIMEOUT, &tstimeout); 551681a5bbeSBoris Popov timespecadd(&tstimeout, &tstimeout); 552681a5bbeSBoris Popov getnanotime(&ts); 553681a5bbeSBoris Popov timespecsub(&ts, &tstimeout); 554681a5bbeSBoris Popov if (timespeccmp(&ts, &rqp->sr_timesent, >)) { 555681a5bbeSBoris Popov smb_iod_rqprocessed(rqp, ETIMEDOUT); 556681a5bbeSBoris Popov } 557681a5bbeSBoris Popov break; 558681a5bbeSBoris Popov default: 559681a5bbeSBoris Popov } 560681a5bbeSBoris Popov if (herror) 561681a5bbeSBoris Popov break; 562681a5bbeSBoris Popov } 563681a5bbeSBoris Popov SMB_IOD_RQUNLOCK(iod); 564681a5bbeSBoris Popov if (herror == ENOTCONN) 565681a5bbeSBoris Popov smb_iod_dead(iod); 566681a5bbeSBoris Popov return 0; 567681a5bbeSBoris Popov } 568681a5bbeSBoris Popov 569681a5bbeSBoris Popov /* 570681a5bbeSBoris Popov * "main" function for smbiod daemon 571681a5bbeSBoris Popov */ 572681a5bbeSBoris Popov static __inline void 573681a5bbeSBoris Popov smb_iod_main(struct smbiod *iod) 574681a5bbeSBoris Popov { 575681a5bbeSBoris Popov /* struct smb_vc *vcp = iod->iod_vc;*/ 576681a5bbeSBoris Popov struct smbiod_event *evp; 577681a5bbeSBoris Popov /* struct timespec tsnow;*/ 578681a5bbeSBoris Popov int error; 579681a5bbeSBoris Popov 580681a5bbeSBoris Popov SMBIODEBUG("\n"); 581681a5bbeSBoris Popov error = 0; 582681a5bbeSBoris Popov 583681a5bbeSBoris Popov /* 584681a5bbeSBoris Popov * Check all interesting events 585681a5bbeSBoris Popov */ 586681a5bbeSBoris Popov for (;;) { 587681a5bbeSBoris Popov SMB_IOD_EVLOCK(iod); 588681a5bbeSBoris Popov evp = STAILQ_FIRST(&iod->iod_evlist); 589681a5bbeSBoris Popov if (evp == NULL) { 590681a5bbeSBoris Popov SMB_IOD_EVUNLOCK(iod); 591681a5bbeSBoris Popov break; 592681a5bbeSBoris Popov } 593681a5bbeSBoris Popov STAILQ_REMOVE_HEAD(&iod->iod_evlist, ev_link); 594681a5bbeSBoris Popov evp->ev_type |= SMBIOD_EV_PROCESSING; 595681a5bbeSBoris Popov SMB_IOD_EVUNLOCK(iod); 596681a5bbeSBoris Popov switch (evp->ev_type & SMBIOD_EV_MASK) { 597681a5bbeSBoris Popov case SMBIOD_EV_CONNECT: 598681a5bbeSBoris Popov iod->iod_state = SMBIOD_ST_RECONNECT; 599681a5bbeSBoris Popov evp->ev_error = smb_iod_connect(iod); 600681a5bbeSBoris Popov break; 601681a5bbeSBoris Popov case SMBIOD_EV_DISCONNECT: 602681a5bbeSBoris Popov evp->ev_error = smb_iod_disconnect(iod); 603681a5bbeSBoris Popov break; 604681a5bbeSBoris Popov case SMBIOD_EV_TREECONNECT: 605681a5bbeSBoris Popov evp->ev_error = smb_iod_treeconnect(iod, evp->ev_ident); 606681a5bbeSBoris Popov break; 607681a5bbeSBoris Popov case SMBIOD_EV_SHUTDOWN: 608681a5bbeSBoris Popov iod->iod_flags |= SMBIOD_SHUTDOWN; 609681a5bbeSBoris Popov break; 610681a5bbeSBoris Popov case SMBIOD_EV_NEWRQ: 611681a5bbeSBoris Popov break; 612681a5bbeSBoris Popov } 613681a5bbeSBoris Popov if (evp->ev_type & SMBIOD_EV_SYNC) { 614681a5bbeSBoris Popov SMB_IOD_EVLOCK(iod); 615681a5bbeSBoris Popov wakeup(evp); 616681a5bbeSBoris Popov SMB_IOD_EVUNLOCK(iod); 617681a5bbeSBoris Popov } else 618681a5bbeSBoris Popov free(evp, M_SMBIOD); 619681a5bbeSBoris Popov } 620681a5bbeSBoris Popov #if 0 621681a5bbeSBoris Popov if (iod->iod_state == SMBIOD_ST_VCACTIVE) { 622681a5bbeSBoris Popov getnanotime(&tsnow); 623681a5bbeSBoris Popov timespecsub(&tsnow, &iod->iod_pingtimo); 624681a5bbeSBoris Popov if (timespeccmp(&tsnow, &iod->iod_lastrqsent, >)) { 625681a5bbeSBoris Popov smb_smb_echo(vcp, &iod->iod_scred); 626681a5bbeSBoris Popov } 627681a5bbeSBoris Popov } 628681a5bbeSBoris Popov #endif 629681a5bbeSBoris Popov smb_iod_sendall(iod); 630681a5bbeSBoris Popov smb_iod_recvall(iod); 631681a5bbeSBoris Popov return; 632681a5bbeSBoris Popov } 633681a5bbeSBoris Popov 634681a5bbeSBoris Popov void 635681a5bbeSBoris Popov smb_iod_thread(void *arg) 636681a5bbeSBoris Popov { 637681a5bbeSBoris Popov struct smbiod *iod = arg; 638681a5bbeSBoris Popov 639681a5bbeSBoris Popov mtx_lock(&Giant); 640fce6fbfaSBoris Popov /* 641fce6fbfaSBoris Popov * Here we assume that the thread structure will be the same 642fce6fbfaSBoris Popov * for an entire kthread (kproc, to be more precise) life. 643fce6fbfaSBoris Popov */ 644fce6fbfaSBoris Popov iod->iod_td = curthread; 645fce6fbfaSBoris Popov smb_makescred(&iod->iod_scred, iod->iod_td, NULL); 646681a5bbeSBoris Popov while ((iod->iod_flags & SMBIOD_SHUTDOWN) == 0) { 647681a5bbeSBoris Popov smb_iod_main(iod); 648681a5bbeSBoris Popov SMBIODEBUG("going to sleep for %d ticks\n", iod->iod_sleeptimo); 649681a5bbeSBoris Popov /* mtx_unlock(&Giant, MTX_DEF);*/ 650681a5bbeSBoris Popov if (iod->iod_flags & SMBIOD_SHUTDOWN) 651681a5bbeSBoris Popov break; 652681a5bbeSBoris Popov tsleep(&iod->iod_flags, PWAIT, "90idle", iod->iod_sleeptimo); 653681a5bbeSBoris Popov } 654681a5bbeSBoris Popov /* mtx_lock(&Giant, MTX_DEF);*/ 655681a5bbeSBoris Popov kthread_exit(0); 656681a5bbeSBoris Popov } 657681a5bbeSBoris Popov 658681a5bbeSBoris Popov int 659681a5bbeSBoris Popov smb_iod_create(struct smb_vc *vcp) 660681a5bbeSBoris Popov { 661681a5bbeSBoris Popov struct smbiod *iod; 662681a5bbeSBoris Popov int error; 663681a5bbeSBoris Popov 664681a5bbeSBoris Popov iod = smb_zmalloc(sizeof(*iod), M_SMBIOD, M_WAITOK); 665681a5bbeSBoris Popov iod->iod_id = smb_iod_next++; 666681a5bbeSBoris Popov iod->iod_state = SMBIOD_ST_NOTCONN; 667681a5bbeSBoris Popov iod->iod_vc = vcp; 668681a5bbeSBoris Popov iod->iod_sleeptimo = hz * SMBIOD_SLEEP_TIMO; 669681a5bbeSBoris Popov iod->iod_pingtimo.tv_sec = SMBIOD_PING_TIMO; 670681a5bbeSBoris Popov getnanotime(&iod->iod_lastrqsent); 671681a5bbeSBoris Popov vcp->vc_iod = iod; 672681a5bbeSBoris Popov smb_sl_init(&iod->iod_rqlock, "90rql"); 673681a5bbeSBoris Popov TAILQ_INIT(&iod->iod_rqlist); 674681a5bbeSBoris Popov smb_sl_init(&iod->iod_evlock, "90evl"); 675681a5bbeSBoris Popov STAILQ_INIT(&iod->iod_evlist); 676fce6fbfaSBoris Popov error = kthread_create(smb_iod_thread, iod, &iod->iod_p, 677681a5bbeSBoris Popov RFNOWAIT, "smbiod%d", iod->iod_id); 678681a5bbeSBoris Popov if (error) { 679681a5bbeSBoris Popov SMBERROR("can't start smbiod: %d", error); 680681a5bbeSBoris Popov free(iod, M_SMBIOD); 681681a5bbeSBoris Popov return error; 682681a5bbeSBoris Popov } 683681a5bbeSBoris Popov return 0; 684681a5bbeSBoris Popov } 685681a5bbeSBoris Popov 686681a5bbeSBoris Popov int 687681a5bbeSBoris Popov smb_iod_destroy(struct smbiod *iod) 688681a5bbeSBoris Popov { 689681a5bbeSBoris Popov smb_iod_request(iod, SMBIOD_EV_SHUTDOWN | SMBIOD_EV_SYNC, NULL); 690e7681448SBoris Popov smb_sl_destroy(&iod->iod_rqlock); 691e7681448SBoris Popov smb_sl_destroy(&iod->iod_evlock); 692681a5bbeSBoris Popov free(iod, M_SMBIOD); 693681a5bbeSBoris Popov return 0; 694681a5bbeSBoris Popov } 695681a5bbeSBoris Popov 696681a5bbeSBoris Popov int 697681a5bbeSBoris Popov smb_iod_init(void) 698681a5bbeSBoris Popov { 699681a5bbeSBoris Popov return 0; 700681a5bbeSBoris Popov } 701681a5bbeSBoris Popov 702681a5bbeSBoris Popov int 703681a5bbeSBoris Popov smb_iod_done(void) 704681a5bbeSBoris Popov { 705681a5bbeSBoris Popov return 0; 706681a5bbeSBoris Popov } 707681a5bbeSBoris Popov 708