Home | History | Annotate | Download | only in smbsrv
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #include <sys/types.h>
     27 #include <sys/param.h>
     28 #include <sys/cpuvar.h>
     29 #include <sys/ddi.h>
     30 #include <sys/sunddi.h>
     31 #include <sys/time.h>
     32 #include <sys/varargs.h>
     33 #include <sys/modctl.h>
     34 #include <sys/pathname.h>
     35 #include <sys/fs/snode.h>
     36 #include <sys/fs/dv_node.h>
     37 #include <sys/vnode.h>
     38 #include <sys/ksocket.h>
     39 #undef mem_free /* XXX Remove this after we convert everything to kmem_alloc */
     40 
     41 #include <smbsrv/smb_vops.h>
     42 #include <smbsrv/smb.h>
     43 #include <smbsrv/smb_kproto.h>
     44 #include <smbsrv/smb_kstat.h>
     45 
     46 static	kmem_cache_t	*smb_txr_cache = NULL;
     47 
     48 /*
     49  * smb_net_init
     50  *
     51  *	This function initializes the resources necessary to access the
     52  *	network. It assumes it won't be called simultaneously by multiple
     53  *	threads.
     54  *
     55  * Return Value
     56  *
     57  *	0	Initialization successful
     58  *	ENOMEM	Initialization failed
     59  */
     60 int
     61 smb_net_init(void)
     62 {
     63 	int	rc = 0;
     64 
     65 	ASSERT(smb_txr_cache == NULL);
     66 
     67 	smb_txr_cache = kmem_cache_create(SMBSRV_KSTAT_TXRCACHE,
     68 	    sizeof (smb_txreq_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
     69 	if (smb_txr_cache == NULL)
     70 		rc = ENOMEM;
     71 	return (rc);
     72 }
     73 
     74 /*
     75  * smb_net_fini
     76  *
     77  *	This function releases the resources allocated by smb_net_init(). It
     78  *	assumes it won't be called simultaneously by multiple threads.
     79  *	This function can safely be called even if smb_net_init() hasn't been
     80  *	called previously.
     81  *
     82  * Return Value
     83  *
     84  *	None
     85  */
     86 void
     87 smb_net_fini(void)
     88 {
     89 	if (smb_txr_cache) {
     90 		kmem_cache_destroy(smb_txr_cache);
     91 		smb_txr_cache = NULL;
     92 	}
     93 }
     94 
     95 /*
     96  * SMB Network Socket API
     97  *
     98  * smb_socreate:	Creates an socket based on domain/type.
     99  * smb_soshutdown:	Disconnect a socket created with smb_socreate
    100  * smb_sodestroy:	Release resources associated with a socket
    101  * smb_sosend:		Send the contents of a buffer on a socket
    102  * smb_sorecv:		Receive data into a buffer from a socket
    103  * smb_iov_sosend:	Send the contents of an iovec on a socket
    104  * smb_iov_sorecv:	Receive data into an iovec from a socket
    105  */
    106 
    107 ksocket_t
    108 smb_socreate(int domain, int type, int protocol)
    109 {
    110 	ksocket_t	sock;
    111 	int		err = 0;
    112 
    113 	err = ksocket_socket(&sock, domain, type, protocol, KSOCKET_SLEEP,
    114 	    CRED());
    115 
    116 	if (err != 0)
    117 		return (NULL);
    118 	else
    119 		return (sock);
    120 }
    121 
    122 /*
    123  * smb_soshutdown will disconnect the socket and prevent subsequent PDU
    124  * reception and transmission.  The sonode still exists but its state
    125  * gets modified to indicate it is no longer connected.  Calls to
    126  * smb_sorecv/smb_iov_sorecv will return so smb_soshutdown can be used
    127  * regain control of a thread stuck in smb_sorecv.
    128  */
    129 void
    130 smb_soshutdown(ksocket_t so)
    131 {
    132 	(void) ksocket_shutdown(so, SHUT_RDWR, CRED());
    133 }
    134 
    135 /*
    136  * smb_sodestroy releases all resources associated with a socket previously
    137  * created with smb_socreate.  The socket must be shutdown using smb_soshutdown
    138  * before the socket is destroyed with smb_sodestroy, otherwise undefined
    139  * behavior will result.
    140  */
    141 void
    142 smb_sodestroy(ksocket_t so)
    143 {
    144 	(void) ksocket_close(so, CRED());
    145 }
    146 
    147 int
    148 smb_sorecv(ksocket_t so, void *msg, size_t len)
    149 {
    150 	size_t recvd;
    151 	int err;
    152 
    153 	ASSERT(so != NULL);
    154 	ASSERT(len != 0);
    155 
    156 	if ((err = ksocket_recv(so, msg, len, MSG_WAITALL, &recvd,
    157 	    CRED())) != 0) {
    158 		return (err);
    159 	}
    160 
    161 	/* Successful receive */
    162 	return ((recvd == len) ? 0 : -1);
    163 }
    164 
    165 /*
    166  * smb_net_txl_constructor
    167  *
    168  *	Transmit list constructor
    169  */
    170 void
    171 smb_net_txl_constructor(smb_txlst_t *txl)
    172 {
    173 	ASSERT(txl->tl_magic != SMB_TXLST_MAGIC);
    174 
    175 	mutex_init(&txl->tl_mutex, NULL, MUTEX_DEFAULT, NULL);
    176 	list_create(&txl->tl_list, sizeof (smb_txreq_t),
    177 	    offsetof(smb_txreq_t, tr_lnd));
    178 	txl->tl_active = B_FALSE;
    179 	txl->tl_magic = SMB_TXLST_MAGIC;
    180 }
    181 
    182 /*
    183  * smb_net_txl_destructor
    184  *
    185  *	Transmit list destructor
    186  */
    187 void
    188 smb_net_txl_destructor(smb_txlst_t *txl)
    189 {
    190 	ASSERT(txl->tl_magic == SMB_TXLST_MAGIC);
    191 
    192 	txl->tl_magic = 0;
    193 	list_destroy(&txl->tl_list);
    194 	mutex_destroy(&txl->tl_mutex);
    195 }
    196 
    197 /*
    198  * smb_net_txr_alloc
    199  *
    200  *	Transmit buffer allocator
    201  */
    202 smb_txreq_t *
    203 smb_net_txr_alloc(void)
    204 {
    205 	smb_txreq_t	*txr;
    206 
    207 	txr = kmem_cache_alloc(smb_txr_cache, KM_SLEEP);
    208 	txr->tr_len = 0;
    209 	bzero(&txr->tr_lnd, sizeof (txr->tr_lnd));
    210 	txr->tr_magic = SMB_TXREQ_MAGIC;
    211 	return (txr);
    212 }
    213 
    214 /*
    215  * smb_net_txr_free
    216  *
    217  *	Transmit buffer deallocator
    218  */
    219 void
    220 smb_net_txr_free(smb_txreq_t *txr)
    221 {
    222 	ASSERT(txr->tr_magic == SMB_TXREQ_MAGIC);
    223 	ASSERT(!list_link_active(&txr->tr_lnd));
    224 
    225 	txr->tr_magic = 0;
    226 	kmem_cache_free(smb_txr_cache, txr);
    227 }
    228 
    229 /*
    230  * smb_net_txr_send
    231  *
    232  *	This routine puts the transmit buffer passed in on the wire. If another
    233  *	thread is already draining the transmit list, the transmit buffer is
    234  *	queued and the routine returns immediately.
    235  */
    236 int
    237 smb_net_txr_send(ksocket_t so, smb_txlst_t *txl, smb_txreq_t *txr)
    238 {
    239 	list_t		local;
    240 	int		rc = 0;
    241 	size_t		sent = 0;
    242 	size_t		len;
    243 
    244 	ASSERT(txl->tl_magic == SMB_TXLST_MAGIC);
    245 
    246 	mutex_enter(&txl->tl_mutex);
    247 	list_insert_tail(&txl->tl_list, txr);
    248 	if (txl->tl_active) {
    249 		mutex_exit(&txl->tl_mutex);
    250 		return (0);
    251 	}
    252 	txl->tl_active = B_TRUE;
    253 
    254 	list_create(&local, sizeof (smb_txreq_t),
    255 	    offsetof(smb_txreq_t, tr_lnd));
    256 
    257 	while (!list_is_empty(&txl->tl_list)) {
    258 		list_move_tail(&local, &txl->tl_list);
    259 		mutex_exit(&txl->tl_mutex);
    260 		while ((txr = list_head(&local)) != NULL) {
    261 			ASSERT(txr->tr_magic == SMB_TXREQ_MAGIC);
    262 			list_remove(&local, txr);
    263 
    264 			len = txr->tr_len;
    265 			rc = ksocket_send(so, txr->tr_buf, txr->tr_len,
    266 			    MSG_WAITALL, &sent, CRED());
    267 			smb_net_txr_free(txr);
    268 			if ((rc == 0) && (sent == len))
    269 				continue;
    270 
    271 			if (rc == 0)
    272 				rc = -1;
    273 
    274 			while ((txr = list_head(&local)) != NULL) {
    275 				ASSERT(txr->tr_magic == SMB_TXREQ_MAGIC);
    276 				list_remove(&local, txr);
    277 				smb_net_txr_free(txr);
    278 			}
    279 			break;
    280 		}
    281 		mutex_enter(&txl->tl_mutex);
    282 		if (rc == 0)
    283 			continue;
    284 
    285 		while ((txr = list_head(&txl->tl_list)) != NULL) {
    286 			ASSERT(txr->tr_magic == SMB_TXREQ_MAGIC);
    287 			list_remove(&txl->tl_list, txr);
    288 			smb_net_txr_free(txr);
    289 		}
    290 		break;
    291 	}
    292 	txl->tl_active = B_FALSE;
    293 	mutex_exit(&txl->tl_mutex);
    294 	return (rc);
    295 }
    296