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
ksocket_socket(ksocket_t * ksp,int domain,int type,int protocol,int flags,struct cred * cr)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
ksocket_bind(ksocket_t ks,struct sockaddr * addr,socklen_t addrlen,struct cred * cr)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
ksocket_listen(ksocket_t ks,int backlog,struct cred * cr)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
ksocket_accept(ksocket_t ks,struct sockaddr * addr,socklen_t * addrlenp,ksocket_t * nks,struct cred * cr)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
ksocket_connect(ksocket_t ks,struct sockaddr * addr,socklen_t addrlen,struct cred * cr)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
ksocket_send(ksocket_t ks,void * msg,size_t msglen,int flags,size_t * sent,struct cred * cr)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
ksocket_sendto(ksocket_t ks,void * msg,size_t msglen,int flags,struct sockaddr * name,socklen_t namelen,size_t * sent,struct cred * cr)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
ksocket_sendmsg(ksocket_t ks,struct nmsghdr * msg,int flags,size_t * sent,struct cred * cr)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
ksocket_recv(ksocket_t ks,void * msg,size_t msglen,int flags,size_t * recv,struct cred * cr)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
ksocket_recvfrom(ksocket_t ks,void * msg,size_t msglen,int flags,struct sockaddr * name,socklen_t * namelen,size_t * recv,struct cred * cr)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
ksocket_recvmsg(ksocket_t ks,struct nmsghdr * msg,int flags,size_t * recv,struct cred * cr)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
ksocket_shutdown(ksocket_t ks,int how,struct cred * cr)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
ksocket_close(ksocket_t ks,struct cred * cr)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
ksocket_getsockname(ksocket_t ks,struct sockaddr * addr,socklen_t * addrlen,struct cred * cr)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
ksocket_getpeername(ksocket_t ks,struct sockaddr * addr,socklen_t * addrlen,struct cred * cr)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
ksocket_getsockopt(ksocket_t ks,int level,int optname,void * optval,int * optlen,struct cred * cr)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
ksocket_setsockopt(ksocket_t ks,int level,int optname,const void * optval,int optlen,struct cred * cr)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
ksocket_setcallbacks(ksocket_t ks,ksocket_callbacks_t * cb,void * arg,struct cred * cr)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
ksocket_ioctl(ksocket_t ks,int cmd,intptr_t arg,int * rvalp,struct cred * cr)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
ksocket_sendmblk(ksocket_t ks,struct nmsghdr * msg,int flags,mblk_t ** mpp,cred_t * cr)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
ksocket_hold(ksocket_t ks)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
ksocket_rele(ksocket_t ks)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