xref: /illumos-gate/usr/src/uts/common/io/ksocket/ksocket.c (revision 20a7641f9918de8574b8b3b47dbe35c4bfc78df1)
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 2011 Nexenta Systems, Inc.  All rights reserved.
24  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
25  * Copyright 2015, Joyent, Inc.
26  * Copyright 2022 Garrett D'Amore
27  */
28 
29 #include <sys/file.h>
30 #include <sys/stropts.h>
31 #include <sys/socket.h>
32 #include <sys/socketvar.h>
33 #include <sys/sysmacros.h>
34 #include <sys/filio.h>		/* FIO* ioctls */
35 #include <sys/sockio.h>		/* SIOC* ioctls */
36 #include <sys/poll_impl.h>
37 #include <sys/cmn_err.h>
38 #include <sys/ksocket.h>
39 #include <io/ksocket/ksocket_impl.h>
40 #include <fs/sockfs/sockcommon.h>
41 
42 #define	SOCKETMOD_TCP	"tcp"
43 #define	SOCKETMOD_UDP	"udp"
44 /*
45  * Kernel Sockets
46  *
47  * Mostly a wrapper around the private socket_* functions.
48  */
49 int
50 ksocket_socket(ksocket_t *ksp, int domain, int type, int protocol, int flags,
51     struct cred *cr)
52 {
53 	static const int version = SOV_DEFAULT;
54 	int error = 0;
55 	struct sonode *so;
56 	*ksp = NULL;
57 
58 	/* All Solaris components should pass a cred for this operation. */
59 	ASSERT(cr != NULL);
60 
61 	ASSERT(flags == KSOCKET_SLEEP || flags == KSOCKET_NOSLEEP);
62 	so = socket_create(domain, type, protocol, NULL, NULL, version, flags,
63 	    cr, &error);
64 	if (so == NULL) {
65 		if (error == EAFNOSUPPORT) {
66 			char *mod = NULL;
67 
68 			/*
69 			 * Could be that root file system is not loaded or
70 			 * soconfig has not run yet.
71 			 */
72 			if (type == SOCK_STREAM && (domain == AF_INET ||
73 			    domain == AF_INET6) && (protocol == 0 ||
74 			    protocol == IPPROTO_TCP)) {
75 					mod = SOCKETMOD_TCP;
76 			} else if (type == SOCK_DGRAM && (domain == AF_INET ||
77 			    domain == AF_INET6) && (protocol == 0 ||
78 			    protocol == IPPROTO_UDP)) {
79 					mod = SOCKETMOD_UDP;
80 			} else {
81 				return (EAFNOSUPPORT);
82 			}
83 
84 			so = socket_create(domain, type, protocol, NULL,
85 			    mod, version, flags, cr, &error);
86 			if (so == NULL)
87 				return (error);
88 		} else {
89 			return (error);
90 		}
91 	}
92 
93 	so->so_mode |= SM_KERNEL;
94 
95 	*ksp = SOTOKS(so);
96 
97 	return (0);
98 }
99 int
100 ksocket_bind(ksocket_t ks, struct sockaddr *addr, socklen_t addrlen,
101     struct cred *cr)
102 {
103 	int error;
104 
105 	/* All Solaris components should pass a cred for this operation. */
106 	ASSERT(cr != NULL);
107 
108 	if (!KSOCKET_VALID(ks))
109 		return (ENOTSOCK);
110 
111 	error = socket_bind(KSTOSO(ks), addr, addrlen, _SOBIND_SOCKBSD, cr);
112 
113 	return (error);
114 }
115 
116 int
117 ksocket_listen(ksocket_t ks, int backlog, struct cred *cr)
118 {
119 	/* All Solaris components should pass a cred for this operation. */
120 	ASSERT(cr != NULL);
121 
122 	if (!KSOCKET_VALID(ks))
123 		return (ENOTSOCK);
124 
125 	return (socket_listen(KSTOSO(ks), backlog, cr));
126 }
127 
128 int
129 ksocket_accept(ksocket_t ks, struct sockaddr *addr,
130     socklen_t *addrlenp, ksocket_t *nks, struct cred *cr)
131 {
132 	int error;
133 	struct sonode *nso = NULL;
134 
135 	/* All Solaris components should pass a cred for this operation. */
136 	ASSERT(cr != NULL);
137 
138 	*nks = NULL;
139 
140 	if (!KSOCKET_VALID(ks))
141 		return (ENOTSOCK);
142 
143 	if (addr != NULL && addrlenp == NULL)
144 		return (EFAULT);
145 
146 	error = socket_accept(KSTOSO(ks), KSOCKET_FMODE(ks), cr, &nso);
147 	if (error != 0)
148 		return (error);
149 
150 	ASSERT(nso != NULL);
151 
152 	nso->so_mode |= SM_KERNEL;
153 
154 	if (addr != NULL && addrlenp != NULL) {
155 		error = socket_getpeername(nso, addr, addrlenp, B_TRUE, cr);
156 		if (error != 0) {
157 			(void) socket_close(nso, 0, cr);
158 			socket_destroy(nso);
159 			return ((error == ENOTCONN) ? ECONNABORTED : error);
160 		}
161 	}
162 
163 	*nks = SOTOKS(nso);
164 
165 	return (error);
166 }
167 
168 int
169 ksocket_connect(ksocket_t ks, struct sockaddr *addr, socklen_t addrlen,
170     struct cred *cr)
171 {
172 	/* All Solaris components should pass a cred for this operation. */
173 	ASSERT(cr != NULL);
174 
175 	if (!KSOCKET_VALID(ks))
176 		return (ENOTSOCK);
177 
178 	return (socket_connect(KSTOSO(ks), addr, addrlen,
179 	    KSOCKET_FMODE(ks), 0, cr));
180 }
181 
182 int
183 ksocket_send(ksocket_t ks, void *msg, size_t msglen, int flags,
184     size_t *sent, struct cred *cr)
185 {
186 	int error;
187 	struct nmsghdr msghdr;
188 	struct uio auio;
189 	struct iovec iov;
190 
191 	/* All Solaris components should pass a cred for this operation. */
192 	ASSERT(cr != NULL);
193 
194 	if (!KSOCKET_VALID(ks)) {
195 		if (sent != NULL)
196 			*sent = 0;
197 		return (ENOTSOCK);
198 	}
199 
200 	iov.iov_base = msg;
201 	iov.iov_len = msglen;
202 
203 	bzero(&auio, sizeof (struct uio));
204 	auio.uio_loffset = 0;
205 	auio.uio_iov = &iov;
206 	auio.uio_iovcnt = 1;
207 	auio.uio_resid = msglen;
208 	if (flags & MSG_USERSPACE)
209 		auio.uio_segflg = UIO_USERSPACE;
210 	else
211 		auio.uio_segflg = UIO_SYSSPACE;
212 	auio.uio_extflg = UIO_COPY_DEFAULT;
213 	auio.uio_limit = 0;
214 	auio.uio_fmode = KSOCKET_FMODE(ks);
215 
216 	msghdr.msg_name = NULL;
217 	msghdr.msg_namelen = 0;
218 	msghdr.msg_control = NULL;
219 	msghdr.msg_controllen = 0;
220 	msghdr.msg_flags = flags | MSG_EOR;
221 
222 	error = socket_sendmsg(KSTOSO(ks), &msghdr, &auio, cr);
223 	if (error != 0) {
224 		if (sent != NULL)
225 			*sent = 0;
226 		return (error);
227 	}
228 
229 	if (sent != NULL)
230 		*sent = msglen - auio.uio_resid;
231 	return (0);
232 }
233 
234 int
235 ksocket_sendto(ksocket_t ks, void *msg, size_t msglen, int flags,
236     struct sockaddr *name, socklen_t namelen, size_t *sent, struct cred *cr)
237 {
238 	int error;
239 	struct nmsghdr msghdr;
240 	struct uio auio;
241 	struct iovec iov;
242 
243 	/* All Solaris components should pass a cred for this operation. */
244 	ASSERT(cr != NULL);
245 
246 	if (!KSOCKET_VALID(ks)) {
247 		if (sent != NULL)
248 			*sent = 0;
249 		return (ENOTSOCK);
250 	}
251 
252 	iov.iov_base = msg;
253 	iov.iov_len = msglen;
254 
255 	bzero(&auio, sizeof (struct uio));
256 	auio.uio_loffset = 0;
257 	auio.uio_iov = &iov;
258 	auio.uio_iovcnt = 1;
259 	auio.uio_resid = msglen;
260 	if (flags & MSG_USERSPACE)
261 		auio.uio_segflg = UIO_USERSPACE;
262 	else
263 		auio.uio_segflg = UIO_SYSSPACE;
264 	auio.uio_extflg = UIO_COPY_DEFAULT;
265 	auio.uio_limit = 0;
266 	auio.uio_fmode = KSOCKET_FMODE(ks);
267 
268 	msghdr.msg_iov = &iov;
269 	msghdr.msg_iovlen = 1;
270 	msghdr.msg_name = (char *)name;
271 	msghdr.msg_namelen = namelen;
272 	msghdr.msg_control = NULL;
273 	msghdr.msg_controllen = 0;
274 	msghdr.msg_flags = flags | MSG_EOR;
275 
276 	error = socket_sendmsg(KSTOSO(ks), &msghdr, &auio, cr);
277 	if (error != 0) {
278 		if (sent != NULL)
279 			*sent = 0;
280 		return (error);
281 	}
282 	if (sent != NULL)
283 		*sent = msglen - auio.uio_resid;
284 	return (0);
285 }
286 
287 int
288 ksocket_sendmsg(ksocket_t ks, struct nmsghdr *msg, int flags,
289     size_t *sent, struct cred *cr)
290 {
291 	int error;
292 	ssize_t len;
293 	int i;
294 	struct uio auio;
295 
296 	/* All Solaris components should pass a cred for this operation. */
297 	ASSERT(cr != NULL);
298 
299 	if (!KSOCKET_VALID(ks)) {
300 		if (sent != NULL)
301 			*sent = 0;
302 		return (ENOTSOCK);
303 	}
304 
305 	bzero(&auio, sizeof (struct uio));
306 	auio.uio_loffset = 0;
307 	auio.uio_iov = msg->msg_iov;
308 	auio.uio_iovcnt = msg->msg_iovlen;
309 	if (flags & MSG_USERSPACE)
310 		auio.uio_segflg = UIO_USERSPACE;
311 	else
312 		auio.uio_segflg = UIO_SYSSPACE;
313 	auio.uio_extflg = UIO_COPY_DEFAULT;
314 	auio.uio_limit = 0;
315 	auio.uio_fmode = KSOCKET_FMODE(ks);
316 	len = 0;
317 	for (i = 0; i < msg->msg_iovlen; i++) {
318 		ssize_t iovlen;
319 		iovlen = (msg->msg_iov)[i].iov_len;
320 		len += iovlen;
321 		if (len < 0 || iovlen < 0)
322 			return (EINVAL);
323 	}
324 	auio.uio_resid = len;
325 
326 	msg->msg_flags = flags | MSG_EOR;
327 
328 	error = socket_sendmsg(KSTOSO(ks), msg, &auio, cr);
329 	if (error != 0) {
330 		if (sent != NULL)
331 			*sent = 0;
332 		return (error);
333 	}
334 
335 	if (sent != NULL)
336 		*sent = len - auio.uio_resid;
337 	return (0);
338 }
339 
340 
341 int
342 ksocket_recv(ksocket_t ks, void *msg, size_t msglen, int flags,
343     size_t *recv, struct cred *cr)
344 {
345 	int error;
346 	struct nmsghdr msghdr;
347 	struct uio auio;
348 	struct iovec iov;
349 
350 	/* All Solaris components should pass a cred for this operation. */
351 	ASSERT(cr != NULL);
352 
353 	if (!KSOCKET_VALID(ks)) {
354 		if (recv != NULL)
355 			*recv = 0;
356 		return (ENOTSOCK);
357 	}
358 
359 	iov.iov_base = msg;
360 	iov.iov_len = msglen;
361 
362 	bzero(&auio, sizeof (struct uio));
363 	auio.uio_loffset = 0;
364 	auio.uio_iov = &iov;
365 	auio.uio_iovcnt = 1;
366 	auio.uio_resid = msglen;
367 	if (flags & MSG_USERSPACE)
368 		auio.uio_segflg = UIO_USERSPACE;
369 	else
370 		auio.uio_segflg = UIO_SYSSPACE;
371 	auio.uio_extflg = UIO_COPY_DEFAULT;
372 	auio.uio_limit = 0;
373 	auio.uio_fmode = KSOCKET_FMODE(ks);
374 
375 	msghdr.msg_name = NULL;
376 	msghdr.msg_namelen = 0;
377 	msghdr.msg_control = NULL;
378 	msghdr.msg_controllen = 0;
379 	msghdr.msg_flags = flags & (MSG_OOB | MSG_PEEK | MSG_WAITALL |
380 	    MSG_DONTWAIT | MSG_USERSPACE);
381 
382 	error = socket_recvmsg(KSTOSO(ks), &msghdr, &auio, cr);
383 	if (error != 0) {
384 		if (recv != NULL)
385 			*recv = 0;
386 		return (error);
387 	}
388 
389 	if (recv != NULL)
390 		*recv = msglen - auio.uio_resid;
391 	return (0);
392 }
393 
394 int
395 ksocket_recvfrom(ksocket_t ks, void *msg, size_t msglen, int flags,
396     struct sockaddr *name, socklen_t *namelen, size_t *recv, struct cred *cr)
397 {
398 	int error;
399 	struct nmsghdr msghdr;
400 	struct uio auio;
401 	struct iovec iov;
402 
403 	/* All Solaris components should pass a cred for this operation. */
404 	ASSERT(cr != NULL);
405 
406 	if (!KSOCKET_VALID(ks)) {
407 		if (recv != NULL)
408 			*recv = 0;
409 		return (ENOTSOCK);
410 	}
411 
412 	iov.iov_base = msg;
413 	iov.iov_len = msglen;
414 
415 	bzero(&auio, sizeof (struct uio));
416 	auio.uio_loffset = 0;
417 	auio.uio_iov = &iov;
418 	auio.uio_iovcnt = 1;
419 	auio.uio_resid = msglen;
420 	if (flags & MSG_USERSPACE)
421 		auio.uio_segflg = UIO_USERSPACE;
422 	else
423 		auio.uio_segflg = UIO_SYSSPACE;
424 	auio.uio_extflg = UIO_COPY_DEFAULT;
425 	auio.uio_limit = 0;
426 	auio.uio_fmode = KSOCKET_FMODE(ks);
427 
428 	msghdr.msg_name = (char *)name;
429 	msghdr.msg_namelen = *namelen;
430 	msghdr.msg_control = NULL;
431 	msghdr.msg_controllen = 0;
432 	msghdr.msg_flags = flags & (MSG_OOB | MSG_PEEK | MSG_WAITALL |
433 	    MSG_DONTWAIT | MSG_USERSPACE);
434 
435 	error = socket_recvmsg(KSTOSO(ks), &msghdr, &auio, cr);
436 	if (error != 0) {
437 		if (recv != NULL)
438 			*recv = 0;
439 		return (error);
440 	}
441 	if (recv != NULL)
442 		*recv = msglen - auio.uio_resid;
443 
444 	bcopy(msghdr.msg_name, name, msghdr.msg_namelen);
445 	bcopy(&msghdr.msg_namelen, namelen, sizeof (msghdr.msg_namelen));
446 	return (0);
447 }
448 
449 int
450 ksocket_recvmsg(ksocket_t ks, struct nmsghdr *msg, int flags, size_t *recv,
451     struct cred *cr)
452 {
453 	int error;
454 	ssize_t len;
455 	int i;
456 	struct uio auio;
457 
458 	/* All Solaris components should pass a cred for this operation. */
459 	ASSERT(cr != NULL);
460 
461 	if (!KSOCKET_VALID(ks)) {
462 		if (recv != NULL)
463 			*recv = 0;
464 		return (ENOTSOCK);
465 	}
466 
467 	bzero(&auio, sizeof (struct uio));
468 	auio.uio_loffset = 0;
469 	auio.uio_iov = msg->msg_iov;
470 	auio.uio_iovcnt = msg->msg_iovlen;
471 	if (msg->msg_flags & MSG_USERSPACE)
472 		auio.uio_segflg = UIO_USERSPACE;
473 	else
474 		auio.uio_segflg = UIO_SYSSPACE;
475 	auio.uio_extflg = UIO_COPY_DEFAULT;
476 	auio.uio_limit = 0;
477 	auio.uio_fmode = KSOCKET_FMODE(ks);
478 	len = 0;
479 
480 	for (i = 0; i < msg->msg_iovlen; i++) {
481 		ssize_t iovlen;
482 		iovlen = (msg->msg_iov)[i].iov_len;
483 		len += iovlen;
484 		if (len < 0 || iovlen < 0)
485 			return (EINVAL);
486 	}
487 	auio.uio_resid = len;
488 
489 	msg->msg_flags = flags & (MSG_OOB | MSG_PEEK | MSG_WAITALL |
490 	    MSG_DONTWAIT | MSG_USERSPACE);
491 
492 	error = socket_recvmsg(KSTOSO(ks), msg, &auio, cr);
493 	if (error != 0) {
494 		if (recv != NULL)
495 			*recv = 0;
496 		return (error);
497 	}
498 	if (recv != NULL)
499 		*recv = len - auio.uio_resid;
500 	return (0);
501 
502 }
503 
504 int
505 ksocket_shutdown(ksocket_t ks, int how, struct cred *cr)
506 {
507 	struct sonode *so;
508 
509 	/* All Solaris components should pass a cred for this operation. */
510 	ASSERT(cr != NULL);
511 
512 	if (!KSOCKET_VALID(ks))
513 		return (ENOTSOCK);
514 
515 	so = KSTOSO(ks);
516 
517 	return (socket_shutdown(so, how, cr));
518 }
519 
520 int
521 ksocket_close(ksocket_t ks, struct cred *cr)
522 {
523 	struct sonode *so;
524 	so = KSTOSO(ks);
525 
526 	/* All Solaris components should pass a cred for this operation. */
527 	ASSERT(cr != NULL);
528 
529 	mutex_enter(&so->so_lock);
530 
531 	if (!KSOCKET_VALID(ks)) {
532 		mutex_exit(&so->so_lock);
533 		return (ENOTSOCK);
534 	}
535 
536 	so->so_state |= SS_CLOSING;
537 
538 	if (so->so_count > 1) {
539 		mutex_enter(&so->so_acceptq_lock);
540 		cv_broadcast(&so->so_acceptq_cv);
541 		mutex_exit(&so->so_acceptq_lock);
542 		cv_broadcast(&so->so_rcv_cv);
543 		cv_broadcast(&so->so_state_cv);
544 		cv_broadcast(&so->so_single_cv);
545 		cv_broadcast(&so->so_read_cv);
546 		cv_broadcast(&so->so_snd_cv);
547 		cv_broadcast(&so->so_copy_cv);
548 	}
549 	while (so->so_count > 1)
550 		cv_wait(&so->so_closing_cv, &so->so_lock);
551 
552 	mutex_exit(&so->so_lock);
553 	/* Remove callbacks, if any */
554 	(void) ksocket_setcallbacks(ks, NULL, NULL, cr);
555 
556 	(void) socket_close(so, 0, cr);
557 	socket_destroy(so);
558 
559 	return (0);
560 }
561 
562 int
563 ksocket_getsockname(ksocket_t ks, struct sockaddr *addr, socklen_t *addrlen,
564     struct cred *cr)
565 {
566 	struct sonode *so;
567 
568 	/* All Solaris components should pass a cred for this operation. */
569 	ASSERT(cr != NULL);
570 
571 	if (!KSOCKET_VALID(ks))
572 		return (ENOTSOCK);
573 
574 	so = KSTOSO(ks);
575 
576 	if (addrlen == NULL || (addr == NULL && *addrlen != 0))
577 		return (EFAULT);
578 
579 	return (socket_getsockname(so, addr, addrlen, cr));
580 }
581 
582 int
583 ksocket_getpeername(ksocket_t ks, struct sockaddr *addr, socklen_t *addrlen,
584     struct cred *cr)
585 {
586 	struct sonode *so;
587 
588 	/* All Solaris components should pass a cred for this operation. */
589 	ASSERT(cr != NULL);
590 
591 	if (!KSOCKET_VALID(ks))
592 		return (ENOTSOCK);
593 
594 	so = KSTOSO(ks);
595 
596 	if (addrlen == NULL || (addr == NULL && *addrlen != 0))
597 		return (EFAULT);
598 
599 	return (socket_getpeername(so, addr, addrlen, B_FALSE, cr));
600 }
601 
602 int
603 ksocket_getsockopt(ksocket_t ks, int level, int optname, void *optval,
604     int *optlen, struct cred *cr)
605 {
606 	struct sonode *so;
607 
608 	/* All Solaris components should pass a cred for this operation. */
609 	ASSERT(cr != NULL);
610 
611 	if (!KSOCKET_VALID(ks))
612 		return (ENOTSOCK);
613 
614 	so = KSTOSO(ks);
615 
616 	if (optlen == NULL)
617 		return (EFAULT);
618 	if (*optlen > SO_MAXARGSIZE)
619 		return (EINVAL);
620 
621 	return (socket_getsockopt(so, level, optname, optval,
622 	    (socklen_t *)optlen, 0, cr));
623 }
624 
625 int
626 ksocket_setsockopt(ksocket_t ks, int level, int optname, const void *optval,
627     int optlen, struct cred *cr)
628 {
629 	struct sonode *so;
630 
631 	/* All Solaris components should pass a cred for this operation. */
632 	ASSERT(cr != NULL);
633 
634 	if (!KSOCKET_VALID(ks))
635 		return (ENOTSOCK);
636 
637 	so = KSTOSO(ks);
638 
639 	if (optval == NULL)
640 		optlen = 0;
641 
642 	return (socket_setsockopt(so, level, optname, optval,
643 	    (t_uscalar_t)optlen, cr));
644 }
645 
646 /* ARGSUSED */
647 int
648 ksocket_setcallbacks(ksocket_t ks, ksocket_callbacks_t *cb, void *arg,
649     struct cred *cr)
650 {
651 	struct sonode *so;
652 
653 	/* All Solaris components should pass a cred for this operation. */
654 	ASSERT(cr != NULL);
655 
656 	if (!KSOCKET_VALID(ks))
657 		return (ENOTSOCK);
658 
659 	so = KSTOSO(ks);
660 
661 	if (cb == NULL && arg != NULL)
662 		return (EFAULT);
663 	if (cb == NULL) {
664 		mutex_enter(&so->so_lock);
665 		bzero(&(so->so_ksock_callbacks), sizeof (ksocket_callbacks_t));
666 		so->so_ksock_cb_arg = NULL;
667 		mutex_exit(&so->so_lock);
668 	} else {
669 		mutex_enter(&so->so_lock);
670 		SETCALLBACK(so, cb, connected, KSOCKET_CB_CONNECTED)
671 		SETCALLBACK(so, cb, connectfailed, KSOCKET_CB_CONNECTFAILED)
672 		SETCALLBACK(so, cb, disconnected, KSOCKET_CB_DISCONNECTED)
673 		SETCALLBACK(so, cb, newdata, KSOCKET_CB_NEWDATA)
674 		SETCALLBACK(so, cb, newconn, KSOCKET_CB_NEWCONN)
675 		SETCALLBACK(so, cb, cansend, KSOCKET_CB_CANSEND)
676 		SETCALLBACK(so, cb, oobdata, KSOCKET_CB_OOBDATA)
677 		SETCALLBACK(so, cb, cantsendmore, KSOCKET_CB_CANTSENDMORE)
678 		SETCALLBACK(so, cb, cantrecvmore, KSOCKET_CB_CANTRECVMORE)
679 		so->so_ksock_cb_arg = arg;
680 		mutex_exit(&so->so_lock);
681 	}
682 	return (0);
683 }
684 
685 int
686 ksocket_ioctl(ksocket_t ks, int cmd, intptr_t arg, int *rvalp, struct cred *cr)
687 {
688 	struct sonode *so;
689 	int rval;
690 
691 	/* All Solaris components should pass a cred for this operation. */
692 	ASSERT(cr != NULL);
693 
694 	if (!KSOCKET_VALID(ks))
695 		return (ENOTSOCK);
696 
697 	so = KSTOSO(ks);
698 
699 	switch (cmd) {
700 	default:
701 		/* STREAM iotcls are not supported */
702 		if ((cmd & 0xffffff00U) == STR) {
703 			rval = EOPNOTSUPP;
704 		} else {
705 			rval = socket_ioctl(so, cmd, arg,
706 			    KSOCKET_FMODE(ks) | FKIOCTL, cr, rvalp);
707 		}
708 		break;
709 	case FIOASYNC:
710 	case SIOCSPGRP:
711 	case FIOSETOWN:
712 	case SIOCGPGRP:
713 	case FIOGETOWN:
714 		rval = EOPNOTSUPP;
715 		break;
716 	}
717 
718 	return (rval);
719 }
720 
721 /*
722  * Wait for an input event, similar to t_kspoll().
723  * Ideas and code borrowed from ../devpoll.c
724  * Basically, setup just enough poll data structures so
725  * we can block on a CV until timeout or pollwakeup().
726  */
727 int
728 ksocket_spoll(ksocket_t ks, int timo, short events, short *revents,
729     struct cred *cr)
730 {
731 	struct		sonode *so;
732 	pollhead_t	*php, *php2;
733 	polldat_t	*pdp;
734 	pollcache_t	*pcp;
735 	int		error;
736 	clock_t		expires = 0;
737 	clock_t		rval;
738 
739 	/* All Solaris components should pass a cred for this operation. */
740 	ASSERT(cr != NULL);
741 	ASSERT(curthread->t_pollcache == NULL);
742 
743 	if (revents == NULL)
744 		return (EINVAL);
745 	if (!KSOCKET_VALID(ks))
746 		return (ENOTSOCK);
747 	so = KSTOSO(ks);
748 
749 	/*
750 	 * Check if there are any events already pending.
751 	 * If we're not willing to block, (timo == 0) then
752 	 * pass "anyyet">0 to socket_poll so it can skip
753 	 * some work.  Othewise pass "anyyet"=0 and if
754 	 * there are no events pending, it will fill in
755 	 * the pollhead pointer we need for pollwakeup().
756 	 *
757 	 * XXX - pollrelock() logic needs to know which
758 	 * which pollcache lock to grab. It'd be a
759 	 * cleaner solution if we could pass pcp as
760 	 * an arguement in VOP_POLL interface instead
761 	 * of implicitly passing it using thread_t
762 	 * struct. On the other hand, changing VOP_POLL
763 	 * interface will require all driver/file system
764 	 * poll routine to change. May want to revisit
765 	 * the tradeoff later.
766 	 */
767 	php = NULL;
768 	*revents = 0;
769 	pcp = pcache_alloc();
770 	pcache_create(pcp, 1);
771 
772 	mutex_enter(&pcp->pc_lock);
773 	curthread->t_pollcache = pcp;
774 	error = socket_poll(so, (short)events, (timo == 0),
775 	    revents, &php);
776 	curthread->t_pollcache = NULL;
777 	mutex_exit(&pcp->pc_lock);
778 
779 	if (error != 0 || *revents != 0 || timo == 0)
780 		goto out;
781 
782 	/*
783 	 * Need to block.  Did not get *revents, so the
784 	 * php should be non-NULL, but let's verify.
785 	 * Also compute when our sleep expires.
786 	 */
787 	if (php == NULL) {
788 		error = EIO;
789 		goto out;
790 	}
791 	if (timo > 0)
792 		expires = ddi_get_lbolt() +
793 		    MSEC_TO_TICK_ROUNDUP(timo);
794 
795 	/*
796 	 * Setup: pollhead -> polldat -> pollcache
797 	 * needed for pollwakeup()
798 	 * pdp should be freed by pcache_destroy
799 	 */
800 	pdp = kmem_zalloc(sizeof (*pdp), KM_SLEEP);
801 	pdp->pd_fd = 0;
802 	pdp->pd_events = events;
803 	pdp->pd_pcache = pcp;
804 	pcache_insert_fd(pcp, pdp, 1);
805 	polldat_associate(pdp, php);
806 
807 	mutex_enter(&pcp->pc_lock);
808 	while (!(so->so_state & SS_CLOSING)) {
809 		pcp->pc_flag = 0;
810 
811 		/* Ditto pcp comment above. */
812 		curthread->t_pollcache = pcp;
813 		error = socket_poll(so, (short)events, 0,
814 		    revents, &php2);
815 		curthread->t_pollcache = NULL;
816 		ASSERT(php2 == php);
817 
818 		if (error != 0 || *revents != 0)
819 			break;
820 
821 		if (pcp->pc_flag & PC_POLLWAKE)
822 			continue;
823 
824 		if (timo == -1) {
825 			rval = cv_wait_sig(&pcp->pc_cv, &pcp->pc_lock);
826 		} else {
827 			rval = cv_timedwait_sig(&pcp->pc_cv, &pcp->pc_lock,
828 			    expires);
829 		}
830 		if (rval <= 0) {
831 			if (rval == 0)
832 				error = EINTR;
833 			break;
834 		}
835 	}
836 	mutex_exit(&pcp->pc_lock);
837 
838 	polldat_disassociate(pdp);
839 	pdp->pd_fd = 0;
840 
841 	/*
842 	 * pollwakeup() may still interact with this pollcache. Wait until
843 	 * it is done.
844 	 */
845 	mutex_enter(&pcp->pc_no_exit);
846 	ASSERT(pcp->pc_busy >= 0);
847 	while (pcp->pc_busy > 0)
848 		cv_wait(&pcp->pc_busy_cv, &pcp->pc_no_exit);
849 	mutex_exit(&pcp->pc_no_exit);
850 out:
851 	pcache_destroy(pcp);
852 	return (error);
853 }
854 
855 int
856 ksocket_sendmblk(ksocket_t ks, struct nmsghdr *msg, int flags,
857     mblk_t **mpp, cred_t *cr)
858 {
859 	struct		sonode *so;
860 	int		i_val;
861 	socklen_t	val_len;
862 	mblk_t		*mp = *mpp;
863 	int		error;
864 
865 	/* All Solaris components should pass a cred for this operation. */
866 	ASSERT(cr != NULL);
867 
868 	if (!KSOCKET_VALID(ks))
869 		return (ENOTSOCK);
870 
871 	so = KSTOSO(ks);
872 
873 	if (flags & MSG_MBLK_QUICKRELE) {
874 		error = socket_getsockopt(so, SOL_SOCKET, SO_SND_COPYAVOID,
875 		    &i_val, &val_len, 0, cr);
876 		if (error != 0)
877 			return (error);
878 
879 		/* Zero copy is not enable */
880 		if (i_val == 0)
881 			return (ECANCELED);
882 
883 		for (; mp != NULL; mp = mp->b_cont)
884 			mp->b_datap->db_struioflag |= STRUIO_ZC;
885 	}
886 
887 	error = socket_sendmblk(so, msg, flags, cr, mpp);
888 
889 	return (error);
890 }
891 
892 
893 void
894 ksocket_hold(ksocket_t ks)
895 {
896 	struct sonode *so;
897 	so = KSTOSO(ks);
898 
899 	if (!mutex_owned(&so->so_lock)) {
900 		mutex_enter(&so->so_lock);
901 		so->so_count++;
902 		mutex_exit(&so->so_lock);
903 	} else
904 		so->so_count++;
905 }
906 
907 void
908 ksocket_rele(ksocket_t ks)
909 {
910 	struct sonode *so;
911 
912 	so = KSTOSO(ks);
913 	/*
914 	 * When so_count equals 1 means no thread working on this ksocket
915 	 */
916 	if (so->so_count < 2)
917 		cmn_err(CE_PANIC, "ksocket_rele: sonode ref count 0 or 1");
918 
919 	if (!mutex_owned(&so->so_lock)) {
920 		mutex_enter(&so->so_lock);
921 		if (--so->so_count == 1)
922 			cv_signal(&so->so_closing_cv);
923 		mutex_exit(&so->so_lock);
924 	} else {
925 		if (--so->so_count == 1)
926 			cv_signal(&so->so_closing_cv);
927 	}
928 }
929 
930 int
931 ksocket_krecv_set(ksocket_t ks, ksocket_krecv_f cb, void *arg)
932 {
933 	return (so_krecv_set(KSTOSO(ks), (so_krecv_f)cb, arg));
934 }
935 
936 void
937 ksocket_krecv_unblock(ksocket_t ks)
938 {
939 	return (so_krecv_unblock(KSTOSO(ks)));
940 }
941