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 */
54struct __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
63static umem_cache_t *ksocket_cache = NULL;
64
65/*ARGSUSED*/
66static 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*/
78static 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)
88int
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)
99int
100_ksocket_fini(void)
101{
102	umem_cache_destroy(ksocket_cache);
103	return (0);
104}
105
106static 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
119static void
120_ksocket_destroy(ksocket_t ks)
121{
122	ASSERT(ks->kso_count == 1);
123	umem_cache_free(ksocket_cache, ks);
124}
125
126int
127ksocket_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 */
154int
155ksocket_bind_helper(int fd, struct sockaddr *addr, uint_t addrlen)
156{
157	return (EACCES);
158}
159
160int
161ksocket_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
182int
183ksocket_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
197int
198ksocket_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
223int
224ksocket_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
239int
240ksocket_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
266int
267ksocket_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
293int
294ksocket_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
341int
342ksocket_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
368int
369ksocket_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
395int
396ksocket_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
422int
423ksocket_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
437int
438ksocket_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
472int
473ksocket_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
491int
492ksocket_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
510int
511ksocket_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
529int
530ksocket_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
550void
551ksocket_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
561void
562ksocket_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