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