xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_net.c (revision 5db531e3faa94427746eae754b11770fd8416b6d)
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