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 * Copyright 2015, Joyent, Inc.
26 * Copyright 2022 Garrett D'Amore
27 */
28
29 #include <sys/file.h>
30 #include <sys/stropts.h>
31 #include <sys/socket.h>
32 #include <sys/socketvar.h>
33 #include <sys/sysmacros.h>
34 #include <sys/filio.h> /* FIO* ioctls */
35 #include <sys/sockio.h> /* SIOC* ioctls */
36 #include <sys/poll_impl.h>
37 #include <sys/cmn_err.h>
38 #include <sys/ksocket.h>
39 #include <io/ksocket/ksocket_impl.h>
40 #include <fs/sockfs/sockcommon.h>
41
42 #define SOCKETMOD_TCP "tcp"
43 #define SOCKETMOD_UDP "udp"
44 /*
45 * Kernel Sockets
46 *
47 * Mostly a wrapper around the private socket_* functions.
48 */
49 int
ksocket_socket(ksocket_t * ksp,int domain,int type,int protocol,int flags,struct cred * cr)50 ksocket_socket(ksocket_t *ksp, int domain, int type, int protocol, int flags,
51 struct cred *cr)
52 {
53 static const int version = SOV_DEFAULT;
54 int error = 0;
55 struct sonode *so;
56 *ksp = NULL;
57
58 /* All Solaris components should pass a cred for this operation. */
59 ASSERT(cr != NULL);
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 system 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
ksocket_bind(ksocket_t ks,struct sockaddr * addr,socklen_t addrlen,struct cred * cr)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
ksocket_listen(ksocket_t ks,int backlog,struct cred * cr)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
ksocket_accept(ksocket_t ks,struct sockaddr * addr,socklen_t * addrlenp,ksocket_t * nks,struct cred * cr)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
ksocket_connect(ksocket_t ks,struct sockaddr * addr,socklen_t addrlen,struct cred * cr)169 ksocket_connect(ksocket_t ks, 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
ksocket_send(ksocket_t ks,void * msg,size_t msglen,int flags,size_t * sent,struct cred * cr)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
ksocket_sendto(ksocket_t ks,void * msg,size_t msglen,int flags,struct sockaddr * name,socklen_t namelen,size_t * sent,struct cred * cr)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
ksocket_sendmsg(ksocket_t ks,struct nmsghdr * msg,int flags,size_t * sent,struct cred * cr)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
ksocket_recv(ksocket_t ks,void * msg,size_t msglen,int flags,size_t * recv,struct cred * cr)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
ksocket_recvfrom(ksocket_t ks,void * msg,size_t msglen,int flags,struct sockaddr * name,socklen_t * namelen,size_t * recv,struct cred * cr)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
ksocket_recvmsg(ksocket_t ks,struct nmsghdr * msg,int flags,size_t * recv,struct cred * cr)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
ksocket_shutdown(ksocket_t ks,int how,struct cred * cr)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
ksocket_close(ksocket_t ks,struct cred * cr)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
ksocket_getsockname(ksocket_t ks,struct sockaddr * addr,socklen_t * addrlen,struct cred * cr)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
ksocket_getpeername(ksocket_t ks,struct sockaddr * addr,socklen_t * addrlen,struct cred * cr)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
ksocket_getsockopt(ksocket_t ks,int level,int optname,void * optval,int * optlen,struct cred * cr)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
ksocket_setsockopt(ksocket_t ks,int level,int optname,const void * optval,int optlen,struct cred * cr)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
ksocket_setcallbacks(ksocket_t ks,ksocket_callbacks_t * cb,void * arg,struct cred * cr)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
ksocket_ioctl(ksocket_t ks,int cmd,intptr_t arg,int * rvalp,struct cred * cr)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 /*
722 * Wait for an input event, similar to t_kspoll().
723 * Ideas and code borrowed from ../devpoll.c
724 * Basically, setup just enough poll data structures so
725 * we can block on a CV until timeout or pollwakeup().
726 */
727 int
ksocket_spoll(ksocket_t ks,int timo,short events,short * revents,struct cred * cr)728 ksocket_spoll(ksocket_t ks, int timo, short events, short *revents,
729 struct cred *cr)
730 {
731 struct sonode *so;
732 pollhead_t *php, *php2;
733 polldat_t *pdp;
734 pollcache_t *pcp;
735 int error;
736 clock_t expires = 0;
737 clock_t rval;
738
739 /* All Solaris components should pass a cred for this operation. */
740 ASSERT(cr != NULL);
741 ASSERT(curthread->t_pollcache == NULL);
742
743 if (revents == NULL)
744 return (EINVAL);
745 if (!KSOCKET_VALID(ks))
746 return (ENOTSOCK);
747 so = KSTOSO(ks);
748
749 /*
750 * Check if there are any events already pending.
751 * If we're not willing to block, (timo == 0) then
752 * pass "anyyet">0 to socket_poll so it can skip
753 * some work. Othewise pass "anyyet"=0 and if
754 * there are no events pending, it will fill in
755 * the pollhead pointer we need for pollwakeup().
756 *
757 * XXX - pollrelock() logic needs to know which
758 * which pollcache lock to grab. It'd be a
759 * cleaner solution if we could pass pcp as
760 * an arguement in VOP_POLL interface instead
761 * of implicitly passing it using thread_t
762 * struct. On the other hand, changing VOP_POLL
763 * interface will require all driver/file system
764 * poll routine to change. May want to revisit
765 * the tradeoff later.
766 */
767 php = NULL;
768 *revents = 0;
769 pcp = pcache_alloc();
770 pcache_create(pcp, 1);
771
772 mutex_enter(&pcp->pc_lock);
773 curthread->t_pollcache = pcp;
774 error = socket_poll(so, (short)events, (timo == 0),
775 revents, &php);
776 curthread->t_pollcache = NULL;
777 mutex_exit(&pcp->pc_lock);
778
779 if (error != 0 || *revents != 0 || timo == 0)
780 goto out;
781
782 /*
783 * Need to block. Did not get *revents, so the
784 * php should be non-NULL, but let's verify.
785 * Also compute when our sleep expires.
786 */
787 if (php == NULL) {
788 error = EIO;
789 goto out;
790 }
791 if (timo > 0)
792 expires = ddi_get_lbolt() +
793 MSEC_TO_TICK_ROUNDUP(timo);
794
795 /*
796 * Setup: pollhead -> polldat -> pollcache
797 * needed for pollwakeup()
798 * pdp should be freed by pcache_destroy
799 */
800 pdp = kmem_zalloc(sizeof (*pdp), KM_SLEEP);
801 pdp->pd_fd = 0;
802 pdp->pd_events = events;
803 pdp->pd_pcache = pcp;
804 pcache_insert_fd(pcp, pdp, 1);
805 polldat_associate(pdp, php);
806
807 mutex_enter(&pcp->pc_lock);
808 while (!(so->so_state & SS_CLOSING)) {
809 pcp->pc_flag = 0;
810
811 /* Ditto pcp comment above. */
812 curthread->t_pollcache = pcp;
813 error = socket_poll(so, (short)events, 0,
814 revents, &php2);
815 curthread->t_pollcache = NULL;
816 ASSERT(php2 == php);
817
818 if (error != 0 || *revents != 0)
819 break;
820
821 if (pcp->pc_flag & PC_POLLWAKE)
822 continue;
823
824 if (timo == -1) {
825 rval = cv_wait_sig(&pcp->pc_cv, &pcp->pc_lock);
826 } else {
827 rval = cv_timedwait_sig(&pcp->pc_cv, &pcp->pc_lock,
828 expires);
829 }
830 if (rval <= 0) {
831 if (rval == 0)
832 error = EINTR;
833 break;
834 }
835 }
836 mutex_exit(&pcp->pc_lock);
837
838 polldat_disassociate(pdp);
839 pdp->pd_fd = 0;
840
841 /*
842 * pollwakeup() may still interact with this pollcache. Wait until
843 * it is done.
844 */
845 mutex_enter(&pcp->pc_no_exit);
846 ASSERT(pcp->pc_busy >= 0);
847 while (pcp->pc_busy > 0)
848 cv_wait(&pcp->pc_busy_cv, &pcp->pc_no_exit);
849 mutex_exit(&pcp->pc_no_exit);
850 out:
851 pcache_destroy(pcp);
852 return (error);
853 }
854
855 int
ksocket_sendmblk(ksocket_t ks,struct nmsghdr * msg,int flags,mblk_t ** mpp,cred_t * cr)856 ksocket_sendmblk(ksocket_t ks, struct nmsghdr *msg, int flags,
857 mblk_t **mpp, cred_t *cr)
858 {
859 struct sonode *so;
860 int i_val;
861 socklen_t val_len;
862 mblk_t *mp = *mpp;
863 int error;
864
865 /* All Solaris components should pass a cred for this operation. */
866 ASSERT(cr != NULL);
867
868 if (!KSOCKET_VALID(ks))
869 return (ENOTSOCK);
870
871 so = KSTOSO(ks);
872
873 if (flags & MSG_MBLK_QUICKRELE) {
874 error = socket_getsockopt(so, SOL_SOCKET, SO_SND_COPYAVOID,
875 &i_val, &val_len, 0, cr);
876 if (error != 0)
877 return (error);
878
879 /* Zero copy is not enable */
880 if (i_val == 0)
881 return (ECANCELED);
882
883 for (; mp != NULL; mp = mp->b_cont)
884 mp->b_datap->db_struioflag |= STRUIO_ZC;
885 }
886
887 error = socket_sendmblk(so, msg, flags, cr, mpp);
888
889 return (error);
890 }
891
892
893 void
ksocket_hold(ksocket_t ks)894 ksocket_hold(ksocket_t ks)
895 {
896 struct sonode *so;
897 so = KSTOSO(ks);
898
899 if (!mutex_owned(&so->so_lock)) {
900 mutex_enter(&so->so_lock);
901 so->so_count++;
902 mutex_exit(&so->so_lock);
903 } else
904 so->so_count++;
905 }
906
907 void
ksocket_rele(ksocket_t ks)908 ksocket_rele(ksocket_t ks)
909 {
910 struct sonode *so;
911
912 so = KSTOSO(ks);
913 /*
914 * When so_count equals 1 means no thread working on this ksocket
915 */
916 if (so->so_count < 2)
917 cmn_err(CE_PANIC, "ksocket_rele: sonode ref count 0 or 1");
918
919 if (!mutex_owned(&so->so_lock)) {
920 mutex_enter(&so->so_lock);
921 if (--so->so_count == 1)
922 cv_signal(&so->so_closing_cv);
923 mutex_exit(&so->so_lock);
924 } else {
925 if (--so->so_count == 1)
926 cv_signal(&so->so_closing_cv);
927 }
928 }
929
930 int
ksocket_krecv_set(ksocket_t ks,ksocket_krecv_f cb,void * arg)931 ksocket_krecv_set(ksocket_t ks, ksocket_krecv_f cb, void *arg)
932 {
933 return (so_krecv_set(KSTOSO(ks), (so_krecv_f)cb, arg));
934 }
935
936 void
ksocket_krecv_unblock(ksocket_t ks)937 ksocket_krecv_unblock(ksocket_t ks)
938 {
939 return (so_krecv_unblock(KSTOSO(ks)));
940 }
941