xref: /illumos-gate/usr/src/uts/common/io/ksocket/ksocket.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 2009 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_want_cv);
545 		cv_broadcast(&so->so_snd_cv);
546 		cv_broadcast(&so->so_copy_cv);
547 	}
548 	while (so->so_count > 1)
549 		cv_wait(&so->so_closing_cv, &so->so_lock);
550 
551 	mutex_exit(&so->so_lock);
552 	/* Remove callbacks, if any */
553 	(void) ksocket_setcallbacks(ks, NULL, NULL, cr);
554 
555 	(void) socket_close(so, 0, cr);
556 	socket_destroy(so);
557 
558 	return (0);
559 }
560 
561 int
562 ksocket_getsockname(ksocket_t ks, struct sockaddr *addr, socklen_t *addrlen,
563     struct cred *cr)
564 {
565 	struct sonode *so;
566 
567 	/* All Solaris components should pass a cred for this operation. */
568 	ASSERT(cr != NULL);
569 
570 	if (!KSOCKET_VALID(ks))
571 		return (ENOTSOCK);
572 
573 	so = KSTOSO(ks);
574 
575 	if (addrlen == NULL || (addr == NULL && *addrlen != 0))
576 		return (EFAULT);
577 
578 	return (socket_getsockname(so, addr, addrlen, cr));
579 }
580 
581 int
582 ksocket_getpeername(ksocket_t ks, struct sockaddr *addr, socklen_t *addrlen,
583     struct cred *cr)
584 {
585 	struct sonode *so;
586 
587 	/* All Solaris components should pass a cred for this operation. */
588 	ASSERT(cr != NULL);
589 
590 	if (!KSOCKET_VALID(ks))
591 		return (ENOTSOCK);
592 
593 	so = KSTOSO(ks);
594 
595 	if (addrlen == NULL || (addr == NULL && *addrlen != 0))
596 		return (EFAULT);
597 
598 	return (socket_getpeername(so, addr, addrlen, B_FALSE, cr));
599 }
600 
601 int
602 ksocket_getsockopt(ksocket_t ks, int level, int optname, void *optval,
603     int *optlen, struct cred *cr)
604 {
605 	struct sonode *so;
606 
607 	/* All Solaris components should pass a cred for this operation. */
608 	ASSERT(cr != NULL);
609 
610 	if (!KSOCKET_VALID(ks))
611 		return (ENOTSOCK);
612 
613 	so = KSTOSO(ks);
614 
615 	if (optlen == NULL)
616 		return (EFAULT);
617 	if (*optlen > SO_MAXARGSIZE)
618 		return (EINVAL);
619 
620 	return (socket_getsockopt(so, level, optname, optval,
621 	    (socklen_t *)optlen, 0, cr));
622 }
623 
624 int
625 ksocket_setsockopt(ksocket_t ks, int level, int optname, const void *optval,
626     int optlen, struct cred *cr)
627 {
628 	struct sonode *so;
629 
630 	/* All Solaris components should pass a cred for this operation. */
631 	ASSERT(cr != NULL);
632 
633 	if (!KSOCKET_VALID(ks))
634 		return (ENOTSOCK);
635 
636 	so = KSTOSO(ks);
637 
638 	if (optval == NULL)
639 		optlen = 0;
640 
641 	return (socket_setsockopt(so, level, optname, optval,
642 	    (t_uscalar_t)optlen, cr));
643 }
644 
645 /* ARGSUSED */
646 int
647 ksocket_setcallbacks(ksocket_t ks, ksocket_callbacks_t *cb, void *arg,
648     struct cred *cr)
649 {
650 	struct sonode *so;
651 
652 	/* All Solaris components should pass a cred for this operation. */
653 	ASSERT(cr != NULL);
654 
655 	if (!KSOCKET_VALID(ks))
656 		return (ENOTSOCK);
657 
658 	so = KSTOSO(ks);
659 
660 	if (cb == NULL && arg != NULL)
661 		return (EFAULT);
662 	if (cb == NULL) {
663 		mutex_enter(&so->so_lock);
664 		bzero(&(so->so_ksock_callbacks), sizeof (ksocket_callbacks_t));
665 		so->so_ksock_cb_arg = NULL;
666 		mutex_exit(&so->so_lock);
667 	} else {
668 		mutex_enter(&so->so_lock);
669 		SETCALLBACK(so, cb, connected, KSOCKET_CB_CONNECTED)
670 		SETCALLBACK(so, cb, connectfailed, KSOCKET_CB_CONNECTFAILED)
671 		SETCALLBACK(so, cb, disconnected, KSOCKET_CB_DISCONNECTED)
672 		SETCALLBACK(so, cb, newdata, KSOCKET_CB_NEWDATA)
673 		SETCALLBACK(so, cb, newconn, KSOCKET_CB_NEWCONN)
674 		SETCALLBACK(so, cb, cansend, KSOCKET_CB_CANSEND)
675 		SETCALLBACK(so, cb, oobdata, KSOCKET_CB_OOBDATA)
676 		SETCALLBACK(so, cb, cantsendmore, KSOCKET_CB_CANTSENDMORE)
677 		SETCALLBACK(so, cb, cantrecvmore, KSOCKET_CB_CANTRECVMORE)
678 		so->so_ksock_cb_arg = arg;
679 		mutex_exit(&so->so_lock);
680 	}
681 	return (0);
682 }
683 
684 int
685 ksocket_ioctl(ksocket_t ks, int cmd, intptr_t arg, int *rvalp, struct cred *cr)
686 {
687 	struct sonode *so;
688 	int rval;
689 
690 	/* All Solaris components should pass a cred for this operation. */
691 	ASSERT(cr != NULL);
692 
693 	if (!KSOCKET_VALID(ks))
694 		return (ENOTSOCK);
695 
696 	so = KSTOSO(ks);
697 
698 	switch (cmd) {
699 	default:
700 		/* STREAM iotcls are not supported */
701 		if ((cmd & 0xffffff00U) == STR) {
702 			rval = EOPNOTSUPP;
703 		} else {
704 			rval = socket_ioctl(so, cmd, arg,
705 			    KSOCKET_FMODE(ks) | FKIOCTL, cr, rvalp);
706 		}
707 		break;
708 	case FIOASYNC:
709 	case SIOCSPGRP:
710 	case FIOSETOWN:
711 	case SIOCGPGRP:
712 	case FIOGETOWN:
713 		rval = EOPNOTSUPP;
714 		break;
715 	}
716 
717 	return (rval);
718 }
719 
720 int
721 ksocket_sendmblk(ksocket_t ks, struct nmsghdr *msg, int flags,
722     mblk_t **mpp, cred_t *cr)
723 {
724 	struct		sonode *so;
725 	int		i_val;
726 	socklen_t	val_len;
727 	mblk_t		*mp = *mpp;
728 	int		error;
729 
730 	/* All Solaris components should pass a cred for this operation. */
731 	ASSERT(cr != NULL);
732 
733 	if (!KSOCKET_VALID(ks))
734 		return (ENOTSOCK);
735 
736 	so = KSTOSO(ks);
737 
738 	if (flags & MSG_MBLK_QUICKRELE) {
739 		error = socket_getsockopt(so, SOL_SOCKET, SO_SND_COPYAVOID,
740 		    &i_val, &val_len, 0, cr);
741 		if (error != 0)
742 			return (error);
743 
744 		/* Zero copy is not enable */
745 		if (i_val == 0)
746 			return (ECANCELED);
747 
748 		for (; mp != NULL; mp = mp->b_cont)
749 			mp->b_datap->db_struioflag |= STRUIO_ZC;
750 	}
751 
752 	error = socket_sendmblk(so, msg, flags, cr, mpp);
753 
754 	return (error);
755 }
756 
757 
758 void
759 ksocket_hold(ksocket_t ks)
760 {
761 	struct sonode *so;
762 	so = KSTOSO(ks);
763 
764 	if (!mutex_owned(&so->so_lock)) {
765 		mutex_enter(&so->so_lock);
766 		so->so_count++;
767 		mutex_exit(&so->so_lock);
768 	} else
769 		so->so_count++;
770 }
771 
772 void
773 ksocket_rele(ksocket_t ks)
774 {
775 	struct sonode *so;
776 
777 	so = KSTOSO(ks);
778 	/*
779 	 * When so_count equals 1 means no thread working on this ksocket
780 	 */
781 	if (so->so_count < 2)
782 		cmn_err(CE_PANIC, "ksocket_rele: sonode ref count 0 or 1");
783 
784 	if (!mutex_owned(&so->so_lock)) {
785 		mutex_enter(&so->so_lock);
786 		if (--so->so_count == 1)
787 			cv_signal(&so->so_closing_cv);
788 		mutex_exit(&so->so_lock);
789 	} else {
790 		if (--so->so_count == 1)
791 			cv_signal(&so->so_closing_cv);
792 	}
793 }
794