1da6c28aaSamw /*
2da6c28aaSamw * CDDL HEADER START
3da6c28aaSamw *
4da6c28aaSamw * The contents of this file are subject to the terms of the
5da6c28aaSamw * Common Development and Distribution License (the "License").
6da6c28aaSamw * You may not use this file except in compliance with the License.
7da6c28aaSamw *
8da6c28aaSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw * See the License for the specific language governing permissions
11da6c28aaSamw * and limitations under the License.
12da6c28aaSamw *
13da6c28aaSamw * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw *
19da6c28aaSamw * CDDL HEADER END
20da6c28aaSamw */
21da6c28aaSamw /*
225cdbe942Sjb150015 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23da6c28aaSamw * Use is subject to license terms.
24*b819cea2SGordon Ross *
25*b819cea2SGordon Ross * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
26da6c28aaSamw */
27da6c28aaSamw
28da6c28aaSamw #include <sys/types.h>
29da6c28aaSamw #include <sys/param.h>
30da6c28aaSamw #include <sys/ddi.h>
31da6c28aaSamw #include <sys/sunddi.h>
32da6c28aaSamw #include <sys/time.h>
33da6c28aaSamw #include <sys/varargs.h>
34da6c28aaSamw #include <sys/modctl.h>
35da6c28aaSamw #include <sys/pathname.h>
36da6c28aaSamw #include <sys/vnode.h>
37*b819cea2SGordon Ross #include <sys/socket.h>
380f1702c5SYu Xiangning #include <sys/ksocket.h>
39da6c28aaSamw #undef mem_free /* XXX Remove this after we convert everything to kmem_alloc */
40da6c28aaSamw
41da6c28aaSamw #include <smbsrv/smb_vops.h>
42da6c28aaSamw #include <smbsrv/smb.h>
43da6c28aaSamw #include <smbsrv/smb_kproto.h>
4421b7895dSjb150015 #include <smbsrv/smb_kstat.h>
4521b7895dSjb150015
4621b7895dSjb150015 static kmem_cache_t *smb_txr_cache = NULL;
4721b7895dSjb150015
4821b7895dSjb150015 /*
4921b7895dSjb150015 * smb_net_init
5021b7895dSjb150015 *
5121b7895dSjb150015 * This function initializes the resources necessary to access the
5221b7895dSjb150015 * network. It assumes it won't be called simultaneously by multiple
5321b7895dSjb150015 * threads.
5421b7895dSjb150015 *
5521b7895dSjb150015 * Return Value
5621b7895dSjb150015 *
5721b7895dSjb150015 * 0 Initialization successful
5821b7895dSjb150015 * ENOMEM Initialization failed
5921b7895dSjb150015 */
608622ec45SGordon Ross void
smb_net_init(void)6121b7895dSjb150015 smb_net_init(void)
6221b7895dSjb150015 {
6321b7895dSjb150015
648622ec45SGordon Ross if (smb_txr_cache != NULL)
658622ec45SGordon Ross return;
6621b7895dSjb150015
6721b7895dSjb150015 smb_txr_cache = kmem_cache_create(SMBSRV_KSTAT_TXRCACHE,
6821b7895dSjb150015 sizeof (smb_txreq_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
6921b7895dSjb150015 }
7021b7895dSjb150015
7121b7895dSjb150015 /*
7221b7895dSjb150015 * smb_net_fini
7321b7895dSjb150015 *
7421b7895dSjb150015 * This function releases the resources allocated by smb_net_init(). It
7521b7895dSjb150015 * assumes it won't be called simultaneously by multiple threads.
7621b7895dSjb150015 * This function can safely be called even if smb_net_init() hasn't been
7721b7895dSjb150015 * called previously.
7821b7895dSjb150015 *
7921b7895dSjb150015 * Return Value
8021b7895dSjb150015 *
8121b7895dSjb150015 * None
8221b7895dSjb150015 */
8321b7895dSjb150015 void
smb_net_fini(void)8421b7895dSjb150015 smb_net_fini(void)
8521b7895dSjb150015 {
8621b7895dSjb150015 if (smb_txr_cache) {
8721b7895dSjb150015 kmem_cache_destroy(smb_txr_cache);
8821b7895dSjb150015 smb_txr_cache = NULL;
8921b7895dSjb150015 }
9021b7895dSjb150015 }
91da6c28aaSamw
92da6c28aaSamw /*
93da6c28aaSamw * SMB Network Socket API
94da6c28aaSamw *
95da6c28aaSamw * smb_socreate: Creates an socket based on domain/type.
96da6c28aaSamw * smb_soshutdown: Disconnect a socket created with smb_socreate
97da6c28aaSamw * smb_sodestroy: Release resources associated with a socket
98da6c28aaSamw * smb_sosend: Send the contents of a buffer on a socket
99da6c28aaSamw * smb_sorecv: Receive data into a buffer from a socket
100da6c28aaSamw * smb_iov_sosend: Send the contents of an iovec on a socket
101da6c28aaSamw * smb_iov_sorecv: Receive data into an iovec from a socket
102da6c28aaSamw */
103da6c28aaSamw
1040f1702c5SYu Xiangning ksocket_t
smb_socreate(int domain,int type,int protocol)105da6c28aaSamw smb_socreate(int domain, int type, int protocol)
106da6c28aaSamw {
1070f1702c5SYu Xiangning ksocket_t sock;
108da6c28aaSamw int err = 0;
109da6c28aaSamw
1100f1702c5SYu Xiangning err = ksocket_socket(&sock, domain, type, protocol, KSOCKET_SLEEP,
1110f1702c5SYu Xiangning CRED());
112da6c28aaSamw
1130f1702c5SYu Xiangning if (err != 0)
114da6c28aaSamw return (NULL);
1150f1702c5SYu Xiangning else
1160f1702c5SYu Xiangning return (sock);
117da6c28aaSamw }
118da6c28aaSamw
119da6c28aaSamw /*
120da6c28aaSamw * smb_soshutdown will disconnect the socket and prevent subsequent PDU
121da6c28aaSamw * reception and transmission. The sonode still exists but its state
122da6c28aaSamw * gets modified to indicate it is no longer connected. Calls to
123da6c28aaSamw * smb_sorecv/smb_iov_sorecv will return so smb_soshutdown can be used
124da6c28aaSamw * regain control of a thread stuck in smb_sorecv.
125da6c28aaSamw */
126da6c28aaSamw void
smb_soshutdown(ksocket_t so)1270f1702c5SYu Xiangning smb_soshutdown(ksocket_t so)
128da6c28aaSamw {
1290f1702c5SYu Xiangning (void) ksocket_shutdown(so, SHUT_RDWR, CRED());
130da6c28aaSamw }
131da6c28aaSamw
132da6c28aaSamw /*
133da6c28aaSamw * smb_sodestroy releases all resources associated with a socket previously
134da6c28aaSamw * created with smb_socreate. The socket must be shutdown using smb_soshutdown
135da6c28aaSamw * before the socket is destroyed with smb_sodestroy, otherwise undefined
136da6c28aaSamw * behavior will result.
137da6c28aaSamw */
138da6c28aaSamw void
smb_sodestroy(ksocket_t so)1390f1702c5SYu Xiangning smb_sodestroy(ksocket_t so)
140da6c28aaSamw {
1410f1702c5SYu Xiangning (void) ksocket_close(so, CRED());
142da6c28aaSamw }
143da6c28aaSamw
144da6c28aaSamw int
smb_sorecv(ksocket_t so,void * msg,size_t len)1450f1702c5SYu Xiangning smb_sorecv(ksocket_t so, void *msg, size_t len)
146da6c28aaSamw {
1470f1702c5SYu Xiangning size_t recvd;
148da6c28aaSamw int err;
149da6c28aaSamw
150da6c28aaSamw ASSERT(so != NULL);
151da6c28aaSamw ASSERT(len != 0);
152da6c28aaSamw
1530f1702c5SYu Xiangning if ((err = ksocket_recv(so, msg, len, MSG_WAITALL, &recvd,
1540f1702c5SYu Xiangning CRED())) != 0) {
155da6c28aaSamw return (err);
156da6c28aaSamw }
157da6c28aaSamw
158da6c28aaSamw /* Successful receive */
1590f1702c5SYu Xiangning return ((recvd == len) ? 0 : -1);
160da6c28aaSamw }
1615cdbe942Sjb150015
1625cdbe942Sjb150015 /*
1635cdbe942Sjb150015 * smb_net_txl_constructor
1645cdbe942Sjb150015 *
1655cdbe942Sjb150015 * Transmit list constructor
1665cdbe942Sjb150015 */
1675cdbe942Sjb150015 void
smb_net_txl_constructor(smb_txlst_t * txl)1685cdbe942Sjb150015 smb_net_txl_constructor(smb_txlst_t *txl)
1695cdbe942Sjb150015 {
1705cdbe942Sjb150015 ASSERT(txl->tl_magic != SMB_TXLST_MAGIC);
1715cdbe942Sjb150015
1725cdbe942Sjb150015 mutex_init(&txl->tl_mutex, NULL, MUTEX_DEFAULT, NULL);
17321b7895dSjb150015 list_create(&txl->tl_list, sizeof (smb_txreq_t),
17421b7895dSjb150015 offsetof(smb_txreq_t, tr_lnd));
1755cdbe942Sjb150015 txl->tl_active = B_FALSE;
1765cdbe942Sjb150015 txl->tl_magic = SMB_TXLST_MAGIC;
1775cdbe942Sjb150015 }
1785cdbe942Sjb150015
1795cdbe942Sjb150015 /*
1805cdbe942Sjb150015 * smb_net_txl_destructor
1815cdbe942Sjb150015 *
1825cdbe942Sjb150015 * Transmit list destructor
1835cdbe942Sjb150015 */
1845cdbe942Sjb150015 void
smb_net_txl_destructor(smb_txlst_t * txl)1855cdbe942Sjb150015 smb_net_txl_destructor(smb_txlst_t *txl)
1865cdbe942Sjb150015 {
1875cdbe942Sjb150015 ASSERT(txl->tl_magic == SMB_TXLST_MAGIC);
1885cdbe942Sjb150015
1895cdbe942Sjb150015 txl->tl_magic = 0;
1905cdbe942Sjb150015 list_destroy(&txl->tl_list);
1915cdbe942Sjb150015 mutex_destroy(&txl->tl_mutex);
1925cdbe942Sjb150015 }
1935cdbe942Sjb150015
1945cdbe942Sjb150015 /*
19521b7895dSjb150015 * smb_net_txr_alloc
1965cdbe942Sjb150015 *
1975cdbe942Sjb150015 * Transmit buffer allocator
1985cdbe942Sjb150015 */
19921b7895dSjb150015 smb_txreq_t *
smb_net_txr_alloc(void)20021b7895dSjb150015 smb_net_txr_alloc(void)
2015cdbe942Sjb150015 {
20221b7895dSjb150015 smb_txreq_t *txr;
2035cdbe942Sjb150015
20421b7895dSjb150015 txr = kmem_cache_alloc(smb_txr_cache, KM_SLEEP);
20521b7895dSjb150015 txr->tr_len = 0;
20621b7895dSjb150015 bzero(&txr->tr_lnd, sizeof (txr->tr_lnd));
20721b7895dSjb150015 txr->tr_magic = SMB_TXREQ_MAGIC;
20821b7895dSjb150015 return (txr);
2095cdbe942Sjb150015 }
2105cdbe942Sjb150015
2115cdbe942Sjb150015 /*
21221b7895dSjb150015 * smb_net_txr_free
2135cdbe942Sjb150015 *
2145cdbe942Sjb150015 * Transmit buffer deallocator
2155cdbe942Sjb150015 */
2165cdbe942Sjb150015 void
smb_net_txr_free(smb_txreq_t * txr)21721b7895dSjb150015 smb_net_txr_free(smb_txreq_t *txr)
2185cdbe942Sjb150015 {
21921b7895dSjb150015 ASSERT(txr->tr_magic == SMB_TXREQ_MAGIC);
22021b7895dSjb150015 ASSERT(!list_link_active(&txr->tr_lnd));
2215cdbe942Sjb150015
22221b7895dSjb150015 txr->tr_magic = 0;
22321b7895dSjb150015 kmem_cache_free(smb_txr_cache, txr);
2245cdbe942Sjb150015 }
2255cdbe942Sjb150015
2265cdbe942Sjb150015 /*
22721b7895dSjb150015 * smb_net_txr_send
2285cdbe942Sjb150015 *
2295cdbe942Sjb150015 * This routine puts the transmit buffer passed in on the wire. If another
2305cdbe942Sjb150015 * thread is already draining the transmit list, the transmit buffer is
2315cdbe942Sjb150015 * queued and the routine returns immediately.
2325cdbe942Sjb150015 */
2335cdbe942Sjb150015 int
smb_net_txr_send(ksocket_t so,smb_txlst_t * txl,smb_txreq_t * txr)2340f1702c5SYu Xiangning smb_net_txr_send(ksocket_t so, smb_txlst_t *txl, smb_txreq_t *txr)
2355cdbe942Sjb150015 {
2365cdbe942Sjb150015 list_t local;
2375cdbe942Sjb150015 int rc = 0;
2380f1702c5SYu Xiangning size_t sent = 0;
2390f1702c5SYu Xiangning size_t len;
2405cdbe942Sjb150015
2415cdbe942Sjb150015 ASSERT(txl->tl_magic == SMB_TXLST_MAGIC);
2425cdbe942Sjb150015
2435cdbe942Sjb150015 mutex_enter(&txl->tl_mutex);
24421b7895dSjb150015 list_insert_tail(&txl->tl_list, txr);
2455cdbe942Sjb150015 if (txl->tl_active) {
2465cdbe942Sjb150015 mutex_exit(&txl->tl_mutex);
2475cdbe942Sjb150015 return (0);
2485cdbe942Sjb150015 }
2495cdbe942Sjb150015 txl->tl_active = B_TRUE;
25021b7895dSjb150015
25121b7895dSjb150015 list_create(&local, sizeof (smb_txreq_t),
25221b7895dSjb150015 offsetof(smb_txreq_t, tr_lnd));
2535cdbe942Sjb150015
2545cdbe942Sjb150015 while (!list_is_empty(&txl->tl_list)) {
2555cdbe942Sjb150015 list_move_tail(&local, &txl->tl_list);
2565cdbe942Sjb150015 mutex_exit(&txl->tl_mutex);
25721b7895dSjb150015 while ((txr = list_head(&local)) != NULL) {
25821b7895dSjb150015 ASSERT(txr->tr_magic == SMB_TXREQ_MAGIC);
25921b7895dSjb150015 list_remove(&local, txr);
2605cdbe942Sjb150015
2610f1702c5SYu Xiangning len = txr->tr_len;
2620f1702c5SYu Xiangning rc = ksocket_send(so, txr->tr_buf, txr->tr_len,
2630f1702c5SYu Xiangning MSG_WAITALL, &sent, CRED());
26421b7895dSjb150015 smb_net_txr_free(txr);
2650f1702c5SYu Xiangning if ((rc == 0) && (sent == len))
2665cdbe942Sjb150015 continue;
2675cdbe942Sjb150015
2685cdbe942Sjb150015 if (rc == 0)
2695cdbe942Sjb150015 rc = -1;
2705cdbe942Sjb150015
27121b7895dSjb150015 while ((txr = list_head(&local)) != NULL) {
27221b7895dSjb150015 ASSERT(txr->tr_magic == SMB_TXREQ_MAGIC);
27321b7895dSjb150015 list_remove(&local, txr);
27421b7895dSjb150015 smb_net_txr_free(txr);
2755cdbe942Sjb150015 }
2765cdbe942Sjb150015 break;
2775cdbe942Sjb150015 }
2785cdbe942Sjb150015 mutex_enter(&txl->tl_mutex);
2795cdbe942Sjb150015 if (rc == 0)
2805cdbe942Sjb150015 continue;
2815cdbe942Sjb150015
28221b7895dSjb150015 while ((txr = list_head(&txl->tl_list)) != NULL) {
28321b7895dSjb150015 ASSERT(txr->tr_magic == SMB_TXREQ_MAGIC);
28421b7895dSjb150015 list_remove(&txl->tl_list, txr);
28521b7895dSjb150015 smb_net_txr_free(txr);
2865cdbe942Sjb150015 }
2875cdbe942Sjb150015 break;
2885cdbe942Sjb150015 }
2895cdbe942Sjb150015 txl->tl_active = B_FALSE;
2905cdbe942Sjb150015 mutex_exit(&txl->tl_mutex);
2915cdbe942Sjb150015 return (rc);
2925cdbe942Sjb150015 }
293