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