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