15331Samw /* 25331Samw * CDDL HEADER START 35331Samw * 45331Samw * The contents of this file are subject to the terms of the 55331Samw * Common Development and Distribution License (the "License"). 65331Samw * You may not use this file except in compliance with the License. 75331Samw * 85331Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95331Samw * or http://www.opensolaris.org/os/licensing. 105331Samw * See the License for the specific language governing permissions 115331Samw * and limitations under the License. 125331Samw * 135331Samw * When distributing Covered Code, include this CDDL HEADER in each 145331Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155331Samw * If applicable, add the following below this CDDL HEADER, with the 165331Samw * fields enclosed by brackets "[]" replaced with your own identifying 175331Samw * information: Portions Copyright [yyyy] [name of copyright owner] 185331Samw * 195331Samw * CDDL HEADER END 205331Samw */ 215331Samw /* 225970Sjb150015 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 235331Samw * Use is subject to license terms. 245331Samw */ 255331Samw 265331Samw 275331Samw #pragma ident "%Z%%M% %I% %E% SMI" 285331Samw 295331Samw #include <sys/types.h> 305331Samw #include <sys/param.h> 315331Samw #include <sys/cpuvar.h> 325331Samw #include <sys/ddi.h> 335331Samw #include <sys/sunddi.h> 345331Samw #include <sys/time.h> 355331Samw #include <sys/varargs.h> 365331Samw #include <sys/modctl.h> 375331Samw #include <sys/pathname.h> 385331Samw #include <sys/fs/snode.h> 395331Samw #include <sys/fs/dv_node.h> 405331Samw #include <sys/vnode.h> 415331Samw #undef mem_free /* XXX Remove this after we convert everything to kmem_alloc */ 425331Samw 435331Samw #include <smbsrv/smb_vops.h> 445331Samw #include <smbsrv/smb.h> 455331Samw #include <smbsrv/mlsvc.h> 465331Samw #include <smbsrv/smb_kproto.h> 47*6496Sjb150015 #include <smbsrv/smb_kstat.h> 48*6496Sjb150015 49*6496Sjb150015 static kmem_cache_t *smb_txr_cache = NULL; 50*6496Sjb150015 51*6496Sjb150015 /* 52*6496Sjb150015 * smb_net_init 53*6496Sjb150015 * 54*6496Sjb150015 * This function initializes the resources necessary to access the 55*6496Sjb150015 * network. It assumes it won't be called simultaneously by multiple 56*6496Sjb150015 * threads. 57*6496Sjb150015 * 58*6496Sjb150015 * Return Value 59*6496Sjb150015 * 60*6496Sjb150015 * 0 Initialization successful 61*6496Sjb150015 * ENOMEM Initialization failed 62*6496Sjb150015 */ 63*6496Sjb150015 int 64*6496Sjb150015 smb_net_init(void) 65*6496Sjb150015 { 66*6496Sjb150015 int rc = 0; 67*6496Sjb150015 68*6496Sjb150015 ASSERT(smb_txr_cache == NULL); 69*6496Sjb150015 70*6496Sjb150015 smb_txr_cache = kmem_cache_create(SMBSRV_KSTAT_TXRCACHE, 71*6496Sjb150015 sizeof (smb_txreq_t), 8, NULL, NULL, NULL, NULL, NULL, 0); 72*6496Sjb150015 if (smb_txr_cache == NULL) 73*6496Sjb150015 rc = ENOMEM; 74*6496Sjb150015 return (rc); 75*6496Sjb150015 } 76*6496Sjb150015 77*6496Sjb150015 /* 78*6496Sjb150015 * smb_net_fini 79*6496Sjb150015 * 80*6496Sjb150015 * This function releases the resources allocated by smb_net_init(). It 81*6496Sjb150015 * assumes it won't be called simultaneously by multiple threads. 82*6496Sjb150015 * This function can safely be called even if smb_net_init() hasn't been 83*6496Sjb150015 * called previously. 84*6496Sjb150015 * 85*6496Sjb150015 * Return Value 86*6496Sjb150015 * 87*6496Sjb150015 * None 88*6496Sjb150015 */ 89*6496Sjb150015 void 90*6496Sjb150015 smb_net_fini(void) 91*6496Sjb150015 { 92*6496Sjb150015 if (smb_txr_cache) { 93*6496Sjb150015 kmem_cache_destroy(smb_txr_cache); 94*6496Sjb150015 smb_txr_cache = NULL; 95*6496Sjb150015 } 96*6496Sjb150015 } 975331Samw 985331Samw /* 995331Samw * SMB Network Socket API 1005331Samw * 1015331Samw * smb_socreate: Creates an socket based on domain/type. 1025331Samw * smb_soshutdown: Disconnect a socket created with smb_socreate 1035331Samw * smb_sodestroy: Release resources associated with a socket 1045331Samw * smb_sosend: Send the contents of a buffer on a socket 1055331Samw * smb_sorecv: Receive data into a buffer from a socket 1065331Samw * smb_iov_sosend: Send the contents of an iovec on a socket 1075331Samw * smb_iov_sorecv: Receive data into an iovec from a socket 1085331Samw */ 1095331Samw 1105331Samw struct sonode * 1115331Samw smb_socreate(int domain, int type, int protocol) 1125331Samw { 1135331Samw vnode_t *dvp = NULL; 1145331Samw vnode_t *vp = NULL; 1155331Samw struct snode *csp = NULL; 1165331Samw int err = 0; 1175331Samw major_t maj; 1185331Samw 1195331Samw if ((vp = solookup(domain, type, protocol, NULL, &err)) == NULL) { 1205331Samw 1215331Samw /* 1225331Samw * solookup calls sogetvp if the vp is not found in the cache. 1235331Samw * Since the call to sogetvp is hardwired to use USERSPACE 1245331Samw * and declared static we'll do the work here instead. 1255331Samw */ 1265331Samw err = lookupname(type == SOCK_STREAM ? "/dev/tcp" : "/dev/udp", 1275331Samw UIO_SYSSPACE, FOLLOW, NULLVPP, &vp); 1285331Samw if (err) 1295331Samw return (NULL); 1305331Samw 1315331Samw /* Check that it is the correct vnode */ 1325331Samw if (vp->v_type != VCHR) { 1335331Samw VN_RELE(vp); 1345331Samw return (NULL); 1355331Samw } 1365331Samw 1375331Samw csp = VTOS(VTOS(vp)->s_commonvp); 1385331Samw if (!(csp->s_flag & SDIPSET)) { 1395331Samw char *pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP); 1405331Samw err = ddi_dev_pathname(vp->v_rdev, S_IFCHR, 1415331Samw pathname); 1425331Samw if (err == 0) { 1435331Samw err = devfs_lookupname(pathname, NULLVPP, 1445331Samw &dvp); 1455331Samw } 1465331Samw VN_RELE(vp); 1475331Samw kmem_free(pathname, MAXPATHLEN); 1485331Samw if (err != 0) { 1495331Samw return (NULL); 1505331Samw } 1515331Samw vp = dvp; 1525331Samw } 1535331Samw 1545331Samw maj = getmajor(vp->v_rdev); 1555331Samw if (!STREAMSTAB(maj)) { 1565331Samw VN_RELE(vp); 1575331Samw return (NULL); 1585331Samw } 1595331Samw } 1605331Samw 1615331Samw return (socreate(vp, domain, type, protocol, SOV_DEFAULT, NULL, &err)); 1625331Samw } 1635331Samw 1645331Samw /* 1655331Samw * smb_soshutdown will disconnect the socket and prevent subsequent PDU 1665331Samw * reception and transmission. The sonode still exists but its state 1675331Samw * gets modified to indicate it is no longer connected. Calls to 1685331Samw * smb_sorecv/smb_iov_sorecv will return so smb_soshutdown can be used 1695331Samw * regain control of a thread stuck in smb_sorecv. 1705331Samw */ 1715331Samw void 1725331Samw smb_soshutdown(struct sonode *so) 1735331Samw { 1745331Samw (void) soshutdown(so, SHUT_RDWR); 1755331Samw } 1765331Samw 1775331Samw /* 1785331Samw * smb_sodestroy releases all resources associated with a socket previously 1795331Samw * created with smb_socreate. The socket must be shutdown using smb_soshutdown 1805331Samw * before the socket is destroyed with smb_sodestroy, otherwise undefined 1815331Samw * behavior will result. 1825331Samw */ 1835331Samw void 1845331Samw smb_sodestroy(struct sonode *so) 1855331Samw { 1865331Samw vnode_t *vp = SOTOV(so); 1875331Samw 1885331Samw (void) VOP_CLOSE(vp, 0, 1, 0, kcred, NULL); 1895331Samw VN_RELE(vp); 1905331Samw } 1915331Samw 1925331Samw int 1935331Samw smb_sorecv(struct sonode *so, void *msg, size_t len) 1945331Samw { 1955331Samw iovec_t iov; 1965331Samw int err; 1975331Samw 1985331Samw ASSERT(so != NULL); 1995331Samw ASSERT(len != 0); 2005331Samw 2015331Samw /* 2025331Samw * Fill in iovec and receive data 2035331Samw */ 2045331Samw iov.iov_base = msg; 2055331Samw iov.iov_len = len; 2065331Samw 2075331Samw if ((err = smb_iov_sorecv(so, &iov, 1, len)) != 0) { 2085331Samw return (err); 2095331Samw } 2105331Samw 2115331Samw /* Successful receive */ 2125331Samw return (0); 2135331Samw } 2145331Samw 2155331Samw /* 2165331Samw * smb_iov_sorecv - Receives an iovec from a connection 2175331Samw * 2185331Samw * This function gets the data asked for from the socket. It will return 2195331Samw * only when all the requested data has been retrieved or if an error 2205331Samw * occurs. 2215331Samw * 2225331Samw * Returns 0 for success, the socket errno value if sorecvmsg fails, and 2235331Samw * -1 if sorecvmsg returns success but uio_resid != 0 2245331Samw */ 2255331Samw int 2265331Samw smb_iov_sorecv(struct sonode *so, iovec_t *iop, int iovlen, size_t total_len) 2275331Samw { 2285331Samw struct msghdr msg; 2295331Samw struct uio uio; 2305331Samw int error; 2315331Samw 2325331Samw ASSERT(iop != NULL); 2335331Samw 2345331Samw /* Initialization of the message header. */ 2355331Samw bzero(&msg, sizeof (msg)); 2365331Samw msg.msg_iov = iop; 2375331Samw msg.msg_flags = MSG_WAITALL; 2385331Samw msg.msg_iovlen = iovlen; 2395331Samw 2405331Samw /* Initialization of the uio structure. */ 2415331Samw bzero(&uio, sizeof (uio)); 2425331Samw uio.uio_iov = iop; 2435331Samw uio.uio_iovcnt = iovlen; 2445331Samw uio.uio_segflg = UIO_SYSSPACE; 2455331Samw uio.uio_resid = total_len; 2465331Samw 2475331Samw if ((error = sorecvmsg(so, &msg, &uio)) == 0) { 2485331Samw /* Received data */ 2495331Samw if (uio.uio_resid == 0) { 2505331Samw /* All requested data received. Success */ 2515331Samw return (0); 2525331Samw } else { 2535331Samw /* Not all data was sent. Failure */ 2545331Samw return (-1); 2555331Samw } 2565331Samw } 2575331Samw 2585331Samw /* Receive failed */ 2595331Samw return (error); 2605331Samw } 2615970Sjb150015 2625970Sjb150015 /* 2635970Sjb150015 * smb_net_txl_constructor 2645970Sjb150015 * 2655970Sjb150015 * Transmit list constructor 2665970Sjb150015 */ 2675970Sjb150015 void 2685970Sjb150015 smb_net_txl_constructor(smb_txlst_t *txl) 2695970Sjb150015 { 2705970Sjb150015 ASSERT(txl->tl_magic != SMB_TXLST_MAGIC); 2715970Sjb150015 2725970Sjb150015 mutex_init(&txl->tl_mutex, NULL, MUTEX_DEFAULT, NULL); 273*6496Sjb150015 list_create(&txl->tl_list, sizeof (smb_txreq_t), 274*6496Sjb150015 offsetof(smb_txreq_t, tr_lnd)); 2755970Sjb150015 txl->tl_active = B_FALSE; 2765970Sjb150015 txl->tl_magic = SMB_TXLST_MAGIC; 2775970Sjb150015 } 2785970Sjb150015 2795970Sjb150015 /* 2805970Sjb150015 * smb_net_txl_destructor 2815970Sjb150015 * 2825970Sjb150015 * Transmit list destructor 2835970Sjb150015 */ 2845970Sjb150015 void 2855970Sjb150015 smb_net_txl_destructor(smb_txlst_t *txl) 2865970Sjb150015 { 2875970Sjb150015 ASSERT(txl->tl_magic == SMB_TXLST_MAGIC); 2885970Sjb150015 2895970Sjb150015 txl->tl_magic = 0; 2905970Sjb150015 list_destroy(&txl->tl_list); 2915970Sjb150015 mutex_destroy(&txl->tl_mutex); 2925970Sjb150015 } 2935970Sjb150015 2945970Sjb150015 /* 295*6496Sjb150015 * smb_net_txr_alloc 2965970Sjb150015 * 2975970Sjb150015 * Transmit buffer allocator 2985970Sjb150015 */ 299*6496Sjb150015 smb_txreq_t * 300*6496Sjb150015 smb_net_txr_alloc(void) 3015970Sjb150015 { 302*6496Sjb150015 smb_txreq_t *txr; 3035970Sjb150015 304*6496Sjb150015 txr = kmem_cache_alloc(smb_txr_cache, KM_SLEEP); 305*6496Sjb150015 txr->tr_len = 0; 306*6496Sjb150015 bzero(&txr->tr_lnd, sizeof (txr->tr_lnd)); 307*6496Sjb150015 txr->tr_magic = SMB_TXREQ_MAGIC; 308*6496Sjb150015 return (txr); 3095970Sjb150015 } 3105970Sjb150015 3115970Sjb150015 /* 312*6496Sjb150015 * smb_net_txr_free 3135970Sjb150015 * 3145970Sjb150015 * Transmit buffer deallocator 3155970Sjb150015 */ 3165970Sjb150015 void 317*6496Sjb150015 smb_net_txr_free(smb_txreq_t *txr) 3185970Sjb150015 { 319*6496Sjb150015 ASSERT(txr->tr_magic == SMB_TXREQ_MAGIC); 320*6496Sjb150015 ASSERT(!list_link_active(&txr->tr_lnd)); 3215970Sjb150015 322*6496Sjb150015 txr->tr_magic = 0; 323*6496Sjb150015 kmem_cache_free(smb_txr_cache, txr); 3245970Sjb150015 } 3255970Sjb150015 3265970Sjb150015 /* 327*6496Sjb150015 * smb_net_txr_send 3285970Sjb150015 * 3295970Sjb150015 * This routine puts the transmit buffer passed in on the wire. If another 3305970Sjb150015 * thread is already draining the transmit list, the transmit buffer is 3315970Sjb150015 * queued and the routine returns immediately. 3325970Sjb150015 */ 3335970Sjb150015 int 334*6496Sjb150015 smb_net_txr_send(struct sonode *so, smb_txlst_t *txl, smb_txreq_t *txr) 3355970Sjb150015 { 3365970Sjb150015 list_t local; 3375970Sjb150015 int rc = 0; 3385970Sjb150015 iovec_t iov; 3395970Sjb150015 struct msghdr msg; 3405970Sjb150015 struct uio uio; 3415970Sjb150015 3425970Sjb150015 ASSERT(txl->tl_magic == SMB_TXLST_MAGIC); 3435970Sjb150015 3445970Sjb150015 mutex_enter(&txl->tl_mutex); 345*6496Sjb150015 list_insert_tail(&txl->tl_list, txr); 3465970Sjb150015 if (txl->tl_active) { 3475970Sjb150015 mutex_exit(&txl->tl_mutex); 3485970Sjb150015 return (0); 3495970Sjb150015 } 350*6496Sjb150015 txl->tl_active = B_TRUE; 3515970Sjb150015 352*6496Sjb150015 list_create(&local, sizeof (smb_txreq_t), 353*6496Sjb150015 offsetof(smb_txreq_t, tr_lnd)); 3545970Sjb150015 3555970Sjb150015 while (!list_is_empty(&txl->tl_list)) { 3565970Sjb150015 list_move_tail(&local, &txl->tl_list); 3575970Sjb150015 mutex_exit(&txl->tl_mutex); 358*6496Sjb150015 while ((txr = list_head(&local)) != NULL) { 359*6496Sjb150015 ASSERT(txr->tr_magic == SMB_TXREQ_MAGIC); 360*6496Sjb150015 list_remove(&local, txr); 3615970Sjb150015 362*6496Sjb150015 iov.iov_base = (void *)txr->tr_buf; 363*6496Sjb150015 iov.iov_len = txr->tr_len; 3645970Sjb150015 3655970Sjb150015 bzero(&msg, sizeof (msg)); 3665970Sjb150015 msg.msg_iov = &iov; 3675970Sjb150015 msg.msg_flags = MSG_WAITALL; 3685970Sjb150015 msg.msg_iovlen = 1; 3695970Sjb150015 3705970Sjb150015 bzero(&uio, sizeof (uio)); 3715970Sjb150015 uio.uio_iov = &iov; 3725970Sjb150015 uio.uio_iovcnt = 1; 3735970Sjb150015 uio.uio_segflg = UIO_SYSSPACE; 374*6496Sjb150015 uio.uio_resid = txr->tr_len; 3755970Sjb150015 3765970Sjb150015 rc = sosendmsg(so, &msg, &uio); 3775970Sjb150015 378*6496Sjb150015 smb_net_txr_free(txr); 3795970Sjb150015 3805970Sjb150015 if ((rc == 0) && (uio.uio_resid == 0)) 381*6496Sjb150015 continue; 3825970Sjb150015 3835970Sjb150015 if (rc == 0) 3845970Sjb150015 rc = -1; 3855970Sjb150015 386*6496Sjb150015 while ((txr = list_head(&local)) != NULL) { 387*6496Sjb150015 ASSERT(txr->tr_magic == SMB_TXREQ_MAGIC); 388*6496Sjb150015 list_remove(&local, txr); 389*6496Sjb150015 smb_net_txr_free(txr); 3905970Sjb150015 } 3915970Sjb150015 break; 3925970Sjb150015 } 3935970Sjb150015 mutex_enter(&txl->tl_mutex); 3945970Sjb150015 if (rc == 0) 3955970Sjb150015 continue; 3965970Sjb150015 397*6496Sjb150015 while ((txr = list_head(&txl->tl_list)) != NULL) { 398*6496Sjb150015 ASSERT(txr->tr_magic == SMB_TXREQ_MAGIC); 399*6496Sjb150015 list_remove(&txl->tl_list, txr); 400*6496Sjb150015 smb_net_txr_free(txr); 4015970Sjb150015 } 4025970Sjb150015 break; 4035970Sjb150015 } 4045970Sjb150015 txl->tl_active = B_FALSE; 4055970Sjb150015 mutex_exit(&txl->tl_mutex); 4065970Sjb150015 return (rc); 4075970Sjb150015 } 408