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