xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_net.c (revision da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0)
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 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <sys/param.h>
31 #include <sys/cpuvar.h>
32 #include <sys/ddi.h>
33 #include <sys/sunddi.h>
34 #include <sys/time.h>
35 #include <sys/varargs.h>
36 #include <sys/modctl.h>
37 #include <sys/pathname.h>
38 #include <sys/fs/snode.h>
39 #include <sys/fs/dv_node.h>
40 #include <sys/vnode.h>
41 #undef mem_free /* XXX Remove this after we convert everything to kmem_alloc */
42 
43 #include <smbsrv/smb_vops.h>
44 #include <smbsrv/smb.h>
45 #include <smbsrv/mlsvc.h>
46 #include <smbsrv/smbvar.h>
47 #include <smbsrv/smb_kproto.h>
48 
49 /*
50  * SMB Network Socket API
51  *
52  * smb_socreate:	Creates an socket based on domain/type.
53  * smb_soshutdown:	Disconnect a socket created with smb_socreate
54  * smb_sodestroy:	Release resources associated with a socket
55  * smb_sosend:		Send the contents of a buffer on a socket
56  * smb_sorecv:		Receive data into a buffer from a socket
57  * smb_iov_sosend:	Send the contents of an iovec on a socket
58  * smb_iov_sorecv:	Receive data into an iovec from a socket
59  */
60 
61 struct sonode *
62 smb_socreate(int domain, int type, int protocol)
63 {
64 	vnode_t		*dvp		= NULL;
65 	vnode_t		*vp		= NULL;
66 	struct snode	*csp		= NULL;
67 	int		err		= 0;
68 	major_t		maj;
69 
70 	if ((vp = solookup(domain, type, protocol, NULL, &err)) == NULL) {
71 
72 		/*
73 		 * solookup calls sogetvp if the vp is not found in the cache.
74 		 * Since the call to sogetvp is hardwired to use USERSPACE
75 		 * and declared static we'll do the work here instead.
76 		 */
77 		err = lookupname(type == SOCK_STREAM ? "/dev/tcp" : "/dev/udp",
78 		    UIO_SYSSPACE, FOLLOW, NULLVPP, &vp);
79 		if (err)
80 			return (NULL);
81 
82 		/* Check that it is the correct vnode */
83 		if (vp->v_type != VCHR) {
84 			VN_RELE(vp);
85 			return (NULL);
86 		}
87 
88 		csp = VTOS(VTOS(vp)->s_commonvp);
89 		if (!(csp->s_flag & SDIPSET)) {
90 			char    *pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
91 			err = ddi_dev_pathname(vp->v_rdev, S_IFCHR,
92 			    pathname);
93 			if (err == 0) {
94 				err = devfs_lookupname(pathname, NULLVPP,
95 				    &dvp);
96 			}
97 			VN_RELE(vp);
98 			kmem_free(pathname, MAXPATHLEN);
99 			if (err != 0) {
100 				return (NULL);
101 			}
102 			vp = dvp;
103 		}
104 
105 		maj = getmajor(vp->v_rdev);
106 		if (!STREAMSTAB(maj)) {
107 			VN_RELE(vp);
108 			return (NULL);
109 		}
110 	}
111 
112 	return (socreate(vp, domain, type, protocol, SOV_DEFAULT, NULL, &err));
113 }
114 
115 /*
116  * smb_soshutdown will disconnect the socket and prevent subsequent PDU
117  * reception and transmission.  The sonode still exists but its state
118  * gets modified to indicate it is no longer connected.  Calls to
119  * smb_sorecv/smb_iov_sorecv will return so smb_soshutdown can be used
120  * regain control of a thread stuck in smb_sorecv.
121  */
122 void
123 smb_soshutdown(struct sonode *so)
124 {
125 	(void) soshutdown(so, SHUT_RDWR);
126 }
127 
128 /*
129  * smb_sodestroy releases all resources associated with a socket previously
130  * created with smb_socreate.  The socket must be shutdown using smb_soshutdown
131  * before the socket is destroyed with smb_sodestroy, otherwise undefined
132  * behavior will result.
133  */
134 void
135 smb_sodestroy(struct sonode *so)
136 {
137 	vnode_t *vp = SOTOV(so);
138 
139 	(void) VOP_CLOSE(vp, 0, 1, 0, kcred, NULL);
140 	VN_RELE(vp);
141 }
142 
143 int
144 smb_sosend(struct sonode *so, void *msg, size_t len)
145 {
146 	iovec_t iov;
147 	int err;
148 
149 	ASSERT(so != NULL);
150 	ASSERT(len != 0);
151 
152 	/*
153 	 * Fill in iovec and receive data
154 	 */
155 	iov.iov_base = msg;
156 	iov.iov_len = len;
157 
158 	if ((err = smb_iov_sosend(so, &iov, 1, len)) != 0) {
159 		return (err);
160 	}
161 
162 	/* Successful receive */
163 	return (0);
164 }
165 
166 int
167 smb_sorecv(struct sonode *so, void *msg, size_t len)
168 {
169 	iovec_t iov;
170 	int err;
171 
172 	ASSERT(so != NULL);
173 	ASSERT(len != 0);
174 
175 	/*
176 	 * Fill in iovec and receive data
177 	 */
178 	iov.iov_base = msg;
179 	iov.iov_len = len;
180 
181 	if ((err = smb_iov_sorecv(so, &iov, 1, len)) != 0) {
182 		return (err);
183 	}
184 
185 	/* Successful receive */
186 	return (0);
187 }
188 
189 /*
190  * smb_iov_sosend - Sends an iovec on a connection.
191  *
192  * This function puts the data provided on the wire by calling sosendmsg.
193  * It will return only when all the data has been sent or if an error
194  * occurs.
195  *
196  * Returns 0 for success, the socket errno value if sosendmsg fails, and
197  * -1 if sosendmsg returns success but uio_resid != 0
198  */
199 int
200 smb_iov_sosend(struct sonode *so, iovec_t *iop, int iovlen, size_t total_len)
201 {
202 	struct msghdr		msg;
203 	struct uio		uio;
204 	int			error;
205 
206 	ASSERT(iop != NULL);
207 
208 	/* Initialization of the message header. */
209 	bzero(&msg, sizeof (msg));
210 	msg.msg_iov	= iop;
211 	msg.msg_flags	= MSG_WAITALL;
212 	msg.msg_iovlen	= iovlen;
213 
214 	/* Initialization of the uio structure. */
215 	bzero(&uio, sizeof (uio));
216 	uio.uio_iov	= iop;
217 	uio.uio_iovcnt	= iovlen;
218 	uio.uio_segflg	= UIO_SYSSPACE;
219 	uio.uio_resid	= total_len;
220 
221 	if ((error = sosendmsg(so, &msg, &uio)) == 0) {
222 		/* Data sent */
223 		if (uio.uio_resid == 0) {
224 			/* All data sent.  Success. */
225 			return (0);
226 		} else {
227 			/* Not all data was sent.  Failure */
228 			return (-1);
229 		}
230 	}
231 
232 	/* Send failed */
233 	return (error);
234 }
235 
236 /*
237  * smb_iov_sorecv - Receives an iovec from a connection
238  *
239  * This function gets the data asked for from the socket.  It will return
240  * only when all the requested data has been retrieved or if an error
241  * occurs.
242  *
243  * Returns 0 for success, the socket errno value if sorecvmsg fails, and
244  * -1 if sorecvmsg returns success but uio_resid != 0
245  */
246 int
247 smb_iov_sorecv(struct sonode *so, iovec_t *iop, int iovlen, size_t total_len)
248 {
249 	struct msghdr		msg;
250 	struct uio		uio;
251 	int			error;
252 
253 	ASSERT(iop != NULL);
254 
255 	/* Initialization of the message header. */
256 	bzero(&msg, sizeof (msg));
257 	msg.msg_iov	= iop;
258 	msg.msg_flags	= MSG_WAITALL;
259 	msg.msg_iovlen	= iovlen;
260 
261 	/* Initialization of the uio structure. */
262 	bzero(&uio, sizeof (uio));
263 	uio.uio_iov	= iop;
264 	uio.uio_iovcnt	= iovlen;
265 	uio.uio_segflg	= UIO_SYSSPACE;
266 	uio.uio_resid	= total_len;
267 
268 	if ((error = sorecvmsg(so, &msg, &uio)) == 0) {
269 		/* Received data */
270 		if (uio.uio_resid == 0) {
271 			/* All requested data received.  Success */
272 			return (0);
273 		} else {
274 			/* Not all data was sent.  Failure */
275 			return (-1);
276 		}
277 	}
278 
279 	/* Receive failed */
280 	return (error);
281 }
282