xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_net.c (revision 8348:4137e18bfaf0)
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