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