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