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 * $Id: smb_conn.c,v 1.27.166.1 2005/05/27 02:35:29 lindak Exp $ 33 */ 34 /* 35 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 36 * Use is subject to license terms. 37 */ 38 39 /* 40 * Connection engine. 41 */ 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/kmem.h> 46 #include <sys/proc.h> 47 #include <sys/lock.h> 48 #include <sys/vnode.h> 49 #include <sys/stream.h> 50 #include <sys/stropts.h> 51 #include <sys/socketvar.h> 52 #include <sys/cred.h> 53 #include <netinet/in.h> 54 #include <inet/ip.h> 55 #include <inet/ip6.h> 56 #include <sys/cmn_err.h> 57 #include <sys/thread.h> 58 #include <sys/atomic.h> 59 #include <sys/u8_textprep.h> 60 61 #ifdef APPLE 62 #include <sys/smb_apple.h> 63 #include <sys/smb_iconv.h> 64 #else 65 #include <netsmb/smb_osdep.h> 66 #endif 67 68 #include <netsmb/smb.h> 69 #include <netsmb/smb_conn.h> 70 #include <netsmb/smb_subr.h> 71 #include <netsmb/smb_tran.h> 72 #include <netsmb/smb_pass.h> 73 74 static struct smb_connobj smb_vclist; 75 76 void smb_co_init(struct smb_connobj *cp, int level, char *objname); 77 void smb_co_done(struct smb_connobj *cp); 78 void smb_co_hold(struct smb_connobj *cp); 79 void smb_co_rele(struct smb_connobj *cp); 80 void smb_co_kill(struct smb_connobj *cp); 81 82 static void smb_vc_free(struct smb_connobj *cp); 83 static void smb_vc_gone(struct smb_connobj *cp); 84 85 static void smb_share_free(struct smb_connobj *cp); 86 static void smb_share_gone(struct smb_connobj *cp); 87 88 int 89 smb_sm_init(void) 90 { 91 smb_co_init(&smb_vclist, SMBL_SM, "smbsm"); 92 return (0); 93 } 94 95 int 96 smb_sm_idle(void) 97 { 98 int error = 0; 99 SMB_CO_LOCK(&smb_vclist); 100 if (smb_vclist.co_usecount > 1) { 101 SMBSDEBUG("%d connections still active\n", 102 smb_vclist.co_usecount - 1); 103 error = EBUSY; 104 } 105 SMB_CO_UNLOCK(&smb_vclist); 106 return (error); 107 } 108 109 void 110 smb_sm_done(void) 111 { 112 /* 113 * XXX Q4BP why are we not iterating on smb_vclist here? 114 * Because the caller has just called smb_sm_idle() to 115 * make sure we have no VCs before calling this. 116 */ 117 smb_co_done(&smb_vclist); 118 } 119 120 121 122 /* 123 * Common code for connection object 124 */ 125 /*ARGSUSED*/ 126 void 127 smb_co_init(struct smb_connobj *cp, int level, char *objname) 128 { 129 130 mutex_init(&cp->co_lock, objname, MUTEX_DRIVER, NULL); 131 132 cp->co_level = level; 133 cp->co_usecount = 1; 134 SLIST_INIT(&cp->co_children); 135 } 136 137 /* 138 * Called just before free of an object 139 * of which smb_connobj is a part, i.e. 140 * _vc_free, _share_free, also sm_done. 141 */ 142 void 143 smb_co_done(struct smb_connobj *cp) 144 { 145 ASSERT(SLIST_EMPTY(&cp->co_children)); 146 mutex_destroy(&cp->co_lock); 147 } 148 149 static void 150 smb_co_addchild( 151 struct smb_connobj *parent, 152 struct smb_connobj *child) 153 { 154 155 /* 156 * Set the child's pointer to the parent. 157 * No references yet, so no need to lock. 158 */ 159 ASSERT(child->co_usecount == 1); 160 child->co_parent = parent; 161 162 /* 163 * Add the child to the parent's list of 164 * children, and in-line smb_co_hold 165 */ 166 ASSERT(MUTEX_HELD(&parent->co_lock)); 167 parent->co_usecount++; 168 SLIST_INSERT_HEAD(&parent->co_children, child, co_next); 169 } 170 171 void 172 smb_co_hold(struct smb_connobj *cp) 173 { 174 SMB_CO_LOCK(cp); 175 cp->co_usecount++; 176 SMB_CO_UNLOCK(cp); 177 } 178 179 /* 180 * Called via smb_vc_rele, smb_share_rele 181 */ 182 void 183 smb_co_rele(struct smb_connobj *co) 184 { 185 struct smb_connobj *parent; 186 int old_flags; 187 188 SMB_CO_LOCK(co); 189 if (co->co_usecount > 1) { 190 co->co_usecount--; 191 SMB_CO_UNLOCK(co); 192 return; 193 } 194 ASSERT(co->co_usecount == 1); 195 co->co_usecount = 0; 196 197 /* 198 * This list of children should be empty now. 199 * Check this while we're still linked, so 200 * we have a better chance of debugging. 201 */ 202 ASSERT(SLIST_EMPTY(&co->co_children)); 203 204 /* 205 * OK, this element is going away. 206 * 207 * We need to drop the lock on this CO so we can take the 208 * parent CO lock. The _GONE flag prevents this CO from 209 * getting new references before we can unlink it from the 210 * parent list. 211 * 212 * The _GONE flag is also used to ensure that the co_gone 213 * function is called only once. Note that smb_co_kill may 214 * do this before we get here. If we find that the _GONE 215 * flag was not already set, then call the co_gone hook 216 * (smb_share_gone, smb_vc_gone) which will disconnect 217 * the share or the VC, respectively. 218 * 219 * Note the old: smb_co_gone(co, scred); 220 * is now in-line here. 221 */ 222 old_flags = co->co_flags; 223 co->co_flags |= SMBO_GONE; 224 SMB_CO_UNLOCK(co); 225 226 if ((old_flags & SMBO_GONE) == 0 && co->co_gone) 227 co->co_gone(co); 228 229 /* 230 * If we have a parent (only smb_vclist does not) 231 * then unlink from parent's list of children. 232 * We have the only reference to the child. 233 */ 234 parent = co->co_parent; 235 if (parent) { 236 SMB_CO_LOCK(parent); 237 ASSERT(SLIST_FIRST(&parent->co_children)); 238 if (SLIST_FIRST(&parent->co_children)) { 239 SLIST_REMOVE(&parent->co_children, co, 240 smb_connobj, co_next); 241 } 242 SMB_CO_UNLOCK(parent); 243 } 244 245 /* 246 * Now it's safe to free the CO 247 */ 248 if (co->co_free) { 249 co->co_free(co); 250 } 251 252 /* 253 * Finally, if the CO had a parent, decrement 254 * the parent's hold count for the lost child. 255 */ 256 if (parent) { 257 /* 258 * Recursive call here (easier for debugging). 259 * Can only go two levels. 260 */ 261 smb_co_rele(parent); 262 } 263 } 264 265 /* 266 * Do just the first part of what co_gone does, 267 * i.e. tree disconnect, or disconnect a VC. 268 * This is used to forcibly close things. 269 */ 270 void 271 smb_co_kill(struct smb_connobj *co) 272 { 273 int old_flags; 274 275 SMB_CO_LOCK(co); 276 old_flags = co->co_flags; 277 co->co_flags |= SMBO_GONE; 278 SMB_CO_UNLOCK(co); 279 280 /* 281 * Do the same "call only once" logic here as in 282 * smb_co_rele, though it's probably not possible 283 * for this to be called after smb_co_rele. 284 */ 285 if ((old_flags & SMBO_GONE) == 0 && co->co_gone) 286 co->co_gone(co); 287 288 /* XXX: Walk list of children and kill those too? */ 289 } 290 291 292 /* 293 * Session objects, which are referred to as "VC" for 294 * "virtual cirtuit". This has nothing to do with the 295 * CIFS notion of a "virtual cirtuit". See smb_conn.h 296 */ 297 298 void 299 smb_vc_hold(struct smb_vc *vcp) 300 { 301 smb_co_hold(VCTOCP(vcp)); 302 } 303 304 void 305 smb_vc_rele(struct smb_vc *vcp) 306 { 307 smb_co_rele(VCTOCP(vcp)); 308 } 309 310 void 311 smb_vc_kill(struct smb_vc *vcp) 312 { 313 smb_co_kill(VCTOCP(vcp)); 314 } 315 316 /* 317 * Normally called via smb_vc_rele() 318 * after co_usecount drops to zero. 319 * Also called via: smb_vc_kill() 320 * 321 * Shutdown the VC to this server, 322 * invalidate shares linked with it. 323 */ 324 /*ARGSUSED*/ 325 static void 326 smb_vc_gone(struct smb_connobj *cp) 327 { 328 struct smb_vc *vcp = CPTOVC(cp); 329 330 /* 331 * Was smb_vc_disconnect(vcp); 332 */ 333 smb_iod_disconnect(vcp); 334 } 335 336 /* 337 * The VC has no more references. Free it. 338 * No locks needed here. 339 */ 340 static void 341 smb_vc_free(struct smb_connobj *cp) 342 { 343 struct smb_vc *vcp = CPTOVC(cp); 344 345 /* 346 * The _gone call should have emptied the request list, 347 * but let's make sure, as requests may have references 348 * to this VC without taking a hold. (The hold is the 349 * responsibility of threads placing requests.) 350 */ 351 ASSERT(vcp->iod_rqlist.tqh_first == NULL); 352 353 if (vcp->vc_tdata) 354 SMB_TRAN_DONE(vcp); 355 356 /* 357 * We are not using the iconv routines here. So commenting them for now. 358 * REVISIT. 359 */ 360 #ifdef NOTYETDEFINED 361 if (vcp->vc_tolower) 362 iconv_close(vcp->vc_tolower); 363 if (vcp->vc_toupper) 364 iconv_close(vcp->vc_toupper); 365 if (vcp->vc_tolocal) 366 iconv_close(vcp->vc_tolocal); 367 if (vcp->vc_toserver) 368 iconv_close(vcp->vc_toserver); 369 #endif 370 371 if (vcp->vc_mackey != NULL) 372 kmem_free(vcp->vc_mackey, vcp->vc_mackeylen); 373 374 cv_destroy(&vcp->iod_idle); 375 rw_destroy(&vcp->iod_rqlock); 376 sema_destroy(&vcp->vc_sendlock); 377 cv_destroy(&vcp->vc_statechg); 378 smb_co_done(VCTOCP(vcp)); 379 kmem_free(vcp, sizeof (*vcp)); 380 } 381 382 /*ARGSUSED*/ 383 int 384 smb_vc_create(smbioc_ossn_t *ossn, smb_cred_t *scred, smb_vc_t **vcpp) 385 { 386 static char objtype[] = "smb_vc"; 387 cred_t *cr = scred->scr_cred; 388 struct smb_vc *vcp; 389 int error = 0; 390 391 ASSERT(MUTEX_HELD(&smb_vclist.co_lock)); 392 393 vcp = kmem_zalloc(sizeof (struct smb_vc), KM_SLEEP); 394 395 smb_co_init(VCTOCP(vcp), SMBL_VC, objtype); 396 vcp->vc_co.co_free = smb_vc_free; 397 vcp->vc_co.co_gone = smb_vc_gone; 398 399 cv_init(&vcp->vc_statechg, objtype, CV_DRIVER, NULL); 400 sema_init(&vcp->vc_sendlock, 1, objtype, SEMA_DRIVER, NULL); 401 rw_init(&vcp->iod_rqlock, objtype, RW_DRIVER, NULL); 402 cv_init(&vcp->iod_idle, objtype, CV_DRIVER, NULL); 403 404 /* Expanded TAILQ_HEAD_INITIALIZER */ 405 vcp->iod_rqlist.tqh_last = &vcp->iod_rqlist.tqh_first; 406 407 vcp->vc_state = SMBIOD_ST_IDLE; 408 409 /* 410 * These identify the connection. 411 */ 412 vcp->vc_zoneid = getzoneid(); 413 bcopy(ossn, &vcp->vc_ssn, sizeof (*ossn)); 414 415 /* This fills in vcp->vc_tdata */ 416 vcp->vc_tdesc = &smb_tran_nbtcp_desc; 417 if ((error = SMB_TRAN_CREATE(vcp, cr)) != 0) 418 goto errout; 419 420 /* Success! */ 421 smb_co_addchild(&smb_vclist, VCTOCP(vcp)); 422 *vcpp = vcp; 423 return (0); 424 425 errout: 426 /* 427 * This will destroy the new vc. 428 * See: smb_vc_free 429 */ 430 smb_vc_rele(vcp); 431 return (error); 432 } 433 434 /* 435 * Find or create a VC identified by the info in ossn 436 * and return it with a "hold", but not locked. 437 */ 438 /*ARGSUSED*/ 439 int 440 smb_vc_findcreate(smbioc_ossn_t *ossn, smb_cred_t *scred, smb_vc_t **vcpp) 441 { 442 struct smb_connobj *co; 443 struct smb_vc *vcp; 444 smbioc_ssn_ident_t *vc_id; 445 int error; 446 zoneid_t zoneid = getzoneid(); 447 448 *vcpp = vcp = NULL; 449 450 SMB_CO_LOCK(&smb_vclist); 451 452 /* var, head, next_field */ 453 SLIST_FOREACH(co, &smb_vclist.co_children, co_next) { 454 vcp = CPTOVC(co); 455 456 /* 457 * Some things we can check without 458 * holding the lock (those that are 459 * set at creation and never change). 460 */ 461 462 /* VCs in other zones are invisibile. */ 463 if (vcp->vc_zoneid != zoneid) 464 continue; 465 466 /* Also segregate by Unix owner. */ 467 if (vcp->vc_owner != ossn->ssn_owner) 468 continue; 469 470 /* 471 * Compare identifying info: 472 * server address, user, domain 473 * names are case-insensitive 474 */ 475 vc_id = &vcp->vc_ssn.ssn_id; 476 if (bcmp(&vc_id->id_srvaddr, 477 &ossn->ssn_id.id_srvaddr, 478 sizeof (vc_id->id_srvaddr))) 479 continue; 480 if (u8_strcmp(vc_id->id_user, ossn->ssn_id.id_user, 0, 481 U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &error)) 482 continue; 483 if (u8_strcmp(vc_id->id_domain, ossn->ssn_id.id_domain, 0, 484 U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &error)) 485 continue; 486 487 /* 488 * We have a match, but still have to check 489 * the _GONE flag, and do that with a lock. 490 * No new references when _GONE is set. 491 * 492 * Also clear SMBVOPT_CREATE which the caller 493 * may check to find out if we did create. 494 */ 495 SMB_VC_LOCK(vcp); 496 if ((vcp->vc_flags & SMBV_GONE) == 0) { 497 ossn->ssn_vopt &= ~SMBVOPT_CREATE; 498 /* 499 * Return it held, unlocked. 500 * In-line smb_vc_hold here. 501 */ 502 co->co_usecount++; 503 SMB_VC_UNLOCK(vcp); 504 *vcpp = vcp; 505 error = 0; 506 goto out; 507 } 508 SMB_VC_UNLOCK(vcp); 509 /* keep looking. */ 510 } 511 vcp = NULL; 512 513 /* Note: smb_vclist is still locked. */ 514 515 if (ossn->ssn_vopt & SMBVOPT_CREATE) { 516 /* 517 * Create a new VC. It starts out with 518 * hold count = 1, so don't incr. here. 519 */ 520 error = smb_vc_create(ossn, scred, &vcp); 521 if (error == 0) 522 *vcpp = vcp; 523 } else 524 error = ENOENT; 525 526 out: 527 SMB_CO_UNLOCK(&smb_vclist); 528 return (error); 529 } 530 531 532 /* 533 * Helper functions that operate on VCs 534 */ 535 536 /* 537 * Get a pointer to the IP address suitable for passing to Trusted 538 * Extensions find_tpc() routine. Used by smbfs_mount_label_policy(). 539 * Compare this code to nfs_mount_label_policy() if problems arise. 540 */ 541 void * 542 smb_vc_getipaddr(struct smb_vc *vcp, int *ipvers) 543 { 544 smbioc_ssn_ident_t *id = &vcp->vc_ssn.ssn_id; 545 void *ret; 546 547 switch (id->id_srvaddr.sa.sa_family) { 548 case AF_INET: 549 *ipvers = IPV4_VERSION; 550 ret = &id->id_srvaddr.sin.sin_addr; 551 break; 552 553 case AF_INET6: 554 *ipvers = IPV6_VERSION; 555 ret = &id->id_srvaddr.sin6.sin6_addr; 556 break; 557 default: 558 SMBSDEBUG("invalid address family %d\n", 559 id->id_srvaddr.sa.sa_family); 560 *ipvers = 0; 561 ret = NULL; 562 break; 563 } 564 return (ret); 565 } 566 567 void 568 smb_vc_walkshares(struct smb_vc *vcp, 569 walk_share_func_t func) 570 { 571 smb_connobj_t *co; 572 smb_share_t *ssp; 573 574 /* 575 * Walk the share list calling func(ssp, arg) 576 */ 577 SMB_VC_LOCK(vcp); 578 SLIST_FOREACH(co, &(VCTOCP(vcp)->co_children), co_next) { 579 ssp = CPTOSS(co); 580 SMB_SS_LOCK(ssp); 581 func(ssp); 582 SMB_SS_UNLOCK(ssp); 583 } 584 SMB_VC_UNLOCK(vcp); 585 } 586 587 588 /* 589 * Share implementation 590 */ 591 592 void 593 smb_share_hold(struct smb_share *ssp) 594 { 595 smb_co_hold(SSTOCP(ssp)); 596 } 597 598 void 599 smb_share_rele(struct smb_share *ssp) 600 { 601 smb_co_rele(SSTOCP(ssp)); 602 } 603 604 void 605 smb_share_kill(struct smb_share *ssp) 606 { 607 smb_co_kill(SSTOCP(ssp)); 608 } 609 610 /* 611 * Normally called via smb_share_rele() 612 * after co_usecount drops to zero. 613 * Also called via: smb_share_kill() 614 */ 615 static void 616 smb_share_gone(struct smb_connobj *cp) 617 { 618 struct smb_cred scred; 619 struct smb_share *ssp = CPTOSS(cp); 620 621 smb_credinit(&scred, NULL); 622 smb_iod_shutdown_share(ssp); 623 smb_smb_treedisconnect(ssp, &scred); 624 smb_credrele(&scred); 625 } 626 627 /* 628 * Normally called via smb_share_rele() 629 * after co_usecount drops to zero. 630 */ 631 static void 632 smb_share_free(struct smb_connobj *cp) 633 { 634 struct smb_share *ssp = CPTOSS(cp); 635 636 cv_destroy(&ssp->ss_conn_done); 637 smb_co_done(SSTOCP(ssp)); 638 kmem_free(ssp, sizeof (*ssp)); 639 } 640 641 /* 642 * Allocate share structure and attach it to the given VC 643 * Connection expected to be locked on entry. Share will be returned 644 * in locked state. 645 */ 646 /*ARGSUSED*/ 647 int 648 smb_share_create(smbioc_tcon_t *tcon, struct smb_vc *vcp, 649 struct smb_share **sspp, struct smb_cred *scred) 650 { 651 static char objtype[] = "smb_ss"; 652 struct smb_share *ssp; 653 654 ASSERT(MUTEX_HELD(&vcp->vc_lock)); 655 656 ssp = kmem_zalloc(sizeof (struct smb_share), KM_SLEEP); 657 smb_co_init(SSTOCP(ssp), SMBL_SHARE, objtype); 658 ssp->ss_co.co_free = smb_share_free; 659 ssp->ss_co.co_gone = smb_share_gone; 660 661 cv_init(&ssp->ss_conn_done, objtype, CV_DRIVER, NULL); 662 ssp->ss_tid = SMB_TID_UNKNOWN; 663 664 bcopy(&tcon->tc_sh, &ssp->ss_ioc, 665 sizeof (smbioc_oshare_t)); 666 667 smb_co_addchild(VCTOCP(vcp), SSTOCP(ssp)); 668 *sspp = ssp; 669 670 return (0); 671 } 672 673 /* 674 * Find or create a share under the given VC 675 * and return it with a "hold", but not locked. 676 */ 677 678 int 679 smb_share_findcreate(smbioc_tcon_t *tcon, struct smb_vc *vcp, 680 struct smb_share **sspp, struct smb_cred *scred) 681 { 682 struct smb_connobj *co; 683 struct smb_share *ssp = NULL; 684 int error = 0; 685 686 *sspp = NULL; 687 688 SMB_VC_LOCK(vcp); 689 690 /* var, head, next_field */ 691 SLIST_FOREACH(co, &(VCTOCP(vcp)->co_children), co_next) { 692 ssp = CPTOSS(co); 693 694 /* Share name */ 695 if (u8_strcmp(ssp->ss_name, tcon->tc_sh.sh_name, 0, 696 U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &error)) 697 continue; 698 699 /* 700 * We have a match, but still have to check 701 * the _GONE flag, and do that with a lock. 702 * No new references when _GONE is set. 703 * 704 * Also clear SMBSOPT_CREATE which the caller 705 * may check to find out if we did create. 706 */ 707 SMB_SS_LOCK(ssp); 708 if ((ssp->ss_flags & SMBS_GONE) == 0) { 709 tcon->tc_opt &= ~SMBSOPT_CREATE; 710 /* 711 * Return it held, unlocked. 712 * In-line smb_share_hold here. 713 */ 714 co->co_usecount++; 715 SMB_SS_UNLOCK(ssp); 716 *sspp = ssp; 717 error = 0; 718 goto out; 719 } 720 SMB_SS_UNLOCK(ssp); 721 /* keep looking. */ 722 } 723 ssp = NULL; 724 725 /* Note: vcp (list of shares) is still locked. */ 726 727 if (tcon->tc_opt & SMBSOPT_CREATE) { 728 /* 729 * Create a new share. It starts out with 730 * hold count = 1, so don't incr. here. 731 */ 732 error = smb_share_create(tcon, vcp, &ssp, scred); 733 if (error == 0) 734 *sspp = ssp; 735 } else 736 error = ENOENT; 737 738 out: 739 SMB_VC_UNLOCK(vcp); 740 return (error); 741 } 742 743 744 /* 745 * Helper functions that operate on shares 746 */ 747 748 /* 749 * Mark this share as invalid, so consumers will know 750 * their file handles have become invalid. 751 * 752 * Most share consumers store a copy of ss_vcgenid when 753 * opening a file handle and compare that with what's in 754 * the share before using a file handle. If the genid 755 * doesn't match, the file handle has become "stale" 756 * due to disconnect. Therefore, zap ss_vcgenid here. 757 */ 758 void 759 smb_share_invalidate(struct smb_share *ssp) 760 { 761 762 ASSERT(MUTEX_HELD(&ssp->ss_lock)); 763 764 ssp->ss_flags &= ~SMBS_CONNECTED; 765 ssp->ss_tid = SMB_TID_UNKNOWN; 766 ssp->ss_vcgenid = 0; 767 } 768 769 /* 770 * Connect (or reconnect) a share object. 771 * 772 * Called by smb_usr_get_tree() for new connections, 773 * and called by smb_rq_enqueue() for reconnect. 774 */ 775 int 776 smb_share_tcon(smb_share_t *ssp, smb_cred_t *scred) 777 { 778 clock_t tmo; 779 int error; 780 781 SMB_SS_LOCK(ssp); 782 783 if (ssp->ss_flags & SMBS_CONNECTED) { 784 SMBIODEBUG("alread connected?"); 785 error = 0; 786 goto out; 787 } 788 789 /* 790 * Wait for completion of any state changes 791 * that might be underway. 792 */ 793 while (ssp->ss_flags & SMBS_RECONNECTING) { 794 ssp->ss_conn_waiters++; 795 tmo = cv_wait_sig(&ssp->ss_conn_done, &ssp->ss_lock); 796 ssp->ss_conn_waiters--; 797 if (tmo == 0) { 798 /* Interrupt! */ 799 error = EINTR; 800 goto out; 801 } 802 } 803 804 /* Did someone else do it for us? */ 805 if (ssp->ss_flags & SMBS_CONNECTED) { 806 error = 0; 807 goto out; 808 } 809 810 /* 811 * OK, we'll do the work. 812 */ 813 ssp->ss_flags |= SMBS_RECONNECTING; 814 815 /* 816 * Drop the lock while doing the TCON. 817 * On success, sets ss_tid, ss_vcgenid, 818 * and ss_flags |= SMBS_CONNECTED; 819 */ 820 SMB_SS_UNLOCK(ssp); 821 error = smb_smb_treeconnect(ssp, scred); 822 SMB_SS_LOCK(ssp); 823 824 ssp->ss_flags &= ~SMBS_RECONNECTING; 825 826 /* They can all go ahead! */ 827 if (ssp->ss_conn_waiters) 828 cv_broadcast(&ssp->ss_conn_done); 829 830 out: 831 SMB_SS_UNLOCK(ssp); 832 833 return (error); 834 } 835 836 /* 837 * Solaris zones support 838 */ 839 /*ARGSUSED*/ 840 void 841 lingering_vc(struct smb_vc *vc) 842 { 843 /* good place for a breakpoint */ 844 DEBUG_ENTER("lingering VC"); 845 } 846 847 /* 848 * On zone shutdown, kill any IOD threads still running in this zone. 849 */ 850 /* ARGSUSED */ 851 void 852 nsmb_zone_shutdown(zoneid_t zoneid, void *data) 853 { 854 struct smb_connobj *co; 855 struct smb_vc *vcp; 856 857 SMB_CO_LOCK(&smb_vclist); 858 SLIST_FOREACH(co, &smb_vclist.co_children, co_next) { 859 vcp = CPTOVC(co); 860 861 if (vcp->vc_zoneid != zoneid) 862 continue; 863 864 /* 865 * This will close the connection, and 866 * cause the IOD thread to terminate. 867 */ 868 smb_vc_kill(vcp); 869 } 870 SMB_CO_UNLOCK(&smb_vclist); 871 } 872 873 /* 874 * On zone destroy, kill any IOD threads and free all resources they used. 875 */ 876 /* ARGSUSED */ 877 void 878 nsmb_zone_destroy(zoneid_t zoneid, void *data) 879 { 880 struct smb_connobj *co; 881 struct smb_vc *vcp; 882 883 /* 884 * We will repeat what should have already happened 885 * in zone_shutdown to make things go away. 886 * 887 * There should have been an smb_vc_rele call 888 * by now for all VCs in the zone. If not, 889 * there's probably more we needed to do in 890 * the shutdown call. 891 */ 892 893 SMB_CO_LOCK(&smb_vclist); 894 895 if (smb_vclist.co_usecount > 1) { 896 SMBERROR("%d connections still active\n", 897 smb_vclist.co_usecount - 1); 898 } 899 900 /* var, head, next_field */ 901 SLIST_FOREACH(co, &smb_vclist.co_children, co_next) { 902 vcp = CPTOVC(co); 903 904 if (vcp->vc_zoneid != zoneid) 905 continue; 906 907 /* Debugging */ 908 lingering_vc(vcp); 909 } 910 911 SMB_CO_UNLOCK(&smb_vclist); 912 } 913