xref: /titanic_44/usr/src/uts/common/io/ksocket/ksocket.c (revision 1e4c938b57d1656808e4112127ff1dce3eba5314)
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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 #include <sys/file.h>
27 #include <sys/stropts.h>
28 #include <sys/socket.h>
29 #include <sys/socketvar.h>
30 #include <sys/sysmacros.h>
31 #include <sys/filio.h>		/* FIO* ioctls */
32 #include <sys/sockio.h>		/* SIOC* ioctls */
33 #include <sys/cmn_err.h>
34 #include <sys/ksocket.h>
35 #include <io/ksocket/ksocket_impl.h>
36 #include <fs/sockfs/sockcommon.h>
37 
38 #define	SOCKETMOD_TCP	"tcp"
39 #define	SOCKETMOD_UDP	"udp"
40 /*
41  * Kernel Sockets
42  *
43  * Mostly a wrapper around the private socket_* functions.
44  */
45 int
46 ksocket_socket(ksocket_t *ksp, int domain, int type, int protocol, int flags,
47     struct cred *cr)
48 {
49 	static const int version = SOV_DEFAULT;
50 	int error = 0;
51 	struct sonode *so;
52 	*ksp = NULL;
53 
54 	/* All Solaris components should pass a cred for this operation. */
55 	ASSERT(cr != NULL);
56 
57 	if (domain == AF_NCA || domain == AF_UNIX)
58 		return (EAFNOSUPPORT);
59 
60 	ASSERT(flags == KSOCKET_SLEEP || flags == KSOCKET_NOSLEEP);
61 	so = socket_create(domain, type, protocol, NULL, NULL, version, flags,
62 	    cr, &error);
63 	if (so == NULL) {
64 		if (error == EAFNOSUPPORT) {
65 			char *mod = NULL;
66 
67 			/*
68 			 * Could be that root file sytem is not loaded or
69 			 * soconfig has not run yet.
70 			 */
71 			if (type == SOCK_STREAM && (domain == AF_INET ||
72 			    domain == AF_INET6) && (protocol == 0 ||
73 			    protocol == IPPROTO_TCP)) {
74 					mod = SOCKETMOD_TCP;
75 			} else if (type == SOCK_DGRAM && (domain == AF_INET ||
76 			    domain == AF_INET6) && (protocol == 0 ||
77 			    protocol == IPPROTO_UDP)) {
78 					mod = SOCKETMOD_UDP;
79 			} else {
80 				return (EAFNOSUPPORT);
81 			}
82 
83 			so = socket_create(domain, type, protocol, NULL,
84 			    mod, version, flags, cr, &error);
85 			if (so == NULL)
86 				return (error);
87 		} else {
88 			return (error);
89 		}
90 	}
91 
92 	so->so_mode |= SM_KERNEL;
93 
94 	*ksp = SOTOKS(so);
95 
96 	return (0);
97 }
98 int
99 ksocket_bind(ksocket_t ks, struct sockaddr *addr, socklen_t addrlen,
100     struct cred *cr)
101 {
102 	int error;
103 
104 	/* All Solaris components should pass a cred for this operation. */
105 	ASSERT(cr != NULL);
106 
107 	if (!KSOCKET_VALID(ks))
108 		return (ENOTSOCK);
109 
110 	error = socket_bind(KSTOSO(ks), addr, addrlen, _SOBIND_SOCKBSD, cr);
111 
112 	return (error);
113 }
114 
115 int
116 ksocket_listen(ksocket_t ks, int backlog, struct cred *cr)
117 {
118 	/* All Solaris components should pass a cred for this operation. */
119 	ASSERT(cr != NULL);
120 
121 	if (!KSOCKET_VALID(ks))
122 		return (ENOTSOCK);
123 
124 	return (socket_listen(KSTOSO(ks), backlog, cr));
125 }
126 
127 int
128 ksocket_accept(ksocket_t ks, struct sockaddr *addr,
129     socklen_t *addrlenp, ksocket_t *nks, struct cred *cr)
130 {
131 	int error;
132 	struct sonode *nso = NULL;
133 
134 	/* All Solaris components should pass a cred for this operation. */
135 	ASSERT(cr != NULL);
136 
137 	*nks = NULL;
138 
139 	if (!KSOCKET_VALID(ks))
140 		return (ENOTSOCK);
141 
142 	if (addr != NULL && addrlenp == NULL)
143 		return (EFAULT);
144 
145 	error = socket_accept(KSTOSO(ks), KSOCKET_FMODE(ks), cr, &nso);
146 	if (error != 0)
147 		return (error);
148 
149 	ASSERT(nso != NULL);
150 
151 	nso->so_mode |= SM_KERNEL;
152 
153 	if (addr != NULL && addrlenp != NULL) {
154 		error = socket_getpeername(nso, addr, addrlenp, B_TRUE, cr);
155 		if (error != 0) {
156 			(void) socket_close(nso, 0, cr);
157 			socket_destroy(nso);
158 			return ((error == ENOTCONN) ? ECONNABORTED : error);
159 		}
160 	}
161 
162 	*nks = SOTOKS(nso);
163 
164 	return (error);
165 }
166 
167 int
168 ksocket_connect(ksocket_t ks, struct sockaddr *addr, socklen_t addrlen,
169     struct cred *cr)
170 {
171 	/* All Solaris components should pass a cred for this operation. */
172 	ASSERT(cr != NULL);
173 
174 	if (!KSOCKET_VALID(ks))
175 		return (ENOTSOCK);
176 
177 	return (socket_connect(KSTOSO(ks), addr, addrlen,
178 	    KSOCKET_FMODE(ks), 0, cr));
179 }
180 
181 int
182 ksocket_send(ksocket_t ks, void *msg, size_t msglen, int flags,
183     size_t *sent, struct cred *cr)
184 {
185 	int error;
186 	struct nmsghdr msghdr;
187 	struct uio auio;
188 	struct iovec iov;
189 
190 	/* All Solaris components should pass a cred for this operation. */
191 	ASSERT(cr != NULL);
192 
193 	if (!KSOCKET_VALID(ks)) {
194 		if (sent != NULL)
195 			*sent = 0;
196 		return (ENOTSOCK);
197 	}
198 
199 	iov.iov_base = msg;
200 	iov.iov_len = msglen;
201 
202 	bzero(&auio, sizeof (struct uio));
203 	auio.uio_loffset = 0;
204 	auio.uio_iov = &iov;
205 	auio.uio_iovcnt = 1;
206 	auio.uio_resid = msglen;
207 	if (flags & MSG_USERSPACE)
208 		auio.uio_segflg = UIO_USERSPACE;
209 	else
210 		auio.uio_segflg = UIO_SYSSPACE;
211 	auio.uio_extflg = UIO_COPY_DEFAULT;
212 	auio.uio_limit = 0;
213 	auio.uio_fmode = KSOCKET_FMODE(ks);
214 
215 	msghdr.msg_name = NULL;
216 	msghdr.msg_namelen = 0;
217 	msghdr.msg_control = NULL;
218 	msghdr.msg_controllen = 0;
219 	msghdr.msg_flags = flags | MSG_EOR;
220 
221 	error = socket_sendmsg(KSTOSO(ks), &msghdr, &auio, cr);
222 	if (error != 0) {
223 		if (sent != NULL)
224 			*sent = 0;
225 		return (error);
226 	}
227 
228 	if (sent != NULL)
229 		*sent = msglen - auio.uio_resid;
230 	return (0);
231 }
232 
233 int
234 ksocket_sendto(ksocket_t ks, void *msg, size_t msglen, int flags,
235     struct sockaddr *name, socklen_t namelen, size_t *sent, struct cred *cr)
236 {
237 	int error;
238 	struct nmsghdr msghdr;
239 	struct uio auio;
240 	struct iovec iov;
241 
242 	/* All Solaris components should pass a cred for this operation. */
243 	ASSERT(cr != NULL);
244 
245 	if (!KSOCKET_VALID(ks)) {
246 		if (sent != NULL)
247 			*sent = 0;
248 		return (ENOTSOCK);
249 	}
250 
251 	iov.iov_base = msg;
252 	iov.iov_len = msglen;
253 
254 	bzero(&auio, sizeof (struct uio));
255 	auio.uio_loffset = 0;
256 	auio.uio_iov = &iov;
257 	auio.uio_iovcnt = 1;
258 	auio.uio_resid = msglen;
259 	if (flags & MSG_USERSPACE)
260 		auio.uio_segflg = UIO_USERSPACE;
261 	else
262 		auio.uio_segflg = UIO_SYSSPACE;
263 	auio.uio_extflg = UIO_COPY_DEFAULT;
264 	auio.uio_limit = 0;
265 	auio.uio_fmode = KSOCKET_FMODE(ks);
266 
267 	msghdr.msg_iov = &iov;
268 	msghdr.msg_iovlen = 1;
269 	msghdr.msg_name = (char *)name;
270 	msghdr.msg_namelen = namelen;
271 	msghdr.msg_control = NULL;
272 	msghdr.msg_controllen = 0;
273 	msghdr.msg_flags = flags | MSG_EOR;
274 
275 	error = socket_sendmsg(KSTOSO(ks), &msghdr, &auio, cr);
276 	if (error != 0) {
277 		if (sent != NULL)
278 			*sent = 0;
279 		return (error);
280 	}
281 	if (sent != NULL)
282 		*sent = msglen - auio.uio_resid;
283 	return (0);
284 }
285 
286 int
287 ksocket_sendmsg(ksocket_t ks, struct nmsghdr *msg, int flags,
288     size_t *sent, struct cred *cr)
289 {
290 	int error;
291 	ssize_t len;
292 	int i;
293 	struct uio auio;
294 
295 	/* All Solaris components should pass a cred for this operation. */
296 	ASSERT(cr != NULL);
297 
298 	if (!KSOCKET_VALID(ks)) {
299 		if (sent != NULL)
300 			*sent = 0;
301 		return (ENOTSOCK);
302 	}
303 
304 	bzero(&auio, sizeof (struct uio));
305 	auio.uio_loffset = 0;
306 	auio.uio_iov = msg->msg_iov;
307 	auio.uio_iovcnt = msg->msg_iovlen;
308 	if (flags & MSG_USERSPACE)
309 		auio.uio_segflg = UIO_USERSPACE;
310 	else
311 		auio.uio_segflg = UIO_SYSSPACE;
312 	auio.uio_extflg = UIO_COPY_DEFAULT;
313 	auio.uio_limit = 0;
314 	auio.uio_fmode = KSOCKET_FMODE(ks);
315 	len = 0;
316 	for (i = 0; i < msg->msg_iovlen; i++) {
317 		ssize_t iovlen;
318 		iovlen = (msg->msg_iov)[i].iov_len;
319 		len += iovlen;
320 		if (len < 0 || iovlen < 0)
321 			return (EINVAL);
322 	}
323 	auio.uio_resid = len;
324 
325 	msg->msg_flags = flags | MSG_EOR;
326 
327 	error = socket_sendmsg(KSTOSO(ks), msg, &auio, cr);
328 	if (error != 0) {
329 		if (sent != NULL)
330 			*sent = 0;
331 		return (error);
332 	}
333 
334 	if (sent != NULL)
335 		*sent = len - auio.uio_resid;
336 	return (0);
337 }
338 
339 
340 int
341 ksocket_recv(ksocket_t ks, void *msg, size_t msglen, int flags,
342     size_t *recv, struct cred *cr)
343 {
344 	int error;
345 	struct nmsghdr msghdr;
346 	struct uio auio;
347 	struct iovec iov;
348 
349 	/* All Solaris components should pass a cred for this operation. */
350 	ASSERT(cr != NULL);
351 
352 	if (!KSOCKET_VALID(ks)) {
353 		if (recv != NULL)
354 			*recv = 0;
355 		return (ENOTSOCK);
356 	}
357 
358 	iov.iov_base = msg;
359 	iov.iov_len = msglen;
360 
361 	bzero(&auio, sizeof (struct uio));
362 	auio.uio_loffset = 0;
363 	auio.uio_iov = &iov;
364 	auio.uio_iovcnt = 1;
365 	auio.uio_resid = msglen;
366 	if (flags & MSG_USERSPACE)
367 		auio.uio_segflg = UIO_USERSPACE;
368 	else
369 		auio.uio_segflg = UIO_SYSSPACE;
370 	auio.uio_extflg = UIO_COPY_DEFAULT;
371 	auio.uio_limit = 0;
372 	auio.uio_fmode = KSOCKET_FMODE(ks);
373 
374 	msghdr.msg_name = NULL;
375 	msghdr.msg_namelen = 0;
376 	msghdr.msg_control = NULL;
377 	msghdr.msg_controllen = 0;
378 	msghdr.msg_flags = flags & (MSG_OOB | MSG_PEEK | MSG_WAITALL |
379 	    MSG_DONTWAIT | MSG_USERSPACE);
380 
381 	error = socket_recvmsg(KSTOSO(ks), &msghdr, &auio, cr);
382 	if (error != 0) {
383 		if (recv != NULL)
384 			*recv = 0;
385 		return (error);
386 	}
387 
388 	if (recv != NULL)
389 		*recv = msglen - auio.uio_resid;
390 	return (0);
391 }
392 
393 int
394 ksocket_recvfrom(ksocket_t ks, void *msg, size_t msglen, int flags,
395     struct sockaddr *name, socklen_t *namelen, size_t *recv, struct cred *cr)
396 {
397 	int error;
398 	struct nmsghdr msghdr;
399 	struct uio auio;
400 	struct iovec iov;
401 
402 	/* All Solaris components should pass a cred for this operation. */
403 	ASSERT(cr != NULL);
404 
405 	if (!KSOCKET_VALID(ks)) {
406 		if (recv != NULL)
407 			*recv = 0;
408 		return (ENOTSOCK);
409 	}
410 
411 	iov.iov_base = msg;
412 	iov.iov_len = msglen;
413 
414 	bzero(&auio, sizeof (struct uio));
415 	auio.uio_loffset = 0;
416 	auio.uio_iov = &iov;
417 	auio.uio_iovcnt = 1;
418 	auio.uio_resid = msglen;
419 	if (flags & MSG_USERSPACE)
420 		auio.uio_segflg = UIO_USERSPACE;
421 	else
422 		auio.uio_segflg = UIO_SYSSPACE;
423 	auio.uio_extflg = UIO_COPY_DEFAULT;
424 	auio.uio_limit = 0;
425 	auio.uio_fmode = KSOCKET_FMODE(ks);
426 
427 	msghdr.msg_name = (char *)name;
428 	msghdr.msg_namelen = *namelen;
429 	msghdr.msg_control = NULL;
430 	msghdr.msg_controllen = 0;
431 	msghdr.msg_flags = flags & (MSG_OOB | MSG_PEEK | MSG_WAITALL |
432 	    MSG_DONTWAIT | MSG_USERSPACE);
433 
434 	error = socket_recvmsg(KSTOSO(ks), &msghdr, &auio, cr);
435 	if (error != 0) {
436 		if (recv != NULL)
437 			*recv = 0;
438 		return (error);
439 	}
440 	if (recv != NULL)
441 		*recv = msglen - auio.uio_resid;
442 
443 	bcopy(msghdr.msg_name, name, msghdr.msg_namelen);
444 	bcopy(&msghdr.msg_namelen, namelen, sizeof (msghdr.msg_namelen));
445 	return (0);
446 }
447 
448 int
449 ksocket_recvmsg(ksocket_t ks, struct nmsghdr *msg, int flags, size_t *recv,
450     struct cred *cr)
451 {
452 	int error;
453 	ssize_t len;
454 	int i;
455 	struct uio auio;
456 
457 	/* All Solaris components should pass a cred for this operation. */
458 	ASSERT(cr != NULL);
459 
460 	if (!KSOCKET_VALID(ks)) {
461 		if (recv != NULL)
462 			*recv = 0;
463 		return (ENOTSOCK);
464 	}
465 
466 	bzero(&auio, sizeof (struct uio));
467 	auio.uio_loffset = 0;
468 	auio.uio_iov = msg->msg_iov;
469 	auio.uio_iovcnt = msg->msg_iovlen;
470 	if (msg->msg_flags & MSG_USERSPACE)
471 		auio.uio_segflg = UIO_USERSPACE;
472 	else
473 		auio.uio_segflg = UIO_SYSSPACE;
474 	auio.uio_extflg = UIO_COPY_DEFAULT;
475 	auio.uio_limit = 0;
476 	auio.uio_fmode = KSOCKET_FMODE(ks);
477 	len = 0;
478 
479 	for (i = 0; i < msg->msg_iovlen; i++) {
480 		ssize_t iovlen;
481 		iovlen = (msg->msg_iov)[i].iov_len;
482 		len += iovlen;
483 		if (len < 0 || iovlen < 0)
484 			return (EINVAL);
485 	}
486 	auio.uio_resid = len;
487 
488 	msg->msg_flags = flags & (MSG_OOB | MSG_PEEK | MSG_WAITALL |
489 	    MSG_DONTWAIT | MSG_USERSPACE);
490 
491 	error = socket_recvmsg(KSTOSO(ks), msg, &auio, cr);
492 	if (error != 0) {
493 		if (recv != NULL)
494 			*recv = 0;
495 		return (error);
496 	}
497 	if (recv != NULL)
498 		*recv = len - auio.uio_resid;
499 	return (0);
500 
501 }
502 
503 int
504 ksocket_shutdown(ksocket_t ks, int how, struct cred *cr)
505 {
506 	struct sonode *so;
507 
508 	/* All Solaris components should pass a cred for this operation. */
509 	ASSERT(cr != NULL);
510 
511 	if (!KSOCKET_VALID(ks))
512 		return (ENOTSOCK);
513 
514 	so = KSTOSO(ks);
515 
516 	return (socket_shutdown(so, how, cr));
517 }
518 
519 int
520 ksocket_close(ksocket_t ks, struct cred *cr)
521 {
522 	struct sonode *so;
523 	so = KSTOSO(ks);
524 
525 	/* All Solaris components should pass a cred for this operation. */
526 	ASSERT(cr != NULL);
527 
528 	mutex_enter(&so->so_lock);
529 
530 	if (!KSOCKET_VALID(ks)) {
531 		mutex_exit(&so->so_lock);
532 		return (ENOTSOCK);
533 	}
534 
535 	so->so_state |= SS_CLOSING;
536 
537 	if (so->so_count > 1) {
538 		mutex_enter(&so->so_acceptq_lock);
539 		cv_broadcast(&so->so_acceptq_cv);
540 		mutex_exit(&so->so_acceptq_lock);
541 		cv_broadcast(&so->so_rcv_cv);
542 		cv_broadcast(&so->so_state_cv);
543 		cv_broadcast(&so->so_single_cv);
544 		cv_broadcast(&so->so_read_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