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