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
_ksocket_ctor(void * buf,void * arg,int flags)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
_ksocket_dtor(void * buf,void * arg)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
_ksocket_init(void)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
_ksocket_fini(void)100 _ksocket_fini(void)
101 {
102 umem_cache_destroy(ksocket_cache);
103 return (0);
104 }
105
106 static ksocket_t
_ksocket_create(int fd)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
_ksocket_destroy(ksocket_t ks)120 _ksocket_destroy(ksocket_t ks)
121 {
122 ASSERT(ks->kso_count == 1);
123 umem_cache_free(ksocket_cache, ks);
124 }
125
126 int
ksocket_socket(ksocket_t * ksp,int domain,int type,int protocol,int flags,struct cred * cr)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
ksocket_bind_helper(int fd,struct sockaddr * addr,uint_t addrlen)155 ksocket_bind_helper(int fd, struct sockaddr *addr, uint_t addrlen)
156 {
157 return (EACCES);
158 }
159
160 int
ksocket_bind(ksocket_t ks,struct sockaddr * addr,socklen_t addrlen,struct cred * cr)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
ksocket_listen(ksocket_t ks,int backlog,struct cred * cr)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
ksocket_accept(ksocket_t ks,struct sockaddr * addr,socklen_t * addrlenp,ksocket_t * nks,struct cred * cr)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
ksocket_connect(ksocket_t ks,struct sockaddr * addr,socklen_t addrlen,struct cred * cr)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
ksocket_send(ksocket_t ks,void * msg,size_t msglen,int flags,size_t * sent,struct cred * cr)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
ksocket_sendto(ksocket_t ks,void * msg,size_t msglen,int flags,struct sockaddr * name,socklen_t namelen,size_t * sent,struct cred * cr)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
ksocket_sendmsg(ksocket_t ks,struct nmsghdr * msg,int flags,size_t * sent,struct cred * cr)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
ksocket_recv(ksocket_t ks,void * msg,size_t msglen,int flags,size_t * recvd,struct cred * cr)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
ksocket_recvfrom(ksocket_t ks,void * msg,size_t msglen,int flags,struct sockaddr * name,socklen_t * namelen,size_t * recvd,struct cred * cr)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
ksocket_recvmsg(ksocket_t ks,struct nmsghdr * msg,int flags,size_t * recvd,struct cred * cr)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
ksocket_shutdown(ksocket_t ks,int how,struct cred * cr)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
ksocket_close(ksocket_t ks,struct cred * cr)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
ksocket_getsockname(ksocket_t ks,struct sockaddr * addr,socklen_t * addrlen,struct cred * cr)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
ksocket_getpeername(ksocket_t ks,struct sockaddr * addr,socklen_t * addrlen,struct cred * cr)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
ksocket_setsockopt(ksocket_t ks,int level,int optname,const void * optval,int optlen,struct cred * cr)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
ksocket_ioctl(ksocket_t ks,int cmd,intptr_t arg,int * rvp,struct cred * cr)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
ksocket_hold(ksocket_t ks)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
ksocket_rele(ksocket_t ks)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