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 * Copyright 2015 Nexenta Systems, Inc. All rights reserved. 26 */ 27 28 #include <sys/types.h> 29 #include <sys/param.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/vnode.h> 37 #include <sys/socket.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 /* 47 * SMB Network Socket API 48 * 49 * smb_socreate: Creates an socket based on domain/type. 50 * smb_soshutdown: Disconnect a socket created with smb_socreate 51 * smb_sodestroy: Release resources associated with a socket 52 * smb_sosend: Send the contents of a buffer on a socket 53 * smb_sorecv: Receive data into a buffer from a socket 54 * smb_iov_sosend: Send the contents of an iovec on a socket 55 * smb_iov_sorecv: Receive data into an iovec from a socket 56 */ 57 58 ksocket_t 59 smb_socreate(int domain, int type, int protocol) 60 { 61 ksocket_t sock; 62 int err = 0; 63 64 err = ksocket_socket(&sock, domain, type, protocol, KSOCKET_SLEEP, 65 CRED()); 66 67 if (err != 0) 68 return (NULL); 69 else 70 return (sock); 71 } 72 73 /* 74 * smb_soshutdown will disconnect the socket and prevent subsequent PDU 75 * reception and transmission. The sonode still exists but its state 76 * gets modified to indicate it is no longer connected. Calls to 77 * smb_sorecv/smb_iov_sorecv will return so smb_soshutdown can be used 78 * regain control of a thread stuck in smb_sorecv. 79 */ 80 void 81 smb_soshutdown(ksocket_t so) 82 { 83 (void) ksocket_shutdown(so, SHUT_RDWR, CRED()); 84 } 85 86 /* 87 * smb_sodestroy releases all resources associated with a socket previously 88 * created with smb_socreate. The socket must be shutdown using smb_soshutdown 89 * before the socket is destroyed with smb_sodestroy, otherwise undefined 90 * behavior will result. 91 */ 92 void 93 smb_sodestroy(ksocket_t so) 94 { 95 (void) ksocket_close(so, CRED()); 96 } 97 98 int 99 smb_sorecv(ksocket_t so, void *msg, size_t len) 100 { 101 size_t recvd; 102 int err; 103 104 ASSERT(so != NULL); 105 ASSERT(len != 0); 106 107 if ((err = ksocket_recv(so, msg, len, MSG_WAITALL, &recvd, 108 CRED())) != 0) { 109 return (err); 110 } 111 112 /* Successful receive */ 113 return ((recvd == len) ? 0 : -1); 114 } 115 116 /* 117 * smb_net_txl_constructor 118 * 119 * Transmit list constructor 120 */ 121 void 122 smb_net_txl_constructor(smb_txlst_t *txl) 123 { 124 ASSERT(txl->tl_magic != SMB_TXLST_MAGIC); 125 126 mutex_init(&txl->tl_mutex, NULL, MUTEX_DEFAULT, NULL); 127 cv_init(&txl->tl_wait_cv, NULL, CV_DEFAULT, NULL); 128 txl->tl_active = B_FALSE; 129 txl->tl_magic = SMB_TXLST_MAGIC; 130 } 131 132 /* 133 * smb_net_txl_destructor 134 * 135 * Transmit list destructor 136 */ 137 void 138 smb_net_txl_destructor(smb_txlst_t *txl) 139 { 140 ASSERT(txl->tl_magic == SMB_TXLST_MAGIC); 141 142 txl->tl_magic = 0; 143 cv_destroy(&txl->tl_wait_cv); 144 mutex_destroy(&txl->tl_mutex); 145 } 146 147 /* 148 * smb_net_send_uio 149 * 150 * This routine puts the transmit buffer passed in on the wire. 151 * If another thread is already sending, block on the CV. 152 */ 153 int 154 smb_net_send_uio(smb_session_t *s, struct uio *uio) 155 { 156 struct msghdr msg; 157 size_t sent; 158 smb_txlst_t *txl = &s->s_txlst; 159 int rc = 0; 160 161 DTRACE_PROBE1(send__wait__start, struct smb_session_t *, s); 162 163 /* 164 * Wait for our turn to send. 165 */ 166 mutex_enter(&txl->tl_mutex); 167 while (txl->tl_active) 168 cv_wait(&txl->tl_wait_cv, &txl->tl_mutex); 169 170 /* 171 * Did the connection close while we waited? 172 */ 173 switch (s->s_state) { 174 case SMB_SESSION_STATE_DISCONNECTED: 175 case SMB_SESSION_STATE_TERMINATED: 176 rc = ENOTCONN; 177 break; 178 default: 179 txl->tl_active = B_TRUE; 180 break; 181 } 182 mutex_exit(&txl->tl_mutex); 183 184 DTRACE_PROBE1(send__wait__done, struct smb_session_t *, s); 185 if (rc != 0) 186 return (rc); 187 188 /* 189 * OK, try to send. 190 * 191 * This should block until we've sent it all, 192 * or given up due to errors (socket closed). 193 */ 194 bzero(&msg, sizeof (msg)); 195 msg.msg_iov = uio->uio_iov; 196 msg.msg_iovlen = uio->uio_iovcnt; 197 while (uio->uio_resid > 0) { 198 rc = ksocket_sendmsg(s->sock, &msg, 0, &sent, CRED()); 199 if (rc != 0) 200 break; 201 uio->uio_resid -= sent; 202 } 203 204 mutex_enter(&txl->tl_mutex); 205 txl->tl_active = B_FALSE; 206 cv_signal(&txl->tl_wait_cv); 207 mutex_exit(&txl->tl_mutex); 208 209 return (rc); 210 } 211