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