1 /*- 2 * Copyright (c) 2000-2001 Boris Popov 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Boris Popov. 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include <sys/cdefs.h> 34 __FBSDID("$FreeBSD$"); 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/endian.h> 39 #include <sys/proc.h> 40 #include <sys/kernel.h> 41 #include <sys/kthread.h> 42 #include <sys/malloc.h> 43 #include <sys/mbuf.h> 44 #include <sys/unistd.h> 45 46 #include <netsmb/smb.h> 47 #include <netsmb/smb_conn.h> 48 #include <netsmb/smb_rq.h> 49 #include <netsmb/smb_tran.h> 50 #include <netsmb/smb_trantcp.h> 51 52 53 #define SMBIOD_SLEEP_TIMO 2 54 #define SMBIOD_PING_TIMO 60 /* seconds */ 55 56 #define SMB_IOD_EVLOCKPTR(iod) (&((iod)->iod_evlock)) 57 #define SMB_IOD_EVLOCK(iod) smb_sl_lock(&((iod)->iod_evlock)) 58 #define SMB_IOD_EVUNLOCK(iod) smb_sl_unlock(&((iod)->iod_evlock)) 59 60 #define SMB_IOD_RQLOCKPTR(iod) (&((iod)->iod_rqlock)) 61 #define SMB_IOD_RQLOCK(iod) smb_sl_lock(&((iod)->iod_rqlock)) 62 #define SMB_IOD_RQUNLOCK(iod) smb_sl_unlock(&((iod)->iod_rqlock)) 63 64 #define smb_iod_wakeup(iod) wakeup(&(iod)->iod_flags) 65 66 67 static MALLOC_DEFINE(M_SMBIOD, "SMBIOD", "SMB network io daemon"); 68 69 static int smb_iod_next; 70 71 static int smb_iod_sendall(struct smbiod *iod); 72 static int smb_iod_disconnect(struct smbiod *iod); 73 static void smb_iod_thread(void *); 74 75 static __inline void 76 smb_iod_rqprocessed(struct smb_rq *rqp, int error) 77 { 78 SMBRQ_SLOCK(rqp); 79 rqp->sr_lerror = error; 80 rqp->sr_rpgen++; 81 rqp->sr_state = SMBRQ_NOTIFIED; 82 wakeup(&rqp->sr_state); 83 SMBRQ_SUNLOCK(rqp); 84 } 85 86 static void 87 smb_iod_invrq(struct smbiod *iod) 88 { 89 struct smb_rq *rqp; 90 91 /* 92 * Invalidate all outstanding requests for this connection 93 */ 94 SMB_IOD_RQLOCK(iod); 95 TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) { 96 if (rqp->sr_flags & SMBR_INTERNAL) 97 SMBRQ_SUNLOCK(rqp); 98 rqp->sr_flags |= SMBR_RESTART; 99 smb_iod_rqprocessed(rqp, ENOTCONN); 100 } 101 SMB_IOD_RQUNLOCK(iod); 102 } 103 104 static void 105 smb_iod_closetran(struct smbiod *iod) 106 { 107 struct smb_vc *vcp = iod->iod_vc; 108 struct thread *td = iod->iod_td; 109 110 if (vcp->vc_tdata == NULL) 111 return; 112 SMB_TRAN_DISCONNECT(vcp, td); 113 SMB_TRAN_DONE(vcp, td); 114 vcp->vc_tdata = NULL; 115 } 116 117 static void 118 smb_iod_dead(struct smbiod *iod) 119 { 120 iod->iod_state = SMBIOD_ST_DEAD; 121 smb_iod_closetran(iod); 122 smb_iod_invrq(iod); 123 } 124 125 static int 126 smb_iod_connect(struct smbiod *iod) 127 { 128 struct smb_vc *vcp = iod->iod_vc; 129 struct thread *td = iod->iod_td; 130 int error; 131 132 SMBIODEBUG("%d\n", iod->iod_state); 133 switch(iod->iod_state) { 134 case SMBIOD_ST_VCACTIVE: 135 SMBERROR("called for already opened connection\n"); 136 return EISCONN; 137 case SMBIOD_ST_DEAD: 138 return ENOTCONN; /* XXX: last error code ? */ 139 default: 140 break; 141 } 142 vcp->vc_genid++; 143 error = 0; 144 145 error = (int)SMB_TRAN_CREATE(vcp, td); 146 if (error) 147 goto fail; 148 SMBIODEBUG("tcreate\n"); 149 if (vcp->vc_laddr) { 150 error = (int)SMB_TRAN_BIND(vcp, vcp->vc_laddr, td); 151 if (error) 152 goto fail; 153 } 154 SMBIODEBUG("tbind\n"); 155 error = (int)SMB_TRAN_CONNECT(vcp, vcp->vc_paddr, td); 156 if (error) 157 goto fail; 158 SMB_TRAN_SETPARAM(vcp, SMBTP_SELECTID, &iod->iod_flags); 159 iod->iod_state = SMBIOD_ST_TRANACTIVE; 160 SMBIODEBUG("tconnect\n"); 161 /* vcp->vc_mid = 0;*/ 162 error = (int)smb_smb_negotiate(vcp, &iod->iod_scred); 163 if (error) 164 goto fail; 165 SMBIODEBUG("snegotiate\n"); 166 error = (int)smb_smb_ssnsetup(vcp, &iod->iod_scred); 167 if (error) 168 goto fail; 169 iod->iod_state = SMBIOD_ST_VCACTIVE; 170 SMBIODEBUG("completed\n"); 171 smb_iod_invrq(iod); 172 return (0); 173 174 fail: 175 smb_iod_dead(iod); 176 return (error); 177 } 178 179 static int 180 smb_iod_disconnect(struct smbiod *iod) 181 { 182 struct smb_vc *vcp = iod->iod_vc; 183 184 SMBIODEBUG("\n"); 185 if (iod->iod_state == SMBIOD_ST_VCACTIVE) { 186 smb_smb_ssnclose(vcp, &iod->iod_scred); 187 iod->iod_state = SMBIOD_ST_TRANACTIVE; 188 } 189 vcp->vc_smbuid = SMB_UID_UNKNOWN; 190 smb_iod_closetran(iod); 191 iod->iod_state = SMBIOD_ST_NOTCONN; 192 return 0; 193 } 194 195 static int 196 smb_iod_treeconnect(struct smbiod *iod, struct smb_share *ssp) 197 { 198 int error; 199 200 if (iod->iod_state != SMBIOD_ST_VCACTIVE) { 201 if (iod->iod_state != SMBIOD_ST_DEAD) 202 return ENOTCONN; 203 iod->iod_state = SMBIOD_ST_RECONNECT; 204 error = smb_iod_connect(iod); 205 if (error) 206 return error; 207 } 208 SMBIODEBUG("tree reconnect\n"); 209 SMBS_ST_LOCK(ssp); 210 ssp->ss_flags |= SMBS_RECONNECTING; 211 SMBS_ST_UNLOCK(ssp); 212 error = smb_smb_treeconnect(ssp, &iod->iod_scred); 213 SMBS_ST_LOCK(ssp); 214 ssp->ss_flags &= ~SMBS_RECONNECTING; 215 SMBS_ST_UNLOCK(ssp); 216 wakeup(&ssp->ss_vcgenid); 217 return error; 218 } 219 220 static int 221 smb_iod_sendrq(struct smbiod *iod, struct smb_rq *rqp) 222 { 223 struct thread *td = iod->iod_td; 224 struct smb_vc *vcp = iod->iod_vc; 225 struct smb_share *ssp = rqp->sr_share; 226 struct mbuf *m; 227 int error; 228 229 SMBIODEBUG("iod_state = %d\n", iod->iod_state); 230 switch (iod->iod_state) { 231 case SMBIOD_ST_NOTCONN: 232 smb_iod_rqprocessed(rqp, ENOTCONN); 233 return 0; 234 case SMBIOD_ST_DEAD: 235 iod->iod_state = SMBIOD_ST_RECONNECT; 236 return 0; 237 case SMBIOD_ST_RECONNECT: 238 return 0; 239 default: 240 break; 241 } 242 if (rqp->sr_sendcnt == 0) { 243 #ifdef movedtoanotherplace 244 if (vcp->vc_maxmux != 0 && iod->iod_muxcnt >= vcp->vc_maxmux) 245 return 0; 246 #endif 247 le16enc(rqp->sr_rqtid, ssp ? ssp->ss_tid : SMB_TID_UNKNOWN); 248 le16enc(rqp->sr_rquid, vcp ? vcp->vc_smbuid : 0); 249 mb_fixhdr(&rqp->sr_rq); 250 if (vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) 251 smb_rq_sign(rqp); 252 } 253 if (rqp->sr_sendcnt++ > 5) { 254 rqp->sr_flags |= SMBR_RESTART; 255 smb_iod_rqprocessed(rqp, rqp->sr_lerror); 256 /* 257 * If all attempts to send a request failed, then 258 * something is seriously hosed. 259 */ 260 return ENOTCONN; 261 } 262 SMBSDEBUG("M:%04x, P:%04x, U:%04x, T:%04x\n", rqp->sr_mid, 0, 0, 0); 263 m_dumpm(rqp->sr_rq.mb_top); 264 m = m_copym(rqp->sr_rq.mb_top, 0, M_COPYALL, M_TRYWAIT); 265 error = rqp->sr_lerror = m ? SMB_TRAN_SEND(vcp, m, td) : ENOBUFS; 266 if (error == 0) { 267 getnanotime(&rqp->sr_timesent); 268 iod->iod_lastrqsent = rqp->sr_timesent; 269 rqp->sr_flags |= SMBR_SENT; 270 rqp->sr_state = SMBRQ_SENT; 271 return 0; 272 } 273 /* 274 * Check for fatal errors 275 */ 276 if (SMB_TRAN_FATAL(vcp, error)) { 277 /* 278 * No further attempts should be made 279 */ 280 return ENOTCONN; 281 } 282 if (smb_rq_intr(rqp)) 283 smb_iod_rqprocessed(rqp, EINTR); 284 return 0; 285 } 286 287 /* 288 * Process incoming packets 289 */ 290 static int 291 smb_iod_recvall(struct smbiod *iod) 292 { 293 struct smb_vc *vcp = iod->iod_vc; 294 struct thread *td = iod->iod_td; 295 struct smb_rq *rqp; 296 struct mbuf *m; 297 u_char *hp; 298 u_short mid; 299 int error; 300 301 switch (iod->iod_state) { 302 case SMBIOD_ST_NOTCONN: 303 case SMBIOD_ST_DEAD: 304 case SMBIOD_ST_RECONNECT: 305 return 0; 306 default: 307 break; 308 } 309 for (;;) { 310 m = NULL; 311 error = SMB_TRAN_RECV(vcp, &m, td); 312 if (error == EWOULDBLOCK) 313 break; 314 if (SMB_TRAN_FATAL(vcp, error)) { 315 smb_iod_dead(iod); 316 break; 317 } 318 if (error) 319 break; 320 if (m == NULL) { 321 SMBERROR("tran return NULL without error\n"); 322 error = EPIPE; 323 continue; 324 } 325 m = m_pullup(m, SMB_HDRLEN); 326 if (m == NULL) 327 continue; /* wait for a good packet */ 328 /* 329 * Now we got an entire and possibly invalid SMB packet. 330 * Be careful while parsing it. 331 */ 332 m_dumpm(m); 333 hp = mtod(m, u_char*); 334 if (bcmp(hp, SMB_SIGNATURE, SMB_SIGLEN) != 0) { 335 m_freem(m); 336 continue; 337 } 338 mid = SMB_HDRMID(hp); 339 SMBSDEBUG("mid %04x\n", (u_int)mid); 340 SMB_IOD_RQLOCK(iod); 341 TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) { 342 if (rqp->sr_mid != mid) 343 continue; 344 SMBRQ_SLOCK(rqp); 345 if (rqp->sr_rp.md_top == NULL) { 346 md_initm(&rqp->sr_rp, m); 347 } else { 348 if (rqp->sr_flags & SMBR_MULTIPACKET) { 349 md_append_record(&rqp->sr_rp, m); 350 } else { 351 SMBRQ_SUNLOCK(rqp); 352 SMBERROR("duplicate response %d (ignored)\n", mid); 353 break; 354 } 355 } 356 SMBRQ_SUNLOCK(rqp); 357 smb_iod_rqprocessed(rqp, 0); 358 break; 359 } 360 SMB_IOD_RQUNLOCK(iod); 361 if (rqp == NULL) { 362 SMBERROR("drop resp with mid %d\n", (u_int)mid); 363 /* smb_printrqlist(vcp);*/ 364 m_freem(m); 365 } 366 } 367 /* 368 * check for interrupts 369 */ 370 SMB_IOD_RQLOCK(iod); 371 TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) { 372 if (smb_td_intr(rqp->sr_cred->scr_td)) { 373 smb_iod_rqprocessed(rqp, EINTR); 374 } 375 } 376 SMB_IOD_RQUNLOCK(iod); 377 return 0; 378 } 379 380 int 381 smb_iod_request(struct smbiod *iod, int event, void *ident) 382 { 383 struct smbiod_event *evp; 384 int error; 385 386 SMBIODEBUG("\n"); 387 evp = smb_zmalloc(sizeof(*evp), M_SMBIOD, M_WAITOK); 388 evp->ev_type = event; 389 evp->ev_ident = ident; 390 SMB_IOD_EVLOCK(iod); 391 STAILQ_INSERT_TAIL(&iod->iod_evlist, evp, ev_link); 392 if ((event & SMBIOD_EV_SYNC) == 0) { 393 SMB_IOD_EVUNLOCK(iod); 394 smb_iod_wakeup(iod); 395 return 0; 396 } 397 smb_iod_wakeup(iod); 398 msleep(evp, SMB_IOD_EVLOCKPTR(iod), PWAIT | PDROP, "90evw", 0); 399 error = evp->ev_error; 400 free(evp, M_SMBIOD); 401 return error; 402 } 403 404 /* 405 * Place request in the queue. 406 * Request from smbiod have a high priority. 407 */ 408 int 409 smb_iod_addrq(struct smb_rq *rqp) 410 { 411 struct smb_vc *vcp = rqp->sr_vc; 412 struct smbiod *iod = vcp->vc_iod; 413 int error; 414 415 SMBIODEBUG("\n"); 416 if (rqp->sr_cred->scr_td != NULL && 417 rqp->sr_cred->scr_td->td_proc == iod->iod_p) { 418 rqp->sr_flags |= SMBR_INTERNAL; 419 SMB_IOD_RQLOCK(iod); 420 TAILQ_INSERT_HEAD(&iod->iod_rqlist, rqp, sr_link); 421 SMB_IOD_RQUNLOCK(iod); 422 for (;;) { 423 if (smb_iod_sendrq(iod, rqp) != 0) { 424 smb_iod_dead(iod); 425 break; 426 } 427 /* 428 * we don't need to lock state field here 429 */ 430 if (rqp->sr_state != SMBRQ_NOTSENT) 431 break; 432 tsleep(&iod->iod_flags, PWAIT, "90sndw", hz); 433 } 434 if (rqp->sr_lerror) 435 smb_iod_removerq(rqp); 436 return rqp->sr_lerror; 437 } 438 439 switch (iod->iod_state) { 440 case SMBIOD_ST_NOTCONN: 441 return ENOTCONN; 442 case SMBIOD_ST_DEAD: 443 error = smb_iod_request(vcp->vc_iod, SMBIOD_EV_CONNECT | SMBIOD_EV_SYNC, NULL); 444 if (error) 445 return error; 446 return EXDEV; 447 default: 448 break; 449 } 450 451 SMB_IOD_RQLOCK(iod); 452 for (;;) { 453 if (vcp->vc_maxmux == 0) { 454 SMBERROR("maxmux == 0\n"); 455 break; 456 } 457 if (iod->iod_muxcnt < vcp->vc_maxmux) 458 break; 459 iod->iod_muxwant++; 460 msleep(&iod->iod_muxwant, SMB_IOD_RQLOCKPTR(iod), 461 PWAIT, "90mux", 0); 462 } 463 iod->iod_muxcnt++; 464 TAILQ_INSERT_TAIL(&iod->iod_rqlist, rqp, sr_link); 465 SMB_IOD_RQUNLOCK(iod); 466 smb_iod_wakeup(iod); 467 return 0; 468 } 469 470 int 471 smb_iod_removerq(struct smb_rq *rqp) 472 { 473 struct smb_vc *vcp = rqp->sr_vc; 474 struct smbiod *iod = vcp->vc_iod; 475 476 SMBIODEBUG("\n"); 477 if (rqp->sr_flags & SMBR_INTERNAL) { 478 SMB_IOD_RQLOCK(iod); 479 TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link); 480 SMB_IOD_RQUNLOCK(iod); 481 return 0; 482 } 483 SMB_IOD_RQLOCK(iod); 484 while (rqp->sr_flags & SMBR_XLOCK) { 485 rqp->sr_flags |= SMBR_XLOCKWANT; 486 msleep(rqp, SMB_IOD_RQLOCKPTR(iod), PWAIT, "90xrm", 0); 487 } 488 TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link); 489 iod->iod_muxcnt--; 490 if (iod->iod_muxwant) { 491 iod->iod_muxwant--; 492 wakeup(&iod->iod_muxwant); 493 } 494 SMB_IOD_RQUNLOCK(iod); 495 return 0; 496 } 497 498 int 499 smb_iod_waitrq(struct smb_rq *rqp) 500 { 501 struct smbiod *iod = rqp->sr_vc->vc_iod; 502 int error; 503 504 SMBIODEBUG("\n"); 505 if (rqp->sr_flags & SMBR_INTERNAL) { 506 for (;;) { 507 smb_iod_sendall(iod); 508 smb_iod_recvall(iod); 509 if (rqp->sr_rpgen != rqp->sr_rplast) 510 break; 511 tsleep(&iod->iod_flags, PWAIT, "90irq", hz); 512 } 513 smb_iod_removerq(rqp); 514 return rqp->sr_lerror; 515 516 } 517 SMBRQ_SLOCK(rqp); 518 if (rqp->sr_rpgen == rqp->sr_rplast) 519 msleep(&rqp->sr_state, SMBRQ_SLOCKPTR(rqp), PWAIT, "90wrq", 0); 520 rqp->sr_rplast++; 521 SMBRQ_SUNLOCK(rqp); 522 error = rqp->sr_lerror; 523 if (rqp->sr_flags & SMBR_MULTIPACKET) { 524 /* 525 * If request should stay in the list, then reinsert it 526 * at the end of queue so other waiters have chance to concur 527 */ 528 SMB_IOD_RQLOCK(iod); 529 TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link); 530 TAILQ_INSERT_TAIL(&iod->iod_rqlist, rqp, sr_link); 531 SMB_IOD_RQUNLOCK(iod); 532 } else 533 smb_iod_removerq(rqp); 534 return error; 535 } 536 537 538 static int 539 smb_iod_sendall(struct smbiod *iod) 540 { 541 struct smb_vc *vcp = iod->iod_vc; 542 struct smb_rq *rqp; 543 struct timespec ts, tstimeout; 544 int herror; 545 546 herror = 0; 547 /* 548 * Loop through the list of requests and send them if possible 549 */ 550 SMB_IOD_RQLOCK(iod); 551 TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) { 552 switch (rqp->sr_state) { 553 case SMBRQ_NOTSENT: 554 rqp->sr_flags |= SMBR_XLOCK; 555 SMB_IOD_RQUNLOCK(iod); 556 herror = smb_iod_sendrq(iod, rqp); 557 SMB_IOD_RQLOCK(iod); 558 rqp->sr_flags &= ~SMBR_XLOCK; 559 if (rqp->sr_flags & SMBR_XLOCKWANT) { 560 rqp->sr_flags &= ~SMBR_XLOCKWANT; 561 wakeup(rqp); 562 } 563 break; 564 case SMBRQ_SENT: 565 SMB_TRAN_GETPARAM(vcp, SMBTP_TIMEOUT, &tstimeout); 566 timespecadd(&tstimeout, &tstimeout); 567 getnanotime(&ts); 568 timespecsub(&ts, &tstimeout); 569 if (timespeccmp(&ts, &rqp->sr_timesent, >)) { 570 smb_iod_rqprocessed(rqp, ETIMEDOUT); 571 } 572 break; 573 default: 574 break; 575 } 576 if (herror) 577 break; 578 } 579 SMB_IOD_RQUNLOCK(iod); 580 if (herror == ENOTCONN) 581 smb_iod_dead(iod); 582 return 0; 583 } 584 585 /* 586 * "main" function for smbiod daemon 587 */ 588 static __inline void 589 smb_iod_main(struct smbiod *iod) 590 { 591 /* struct smb_vc *vcp = iod->iod_vc;*/ 592 struct smbiod_event *evp; 593 /* struct timespec tsnow;*/ 594 int error; 595 596 SMBIODEBUG("\n"); 597 error = 0; 598 599 /* 600 * Check all interesting events 601 */ 602 for (;;) { 603 SMB_IOD_EVLOCK(iod); 604 evp = STAILQ_FIRST(&iod->iod_evlist); 605 if (evp == NULL) { 606 SMB_IOD_EVUNLOCK(iod); 607 break; 608 } 609 STAILQ_REMOVE_HEAD(&iod->iod_evlist, ev_link); 610 evp->ev_type |= SMBIOD_EV_PROCESSING; 611 SMB_IOD_EVUNLOCK(iod); 612 switch (evp->ev_type & SMBIOD_EV_MASK) { 613 case SMBIOD_EV_CONNECT: 614 iod->iod_state = SMBIOD_ST_RECONNECT; 615 evp->ev_error = smb_iod_connect(iod); 616 break; 617 case SMBIOD_EV_DISCONNECT: 618 evp->ev_error = smb_iod_disconnect(iod); 619 break; 620 case SMBIOD_EV_TREECONNECT: 621 evp->ev_error = smb_iod_treeconnect(iod, evp->ev_ident); 622 break; 623 case SMBIOD_EV_SHUTDOWN: 624 iod->iod_flags |= SMBIOD_SHUTDOWN; 625 break; 626 case SMBIOD_EV_NEWRQ: 627 break; 628 } 629 if (evp->ev_type & SMBIOD_EV_SYNC) { 630 SMB_IOD_EVLOCK(iod); 631 wakeup(evp); 632 SMB_IOD_EVUNLOCK(iod); 633 } else 634 free(evp, M_SMBIOD); 635 } 636 #if 0 637 if (iod->iod_state == SMBIOD_ST_VCACTIVE) { 638 getnanotime(&tsnow); 639 timespecsub(&tsnow, &iod->iod_pingtimo); 640 if (timespeccmp(&tsnow, &iod->iod_lastrqsent, >)) { 641 smb_smb_echo(vcp, &iod->iod_scred); 642 } 643 } 644 #endif 645 smb_iod_sendall(iod); 646 smb_iod_recvall(iod); 647 return; 648 } 649 650 void 651 smb_iod_thread(void *arg) 652 { 653 struct smbiod *iod = arg; 654 655 mtx_lock(&Giant); 656 /* 657 * Here we assume that the thread structure will be the same 658 * for an entire kthread (kproc, to be more precise) life. 659 */ 660 iod->iod_td = curthread; 661 smb_makescred(&iod->iod_scred, iod->iod_td, NULL); 662 while ((iod->iod_flags & SMBIOD_SHUTDOWN) == 0) { 663 smb_iod_main(iod); 664 SMBIODEBUG("going to sleep for %d ticks\n", iod->iod_sleeptimo); 665 /* mtx_unlock(&Giant, MTX_DEF);*/ 666 if (iod->iod_flags & SMBIOD_SHUTDOWN) 667 break; 668 tsleep(&iod->iod_flags, PWAIT, "90idle", iod->iod_sleeptimo); 669 } 670 /* mtx_lock(&Giant, MTX_DEF);*/ 671 kproc_exit(0); 672 } 673 674 int 675 smb_iod_create(struct smb_vc *vcp) 676 { 677 struct smbiod *iod; 678 int error; 679 680 iod = smb_zmalloc(sizeof(*iod), M_SMBIOD, M_WAITOK); 681 iod->iod_id = smb_iod_next++; 682 iod->iod_state = SMBIOD_ST_NOTCONN; 683 iod->iod_vc = vcp; 684 iod->iod_sleeptimo = hz * SMBIOD_SLEEP_TIMO; 685 iod->iod_pingtimo.tv_sec = SMBIOD_PING_TIMO; 686 getnanotime(&iod->iod_lastrqsent); 687 vcp->vc_iod = iod; 688 smb_sl_init(&iod->iod_rqlock, "90rql"); 689 TAILQ_INIT(&iod->iod_rqlist); 690 smb_sl_init(&iod->iod_evlock, "90evl"); 691 STAILQ_INIT(&iod->iod_evlist); 692 error = kproc_create(smb_iod_thread, iod, &iod->iod_p, 693 RFNOWAIT, 0, "smbiod%d", iod->iod_id); 694 if (error) { 695 SMBERROR("can't start smbiod: %d", error); 696 free(iod, M_SMBIOD); 697 return error; 698 } 699 return 0; 700 } 701 702 int 703 smb_iod_destroy(struct smbiod *iod) 704 { 705 smb_iod_request(iod, SMBIOD_EV_SHUTDOWN | SMBIOD_EV_SYNC, NULL); 706 smb_sl_destroy(&iod->iod_rqlock); 707 smb_sl_destroy(&iod->iod_evlock); 708 free(iod, M_SMBIOD); 709 return 0; 710 } 711 712 int 713 smb_iod_init(void) 714 { 715 return 0; 716 } 717 718 int 719 smb_iod_done(void) 720 { 721 return 0; 722 } 723 724