xref: /titanic_51/usr/src/uts/common/io/ksocket/ksocket.c (revision c3a558e7c77127215b010652905be7916ec5a080)
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 2010 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
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/cmn_err.h>
35 #include <sys/ksocket.h>
36 #include <io/ksocket/ksocket_impl.h>
37 #include <fs/sockfs/sockcommon.h>
38 
39 #define	SOCKETMOD_TCP	"tcp"
40 #define	SOCKETMOD_UDP	"udp"
41 /*
42  * Kernel Sockets
43  *
44  * Mostly a wrapper around the private socket_* functions.
45  */
46 int
47 ksocket_socket(ksocket_t *ksp, int domain, int type, int protocol, int flags,
48     struct cred *cr)
49 {
50 	static const int version = SOV_DEFAULT;
51 	int error = 0;
52 	struct sonode *so;
53 	*ksp = NULL;
54 
55 	/* All Solaris components should pass a cred for this operation. */
56 	ASSERT(cr != NULL);
57 
58 	if (domain == AF_NCA || domain == AF_UNIX)
59 		return (EAFNOSUPPORT);
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 sytem 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, const 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 int
722 ksocket_sendmblk(ksocket_t ks, struct nmsghdr *msg, int flags,
723     mblk_t **mpp, cred_t *cr)
724 {
725 	struct		sonode *so;
726 	int		i_val;
727 	socklen_t	val_len;
728 	mblk_t		*mp = *mpp;
729 	int		error;
730 
731 	/* All Solaris components should pass a cred for this operation. */
732 	ASSERT(cr != NULL);
733 
734 	if (!KSOCKET_VALID(ks))
735 		return (ENOTSOCK);
736 
737 	so = KSTOSO(ks);
738 
739 	if (flags & MSG_MBLK_QUICKRELE) {
740 		error = socket_getsockopt(so, SOL_SOCKET, SO_SND_COPYAVOID,
741 		    &i_val, &val_len, 0, cr);
742 		if (error != 0)
743 			return (error);
744 
745 		/* Zero copy is not enable */
746 		if (i_val == 0)
747 			return (ECANCELED);
748 
749 		for (; mp != NULL; mp = mp->b_cont)
750 			mp->b_datap->db_struioflag |= STRUIO_ZC;
751 	}
752 
753 	error = socket_sendmblk(so, msg, flags, cr, mpp);
754 
755 	return (error);
756 }
757 
758 
759 void
760 ksocket_hold(ksocket_t ks)
761 {
762 	struct sonode *so;
763 	so = KSTOSO(ks);
764 
765 	if (!mutex_owned(&so->so_lock)) {
766 		mutex_enter(&so->so_lock);
767 		so->so_count++;
768 		mutex_exit(&so->so_lock);
769 	} else
770 		so->so_count++;
771 }
772 
773 void
774 ksocket_rele(ksocket_t ks)
775 {
776 	struct sonode *so;
777 
778 	so = KSTOSO(ks);
779 	/*
780 	 * When so_count equals 1 means no thread working on this ksocket
781 	 */
782 	if (so->so_count < 2)
783 		cmn_err(CE_PANIC, "ksocket_rele: sonode ref count 0 or 1");
784 
785 	if (!mutex_owned(&so->so_lock)) {
786 		mutex_enter(&so->so_lock);
787 		if (--so->so_count == 1)
788 			cv_signal(&so->so_closing_cv);
789 		mutex_exit(&so->so_lock);
790 	} else {
791 		if (--so->so_count == 1)
792 			cv_signal(&so->so_closing_cv);
793 	}
794 }
795