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
smb_socreate(int domain,int type,int protocol)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
smb_soshutdown(ksocket_t so)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
smb_sodestroy(ksocket_t so)93 smb_sodestroy(ksocket_t so)
94 {
95 (void) ksocket_close(so, CRED());
96 }
97
98 int
smb_sorecv(ksocket_t so,void * msg,size_t len)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
smb_net_txl_constructor(smb_txlst_t * txl)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
smb_net_txl_destructor(smb_txlst_t * txl)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
smb_net_send_uio(smb_session_t * s,struct uio * uio)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