xref: /illumos-gate/usr/src/lib/libfakekernel/common/ksocket.c (revision 45ede40b2394db7967e59f19288fae9b62efd4aa)
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 /*
23  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
25  */
26 
27 #include <sys/types.h>
28 #include <sys/systm.h>
29 #include <sys/cred.h>
30 #include <sys/errno.h>
31 #include <sys/socket.h>
32 #include <sys/ksocket.h>
33 #include <sys/debug.h>
34 #include <sys/kmem.h>
35 #include <limits.h>
36 #include <unistd.h>
37 #include <errno.h>
38 #include <umem.h>
39 
40 #define	_KSOCKET_MAGIC 0xabcdef09
41 
42 #define	KSOCKET_VALID(ks) (ks->kso_magic == _KSOCKET_MAGIC)
43 #define	KSTOSO(ks) (ks->kso_fd)
44 
45 #ifndef	SS_CLOSING
46 #define	SS_CLOSING 0x00010000
47 #endif
48 
49 /*
50  * NB: you can't cast this into a sonode like you can with a normal
51  * ksocket_t, but no correct code should ever do that anyway.
52  * The ksocket_t type is opaque to prevent exactly that.
53  */
54 struct __ksocket {
55 	uint32_t kso_magic;
56 	uint32_t kso_count;
57 	uint32_t kso_state;
58 	int kso_fd;
59 	kmutex_t kso_lock;
60 	kcondvar_t kso_closing_cv;
61 };
62 
63 static umem_cache_t *ksocket_cache = NULL;
64 
65 /*ARGSUSED*/
66 static int
67 _ksocket_ctor(void *buf, void *arg, int flags)
68 {
69 	ksocket_t sock = buf;
70 
71 	bzero(sock, sizeof (*sock));
72 	mutex_init(&sock->kso_lock, NULL, MUTEX_DEFAULT, NULL);
73 	cv_init(&sock->kso_closing_cv, NULL, CV_DEFAULT, NULL);
74 	return (0);
75 }
76 
77 /*ARGSUSED*/
78 static void
79 _ksocket_dtor(void *buf, void *arg)
80 {
81 	ksocket_t sock = buf;
82 
83 	mutex_destroy(&sock->kso_lock);
84 	cv_destroy(&sock->kso_closing_cv);
85 }
86 
87 #pragma init(_ksocket_init)
88 int
89 _ksocket_init(void)
90 {
91 	ksocket_cache = umem_cache_create("ksocket",
92 	    sizeof (struct __ksocket), 0,
93 	    _ksocket_ctor, _ksocket_dtor, NULL, NULL, NULL, 0);
94 	VERIFY(ksocket_cache != NULL);
95 	return (0);
96 }
97 
98 #pragma fini(_ksocket_fini)
99 int
100 _ksocket_fini(void)
101 {
102 	umem_cache_destroy(ksocket_cache);
103 	return (0);
104 }
105 
106 static ksocket_t
107 _ksocket_create(int fd)
108 {
109 	ksocket_t ks;
110 
111 	ks = umem_cache_alloc(ksocket_cache, 0);
112 	VERIFY(ks != NULL);
113 	ks->kso_magic = _KSOCKET_MAGIC;
114 	ks->kso_count = 1;
115 	ks->kso_fd = fd;
116 	return (ks);
117 }
118 
119 static void
120 _ksocket_destroy(ksocket_t ks)
121 {
122 	ASSERT(ks->kso_count == 1);
123 	umem_cache_free(ksocket_cache, ks);
124 }
125 
126 int
127 ksocket_socket(ksocket_t *ksp, int domain, int type, int protocol, int flags,
128     struct cred *cr)
129 {
130 	int fd;
131 	ksocket_t ks;
132 
133 	/* All Solaris components should pass a cred for this operation. */
134 	ASSERT(cr != NULL);
135 
136 	ASSERT(flags == KSOCKET_SLEEP || flags == KSOCKET_NOSLEEP);
137 
138 	fd = socket(domain, type, protocol);
139 	if (fd < 0) {
140 		*ksp = NULL;
141 		return (errno);
142 	}
143 
144 	ks = _ksocket_create(fd);
145 	*ksp = ks;
146 	return (0);
147 }
148 
149 /*
150  * This is marked NODIRECT so the main program linking with this library
151  * can provide its own "bind helper" function.  See: fksmbd_ksock.c
152  */
153 /* ARGSUSED */
154 int
155 ksocket_bind_helper(int fd, struct sockaddr *addr, uint_t addrlen)
156 {
157 	return (EACCES);
158 }
159 
160 int
161 ksocket_bind(ksocket_t ks, struct sockaddr *addr, socklen_t addrlen,
162     struct cred *cr)
163 {
164 	int err = 0;
165 
166 	/* All Solaris components should pass a cred for this operation. */
167 	ASSERT(cr != NULL);
168 
169 	if (!KSOCKET_VALID(ks))
170 		return (ENOTSOCK);
171 
172 	if (bind(KSTOSO(ks), addr, addrlen) != 0)
173 		err = errno;
174 
175 	if (err == EACCES) {
176 		err = ksocket_bind_helper(KSTOSO(ks), addr, addrlen);
177 	}
178 
179 	return (err);
180 }
181 
182 int
183 ksocket_listen(ksocket_t ks, int backlog, struct cred *cr)
184 {
185 	/* All Solaris components should pass a cred for this operation. */
186 	ASSERT(cr != NULL);
187 
188 	if (!KSOCKET_VALID(ks))
189 		return (ENOTSOCK);
190 
191 	if (listen(KSTOSO(ks), backlog) != 0)
192 		return (errno);
193 
194 	return (0);
195 }
196 
197 int
198 ksocket_accept(ksocket_t ks, struct sockaddr *addr,
199     socklen_t *addrlenp, ksocket_t *nks, struct cred *cr)
200 {
201 	int fd;
202 
203 	/* All Solaris components should pass a cred for this operation. */
204 	ASSERT(cr != NULL);
205 
206 	*nks = NULL;
207 
208 	if (!KSOCKET_VALID(ks))
209 		return (ENOTSOCK);
210 
211 	if (addr != NULL && addrlenp == NULL)
212 		return (EFAULT);
213 
214 	fd = accept(KSTOSO(ks), addr, addrlenp);
215 	if (fd < 0)
216 		return (errno);
217 
218 	*nks = _ksocket_create(fd);
219 
220 	return (0);
221 }
222 
223 int
224 ksocket_connect(ksocket_t ks, struct sockaddr *addr, socklen_t addrlen,
225     struct cred *cr)
226 {
227 	/* All Solaris components should pass a cred for this operation. */
228 	ASSERT(cr != NULL);
229 
230 	if (!KSOCKET_VALID(ks))
231 		return (ENOTSOCK);
232 
233 	if (connect(KSTOSO(ks), addr, addrlen) != 0)
234 		return (errno);
235 
236 	return (0);
237 }
238 
239 int
240 ksocket_send(ksocket_t ks, void *msg, size_t msglen, int flags,
241     size_t *sent, struct cred *cr)
242 {
243 	ssize_t error;
244 
245 	/* All Solaris components should pass a cred for this operation. */
246 	ASSERT(cr != NULL);
247 
248 	if (!KSOCKET_VALID(ks)) {
249 		if (sent != NULL)
250 			*sent = 0;
251 		return (ENOTSOCK);
252 	}
253 
254 	error = send(KSTOSO(ks), msg, msglen, flags);
255 	if (error < 0) {
256 		if (sent != NULL)
257 			*sent = 0;
258 		return (errno);
259 	}
260 
261 	if (sent != NULL)
262 		*sent = (size_t)error;
263 	return (0);
264 }
265 
266 int
267 ksocket_sendto(ksocket_t ks, void *msg, size_t msglen, int flags,
268     struct sockaddr *name, socklen_t namelen, size_t *sent, struct cred *cr)
269 {
270 	ssize_t error;
271 
272 	/* All Solaris components should pass a cred for this operation. */
273 	ASSERT(cr != NULL);
274 
275 	if (!KSOCKET_VALID(ks)) {
276 		if (sent != NULL)
277 			*sent = 0;
278 		return (ENOTSOCK);
279 	}
280 
281 	error = sendto(KSTOSO(ks), msg, msglen, flags, name, namelen);
282 	if (error < 0) {
283 		if (sent != NULL)
284 			*sent = 0;
285 		return (errno);
286 	}
287 
288 	if (sent != NULL)
289 		*sent = (size_t)error;
290 	return (0);
291 }
292 
293 int
294 ksocket_sendmsg(ksocket_t ks, struct nmsghdr *msg, int flags,
295     size_t *sent, struct cred *cr)
296 {
297 	uio_t uio;
298 	ssize_t len;
299 
300 	/* All Solaris components should pass a cred for this operation. */
301 	ASSERT(cr != NULL);
302 
303 	if (!KSOCKET_VALID(ks)) {
304 		if (sent != NULL)
305 			*sent = 0;
306 		return (ENOTSOCK);
307 	}
308 
309 	/* socksyscalls.c uses MSG_MAXIOVLEN (local macro), both are 16 */
310 	ASSERT3U(msg->msg_iovlen, <=, IOV_MAX);
311 	len = sendmsg(KSTOSO(ks), msg, flags);
312 	if (len < 0) {
313 		if (sent != NULL)
314 			*sent = 0;
315 		return (errno);
316 	}
317 
318 	/*
319 	 * The user-level sendmsg() does NOT update msg->iov like
320 	 * ksocket_sendmsg().  It's unclear whether that's a bug
321 	 * or if that was intentional.  Anyway, update it here.
322 	 */
323 	if (msg->msg_iov != NULL) {
324 		bzero(&uio, sizeof (uio));
325 		uio.uio_iov = msg->msg_iov;
326 		uio.uio_iovcnt = msg->msg_iovlen;
327 		uio.uio_resid = len;
328 
329 		uioskip(&uio, len);
330 		ASSERT(uio.uio_resid == 0);
331 
332 		msg->msg_iov = uio.uio_iov;
333 		msg->msg_iovlen = uio.uio_iovcnt;
334 	}
335 
336 	if (sent != NULL)
337 		*sent = (size_t)len;
338 	return (0);
339 }
340 
341 int
342 ksocket_recv(ksocket_t ks, void *msg, size_t msglen, int flags,
343     size_t *recvd, struct cred *cr)
344 {
345 	ssize_t error;
346 
347 	/* All Solaris components should pass a cred for this operation. */
348 	ASSERT(cr != NULL);
349 
350 	if (!KSOCKET_VALID(ks)) {
351 		if (recvd != NULL)
352 			*recvd = 0;
353 		return (ENOTSOCK);
354 	}
355 
356 	error = recv(KSTOSO(ks), msg, msglen, flags);
357 	if (error < 0) {
358 		if (recvd != NULL)
359 			*recvd = 0;
360 		return (errno);
361 	}
362 
363 	if (recvd != NULL)
364 		*recvd = (size_t)error;
365 	return (0);
366 }
367 
368 int
369 ksocket_recvfrom(ksocket_t ks, void *msg, size_t msglen, int flags,
370     struct sockaddr *name, socklen_t *namelen, size_t *recvd, struct cred *cr)
371 {
372 	ssize_t error;
373 
374 	/* All Solaris components should pass a cred for this operation. */
375 	ASSERT(cr != NULL);
376 
377 	if (!KSOCKET_VALID(ks)) {
378 		if (recvd != NULL)
379 			*recvd = 0;
380 		return (ENOTSOCK);
381 	}
382 
383 	error = recvfrom(KSTOSO(ks), msg, msglen, flags, name, namelen);
384 	if (error != 0) {
385 		if (recvd != NULL)
386 			*recvd = 0;
387 		return (errno);
388 	}
389 
390 	if (recvd != NULL)
391 		*recvd = (ssize_t)error;
392 	return (0);
393 }
394 
395 int
396 ksocket_recvmsg(ksocket_t ks, struct nmsghdr *msg, int flags, size_t *recvd,
397     struct cred *cr)
398 {
399 	ssize_t error;
400 
401 	/* All Solaris components should pass a cred for this operation. */
402 	ASSERT(cr != NULL);
403 
404 	if (!KSOCKET_VALID(ks)) {
405 		if (recvd != NULL)
406 			*recvd = 0;
407 		return (ENOTSOCK);
408 	}
409 
410 	error = recvmsg(KSTOSO(ks), msg, flags);
411 	if (error < 0) {
412 		if (recvd != NULL)
413 			*recvd = 0;
414 		return (errno);
415 	}
416 
417 	if (recvd != NULL)
418 		*recvd = (size_t)error;
419 	return (0);
420 }
421 
422 int
423 ksocket_shutdown(ksocket_t ks, int how, struct cred *cr)
424 {
425 	/* All Solaris components should pass a cred for this operation. */
426 	ASSERT(cr != NULL);
427 
428 	if (!KSOCKET_VALID(ks))
429 		return (ENOTSOCK);
430 
431 	if (shutdown(KSTOSO(ks), how) != 0)
432 		return (errno);
433 
434 	return (0);
435 }
436 
437 int
438 ksocket_close(ksocket_t ks, struct cred *cr)
439 {
440 	int fd;
441 
442 	/* All Solaris components should pass a cred for this operation. */
443 	ASSERT(cr != NULL);
444 
445 	mutex_enter(&ks->kso_lock);
446 
447 	if (!KSOCKET_VALID(ks)) {
448 		mutex_exit(&ks->kso_lock);
449 		return (ENOTSOCK);
450 	}
451 
452 	ks->kso_state |= SS_CLOSING;
453 
454 	/*
455 	 * The real ksocket wakes up everything.
456 	 * It seems the only way we can do that
457 	 * is to go ahead and close the FD.
458 	 */
459 	fd = ks->kso_fd;
460 	ks->kso_fd = -1;
461 	(void) close(fd);
462 
463 	while (ks->kso_count > 1)
464 		cv_wait(&ks->kso_closing_cv, &ks->kso_lock);
465 
466 	mutex_exit(&ks->kso_lock);
467 	_ksocket_destroy(ks);
468 
469 	return (0);
470 }
471 
472 int
473 ksocket_getsockname(ksocket_t ks, struct sockaddr *addr, socklen_t *addrlen,
474     struct cred *cr)
475 {
476 	/* All Solaris components should pass a cred for this operation. */
477 	ASSERT(cr != NULL);
478 
479 	if (!KSOCKET_VALID(ks))
480 		return (ENOTSOCK);
481 
482 	if (addrlen == NULL || (addr == NULL && *addrlen != 0))
483 		return (EFAULT);
484 
485 	if (getsockname(KSTOSO(ks), addr, addrlen) != 0)
486 		return (errno);
487 
488 	return (0);
489 }
490 
491 int
492 ksocket_getpeername(ksocket_t ks, struct sockaddr *addr, socklen_t *addrlen,
493     struct cred *cr)
494 {
495 	/* All Solaris components should pass a cred for this operation. */
496 	ASSERT(cr != NULL);
497 
498 	if (!KSOCKET_VALID(ks))
499 		return (ENOTSOCK);
500 
501 	if (addrlen == NULL || (addr == NULL && *addrlen != 0))
502 		return (EFAULT);
503 
504 	if (getpeername(KSTOSO(ks), addr, addrlen) != 0)
505 		return (errno);
506 
507 	return (0);
508 }
509 
510 int
511 ksocket_setsockopt(ksocket_t ks, int level, int optname, const void *optval,
512     int optlen, struct cred *cr)
513 {
514 	/* All Solaris components should pass a cred for this operation. */
515 	ASSERT(cr != NULL);
516 
517 	if (!KSOCKET_VALID(ks))
518 		return (ENOTSOCK);
519 
520 	if (optval == NULL)
521 		optlen = 0;
522 
523 	if (setsockopt(KSTOSO(ks), level, optname, optval, optlen) != 0)
524 		return (errno);
525 
526 	return (0);
527 }
528 
529 int
530 ksocket_ioctl(ksocket_t ks, int cmd, intptr_t arg, int *rvp, struct cred *cr)
531 {
532 	int rval;
533 
534 	/* All Solaris components should pass a cred for this operation. */
535 	ASSERT(cr != NULL);
536 
537 	if (!KSOCKET_VALID(ks))
538 		return (ENOTSOCK);
539 
540 	rval = ioctl(KSTOSO(ks), cmd, arg);
541 	if (rvp != NULL)
542 		*rvp = rval;
543 
544 	if (rval != 0)
545 		rval = errno;
546 
547 	return (rval);
548 }
549 
550 void
551 ksocket_hold(ksocket_t ks)
552 {
553 	if (!mutex_owned(&ks->kso_lock)) {
554 		mutex_enter(&ks->kso_lock);
555 		ks->kso_count++;
556 		mutex_exit(&ks->kso_lock);
557 	} else
558 		ks->kso_count++;
559 }
560 
561 void
562 ksocket_rele(ksocket_t ks)
563 {
564 	/*
565 	 * When so_count equals 1 means no thread working on this ksocket
566 	 */
567 	VERIFY3U(ks->kso_count, >, 1);
568 
569 	if (!mutex_owned(&ks->kso_lock)) {
570 		mutex_enter(&ks->kso_lock);
571 		if (--ks->kso_count == 1)
572 			cv_signal(&ks->kso_closing_cv);
573 		mutex_exit(&ks->kso_lock);
574 	} else {
575 		if (--ks->kso_count == 1)
576 			cv_signal(&ks->kso_closing_cv);
577 	}
578 }
579