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