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