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 #include <sys/types.h>
275331Samw #include <sys/param.h>
285331Samw #include <sys/cpuvar.h>
295331Samw #include <sys/ddi.h>
305331Samw #include <sys/sunddi.h>
315331Samw #include <sys/time.h>
325331Samw #include <sys/varargs.h>
335331Samw #include <sys/modctl.h>
345331Samw #include <sys/pathname.h>
355331Samw #include <sys/fs/snode.h>
365331Samw #include <sys/fs/dv_node.h>
375331Samw #include <sys/vnode.h>
38*8348SEric.Yu@Sun.COM #include <sys/ksocket.h>
395331Samw #undef mem_free /* XXX Remove this after we convert everything to kmem_alloc */
405331Samw
415331Samw #include <smbsrv/smb_vops.h>
425331Samw #include <smbsrv/smb.h>
435331Samw #include <smbsrv/smb_kproto.h>
446496Sjb150015 #include <smbsrv/smb_kstat.h>
456496Sjb150015
466496Sjb150015 static kmem_cache_t *smb_txr_cache = NULL;
476496Sjb150015
486496Sjb150015 /*
496496Sjb150015 * smb_net_init
506496Sjb150015 *
516496Sjb150015 * This function initializes the resources necessary to access the
526496Sjb150015 * network. It assumes it won't be called simultaneously by multiple
536496Sjb150015 * threads.
546496Sjb150015 *
556496Sjb150015 * Return Value
566496Sjb150015 *
576496Sjb150015 * 0 Initialization successful
586496Sjb150015 * ENOMEM Initialization failed
596496Sjb150015 */
606496Sjb150015 int
smb_net_init(void)616496Sjb150015 smb_net_init(void)
626496Sjb150015 {
636496Sjb150015 int rc = 0;
646496Sjb150015
656496Sjb150015 ASSERT(smb_txr_cache == NULL);
666496Sjb150015
676496Sjb150015 smb_txr_cache = kmem_cache_create(SMBSRV_KSTAT_TXRCACHE,
686496Sjb150015 sizeof (smb_txreq_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
696496Sjb150015 if (smb_txr_cache == NULL)
706496Sjb150015 rc = ENOMEM;
716496Sjb150015 return (rc);
726496Sjb150015 }
736496Sjb150015
746496Sjb150015 /*
756496Sjb150015 * smb_net_fini
766496Sjb150015 *
776496Sjb150015 * This function releases the resources allocated by smb_net_init(). It
786496Sjb150015 * assumes it won't be called simultaneously by multiple threads.
796496Sjb150015 * This function can safely be called even if smb_net_init() hasn't been
806496Sjb150015 * called previously.
816496Sjb150015 *
826496Sjb150015 * Return Value
836496Sjb150015 *
846496Sjb150015 * None
856496Sjb150015 */
866496Sjb150015 void
smb_net_fini(void)876496Sjb150015 smb_net_fini(void)
886496Sjb150015 {
896496Sjb150015 if (smb_txr_cache) {
906496Sjb150015 kmem_cache_destroy(smb_txr_cache);
916496Sjb150015 smb_txr_cache = NULL;
926496Sjb150015 }
936496Sjb150015 }
945331Samw
955331Samw /*
965331Samw * SMB Network Socket API
975331Samw *
985331Samw * smb_socreate: Creates an socket based on domain/type.
995331Samw * smb_soshutdown: Disconnect a socket created with smb_socreate
1005331Samw * smb_sodestroy: Release resources associated with a socket
1015331Samw * smb_sosend: Send the contents of a buffer on a socket
1025331Samw * smb_sorecv: Receive data into a buffer from a socket
1035331Samw * smb_iov_sosend: Send the contents of an iovec on a socket
1045331Samw * smb_iov_sorecv: Receive data into an iovec from a socket
1055331Samw */
1065331Samw
107*8348SEric.Yu@Sun.COM ksocket_t
smb_socreate(int domain,int type,int protocol)1085331Samw smb_socreate(int domain, int type, int protocol)
1095331Samw {
110*8348SEric.Yu@Sun.COM ksocket_t sock;
111*8348SEric.Yu@Sun.COM int err = 0;
1125331Samw
113*8348SEric.Yu@Sun.COM err = ksocket_socket(&sock, domain, type, protocol, KSOCKET_SLEEP,
114*8348SEric.Yu@Sun.COM CRED());
1155331Samw
116*8348SEric.Yu@Sun.COM if (err != 0)
117*8348SEric.Yu@Sun.COM return (NULL);
118*8348SEric.Yu@Sun.COM else
119*8348SEric.Yu@Sun.COM return (sock);
1205331Samw }
1215331Samw
1225331Samw /*
1235331Samw * smb_soshutdown will disconnect the socket and prevent subsequent PDU
1245331Samw * reception and transmission. The sonode still exists but its state
1255331Samw * gets modified to indicate it is no longer connected. Calls to
1265331Samw * smb_sorecv/smb_iov_sorecv will return so smb_soshutdown can be used
1275331Samw * regain control of a thread stuck in smb_sorecv.
1285331Samw */
1295331Samw void
smb_soshutdown(ksocket_t so)130*8348SEric.Yu@Sun.COM smb_soshutdown(ksocket_t so)
1315331Samw {
132*8348SEric.Yu@Sun.COM (void) ksocket_shutdown(so, SHUT_RDWR, CRED());
1335331Samw }
1345331Samw
1355331Samw /*
1365331Samw * smb_sodestroy releases all resources associated with a socket previously
1375331Samw * created with smb_socreate. The socket must be shutdown using smb_soshutdown
1385331Samw * before the socket is destroyed with smb_sodestroy, otherwise undefined
1395331Samw * behavior will result.
1405331Samw */
1415331Samw void
smb_sodestroy(ksocket_t so)142*8348SEric.Yu@Sun.COM smb_sodestroy(ksocket_t so)
1435331Samw {
144*8348SEric.Yu@Sun.COM (void) ksocket_close(so, CRED());
1455331Samw }
1465331Samw
1475331Samw int
smb_sorecv(ksocket_t so,void * msg,size_t len)148*8348SEric.Yu@Sun.COM smb_sorecv(ksocket_t so, void *msg, size_t len)
1495331Samw {
150*8348SEric.Yu@Sun.COM size_t recvd;
1515331Samw int err;
1525331Samw
1535331Samw ASSERT(so != NULL);
1545331Samw ASSERT(len != 0);
1555331Samw
156*8348SEric.Yu@Sun.COM if ((err = ksocket_recv(so, msg, len, MSG_WAITALL, &recvd,
157*8348SEric.Yu@Sun.COM CRED())) != 0) {
1585331Samw return (err);
1595331Samw }
1605331Samw
1615331Samw /* Successful receive */
162*8348SEric.Yu@Sun.COM return ((recvd == len) ? 0 : -1);
1635331Samw }
1645970Sjb150015
1655970Sjb150015 /*
1665970Sjb150015 * smb_net_txl_constructor
1675970Sjb150015 *
1685970Sjb150015 * Transmit list constructor
1695970Sjb150015 */
1705970Sjb150015 void
smb_net_txl_constructor(smb_txlst_t * txl)1715970Sjb150015 smb_net_txl_constructor(smb_txlst_t *txl)
1725970Sjb150015 {
1735970Sjb150015 ASSERT(txl->tl_magic != SMB_TXLST_MAGIC);
1745970Sjb150015
1755970Sjb150015 mutex_init(&txl->tl_mutex, NULL, MUTEX_DEFAULT, NULL);
1766496Sjb150015 list_create(&txl->tl_list, sizeof (smb_txreq_t),
1776496Sjb150015 offsetof(smb_txreq_t, tr_lnd));
1785970Sjb150015 txl->tl_active = B_FALSE;
1795970Sjb150015 txl->tl_magic = SMB_TXLST_MAGIC;
1805970Sjb150015 }
1815970Sjb150015
1825970Sjb150015 /*
1835970Sjb150015 * smb_net_txl_destructor
1845970Sjb150015 *
1855970Sjb150015 * Transmit list destructor
1865970Sjb150015 */
1875970Sjb150015 void
smb_net_txl_destructor(smb_txlst_t * txl)1885970Sjb150015 smb_net_txl_destructor(smb_txlst_t *txl)
1895970Sjb150015 {
1905970Sjb150015 ASSERT(txl->tl_magic == SMB_TXLST_MAGIC);
1915970Sjb150015
1925970Sjb150015 txl->tl_magic = 0;
1935970Sjb150015 list_destroy(&txl->tl_list);
1945970Sjb150015 mutex_destroy(&txl->tl_mutex);
1955970Sjb150015 }
1965970Sjb150015
1975970Sjb150015 /*
1986496Sjb150015 * smb_net_txr_alloc
1995970Sjb150015 *
2005970Sjb150015 * Transmit buffer allocator
2015970Sjb150015 */
2026496Sjb150015 smb_txreq_t *
smb_net_txr_alloc(void)2036496Sjb150015 smb_net_txr_alloc(void)
2045970Sjb150015 {
2056496Sjb150015 smb_txreq_t *txr;
2065970Sjb150015
2076496Sjb150015 txr = kmem_cache_alloc(smb_txr_cache, KM_SLEEP);
2086496Sjb150015 txr->tr_len = 0;
2096496Sjb150015 bzero(&txr->tr_lnd, sizeof (txr->tr_lnd));
2106496Sjb150015 txr->tr_magic = SMB_TXREQ_MAGIC;
2116496Sjb150015 return (txr);
2125970Sjb150015 }
2135970Sjb150015
2145970Sjb150015 /*
2156496Sjb150015 * smb_net_txr_free
2165970Sjb150015 *
2175970Sjb150015 * Transmit buffer deallocator
2185970Sjb150015 */
2195970Sjb150015 void
smb_net_txr_free(smb_txreq_t * txr)2206496Sjb150015 smb_net_txr_free(smb_txreq_t *txr)
2215970Sjb150015 {
2226496Sjb150015 ASSERT(txr->tr_magic == SMB_TXREQ_MAGIC);
2236496Sjb150015 ASSERT(!list_link_active(&txr->tr_lnd));
2245970Sjb150015
2256496Sjb150015 txr->tr_magic = 0;
2266496Sjb150015 kmem_cache_free(smb_txr_cache, txr);
2275970Sjb150015 }
2285970Sjb150015
2295970Sjb150015 /*
2306496Sjb150015 * smb_net_txr_send
2315970Sjb150015 *
2325970Sjb150015 * This routine puts the transmit buffer passed in on the wire. If another
2335970Sjb150015 * thread is already draining the transmit list, the transmit buffer is
2345970Sjb150015 * queued and the routine returns immediately.
2355970Sjb150015 */
2365970Sjb150015 int
smb_net_txr_send(ksocket_t so,smb_txlst_t * txl,smb_txreq_t * txr)237*8348SEric.Yu@Sun.COM smb_net_txr_send(ksocket_t so, smb_txlst_t *txl, smb_txreq_t *txr)
2385970Sjb150015 {
2395970Sjb150015 list_t local;
2405970Sjb150015 int rc = 0;
241*8348SEric.Yu@Sun.COM size_t sent = 0;
242*8348SEric.Yu@Sun.COM size_t len;
2435970Sjb150015
2445970Sjb150015 ASSERT(txl->tl_magic == SMB_TXLST_MAGIC);
2455970Sjb150015
2465970Sjb150015 mutex_enter(&txl->tl_mutex);
2476496Sjb150015 list_insert_tail(&txl->tl_list, txr);
2485970Sjb150015 if (txl->tl_active) {
2495970Sjb150015 mutex_exit(&txl->tl_mutex);
2505970Sjb150015 return (0);
2515970Sjb150015 }
2526496Sjb150015 txl->tl_active = B_TRUE;
2535970Sjb150015
2546496Sjb150015 list_create(&local, sizeof (smb_txreq_t),
2556496Sjb150015 offsetof(smb_txreq_t, tr_lnd));
2565970Sjb150015
2575970Sjb150015 while (!list_is_empty(&txl->tl_list)) {
2585970Sjb150015 list_move_tail(&local, &txl->tl_list);
2595970Sjb150015 mutex_exit(&txl->tl_mutex);
2606496Sjb150015 while ((txr = list_head(&local)) != NULL) {
2616496Sjb150015 ASSERT(txr->tr_magic == SMB_TXREQ_MAGIC);
2626496Sjb150015 list_remove(&local, txr);
2635970Sjb150015
264*8348SEric.Yu@Sun.COM len = txr->tr_len;
265*8348SEric.Yu@Sun.COM rc = ksocket_send(so, txr->tr_buf, txr->tr_len,
266*8348SEric.Yu@Sun.COM MSG_WAITALL, &sent, CRED());
2676496Sjb150015 smb_net_txr_free(txr);
268*8348SEric.Yu@Sun.COM if ((rc == 0) && (sent == len))
2696496Sjb150015 continue;
2705970Sjb150015
2715970Sjb150015 if (rc == 0)
2725970Sjb150015 rc = -1;
2735970Sjb150015
2746496Sjb150015 while ((txr = list_head(&local)) != NULL) {
2756496Sjb150015 ASSERT(txr->tr_magic == SMB_TXREQ_MAGIC);
2766496Sjb150015 list_remove(&local, txr);
2776496Sjb150015 smb_net_txr_free(txr);
2785970Sjb150015 }
2795970Sjb150015 break;
2805970Sjb150015 }
2815970Sjb150015 mutex_enter(&txl->tl_mutex);
2825970Sjb150015 if (rc == 0)
2835970Sjb150015 continue;
2845970Sjb150015
2856496Sjb150015 while ((txr = list_head(&txl->tl_list)) != NULL) {
2866496Sjb150015 ASSERT(txr->tr_magic == SMB_TXREQ_MAGIC);
2876496Sjb150015 list_remove(&txl->tl_list, txr);
2886496Sjb150015 smb_net_txr_free(txr);
2895970Sjb150015 }
2905970Sjb150015 break;
2915970Sjb150015 }
2925970Sjb150015 txl->tl_active = B_FALSE;
2935970Sjb150015 mutex_exit(&txl->tl_mutex);
2945970Sjb150015 return (rc);
2955970Sjb150015 }
296