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 } 1044