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