2 * Unix Domain Sockets Implementation (PF_UNIX, PF_LOCAL)
3 * This code handles ioctl(2) commands to implement the socket API.
4 * Some helper functions are also present.
10 perform_connection(devminor_t minorx
, devminor_t minory
,
11 struct sockaddr_un
*addr
)
14 * There are several places were a connection is established, the
15 * initiating call being one of accept(2), connect(2), socketpair(2).
17 dprintf(("UDS: perform_connection(%d, %d)\n", minorx
, minory
));
20 * Only connection-oriented types are acceptable and only equal
21 * types can connect to each other.
23 if ((uds_fd_table
[minorx
].type
!= SOCK_SEQPACKET
&&
24 uds_fd_table
[minorx
].type
!= SOCK_STREAM
) ||
25 uds_fd_table
[minorx
].type
!= uds_fd_table
[minory
].type
)
28 /* Connect the pair of sockets. */
29 uds_fd_table
[minorx
].peer
= minory
;
30 uds_fd_table
[minory
].peer
= minorx
;
32 /* Set the address of both sockets */
33 memcpy(&uds_fd_table
[minorx
].addr
, addr
, sizeof(struct sockaddr_un
));
34 memcpy(&uds_fd_table
[minory
].addr
, addr
, sizeof(struct sockaddr_un
));
40 do_accept(devminor_t minor
, endpoint_t endpt
, cp_grant_id_t grant
)
42 devminor_t minorparent
; /* minor number of parent (server) */
45 struct sockaddr_un addr
;
47 dprintf(("UDS: do_accept(%d)\n", minor
));
50 * Somewhat weird logic is used in this function, so here's an
51 * overview... The minor number is the server's client socket
52 * (the socket to be returned by accept()). The data waiting
53 * for us in the IO Grant is the address that the server is
54 * listening on. This function uses the address to find the
55 * server's descriptor. From there we can perform the
56 * connection or suspend and wait for a connect().
59 /* This IOCTL must be called on a 'fresh' socket. */
60 if (uds_fd_table
[minor
].type
!= -1)
63 /* Get the server's address */
64 if ((rc
= sys_safecopyfrom(endpt
, grant
, 0, (vir_bytes
) &addr
,
65 sizeof(struct sockaddr_un
))) != OK
)
68 /* Locate the server socket. */
69 for (i
= 0; i
< NR_FDS
; i
++) {
70 if (uds_fd_table
[i
].addr
.sun_family
== AF_UNIX
&&
71 !strncmp(addr
.sun_path
, uds_fd_table
[i
].addr
.sun_path
,
72 sizeof(uds_fd_table
[i
].addr
.sun_path
)) &&
73 uds_fd_table
[i
].listening
== 1)
80 minorparent
= i
; /* parent */
82 /* We are the parent's child. */
83 uds_fd_table
[minorparent
].child
= minor
;
86 * The peer has the same type as the parent. we need to be that
89 uds_fd_table
[minor
].type
= uds_fd_table
[minorparent
].type
;
91 /* Locate the peer to accept in the parent's backlog. */
93 for (i
= 0; i
< uds_fd_table
[minorparent
].backlog_size
; i
++) {
94 if (uds_fd_table
[minorparent
].backlog
[i
] != -1) {
95 minorpeer
= uds_fd_table
[minorparent
].backlog
[i
];
96 uds_fd_table
[minorparent
].backlog
[i
] = -1;
101 if (minorpeer
== -1) {
102 dprintf(("UDS: do_accept(%d): suspend\n", minor
));
105 * There are no peers in the backlog, suspend and wait for one
108 uds_fd_table
[minor
].suspended
= UDS_SUSPENDED_ACCEPT
;
113 dprintf(("UDS: connecting %d to %d -- parent is %d\n", minor
,
114 minorpeer
, minorparent
));
116 if ((rc
= perform_connection(minor
, minorpeer
, &addr
)) != OK
) {
117 dprintf(("UDS: do_accept(%d): connection failed\n", minor
));
122 uds_fd_table
[minorparent
].child
= -1;
124 /* If the peer is blocked on connect() or write(), revive the peer. */
125 if (uds_fd_table
[minorpeer
].suspended
== UDS_SUSPENDED_CONNECT
||
126 uds_fd_table
[minorpeer
].suspended
== UDS_SUSPENDED_WRITE
) {
127 dprintf(("UDS: do_accept(%d): revive %d\n", minor
, minorpeer
));
128 uds_unsuspend(minorpeer
);
131 /* See if we can satisfy an ongoing select. */
132 if ((uds_fd_table
[minorpeer
].sel_ops
& CDEV_OP_WR
) &&
133 uds_fd_table
[minorpeer
].size
< UDS_BUF
) {
134 /* A write on the peer is possible now. */
135 chardriver_reply_select(uds_fd_table
[minorpeer
].sel_endpt
,
136 minorpeer
, CDEV_OP_WR
);
137 uds_fd_table
[minorpeer
].sel_ops
&= ~CDEV_OP_WR
;
144 do_connect(devminor_t minor
, endpoint_t endpt
, cp_grant_id_t grant
)
147 struct sockaddr_un addr
;
150 dprintf(("UDS: do_connect(%d)\n", minor
));
152 /* Only connection oriented sockets can connect. */
153 if (uds_fd_table
[minor
].type
!= SOCK_STREAM
&&
154 uds_fd_table
[minor
].type
!= SOCK_SEQPACKET
)
157 /* The socket must not be connecting or connected already. */
158 peer
= uds_fd_table
[minor
].peer
;
160 if (uds_fd_table
[peer
].peer
== -1)
161 return EALREADY
; /* connecting */
163 return EISCONN
; /* connected */
166 if ((rc
= sys_safecopyfrom(endpt
, grant
, 0, (vir_bytes
) &addr
,
167 sizeof(struct sockaddr_un
))) != OK
)
170 if ((rc
= checkperms(uds_fd_table
[minor
].owner
, addr
.sun_path
,
171 sizeof(addr
.sun_path
))) != OK
)
175 * Look for a socket of the same type that is listening on the
176 * address we want to connect to.
178 for (i
= 0; i
< NR_FDS
; i
++) {
179 if (uds_fd_table
[minor
].type
!= uds_fd_table
[i
].type
)
181 if (!uds_fd_table
[i
].listening
)
183 if (uds_fd_table
[i
].addr
.sun_family
!= AF_UNIX
)
185 if (strncmp(addr
.sun_path
, uds_fd_table
[i
].addr
.sun_path
,
186 sizeof(uds_fd_table
[i
].addr
.sun_path
)))
189 /* Found a matching socket. */
196 /* If the server is blocked on an accept, perform the connection. */
197 if ((child
= uds_fd_table
[i
].child
) != -1) {
198 rc
= perform_connection(minor
, child
, &addr
);
203 uds_fd_table
[i
].child
= -1;
205 dprintf(("UDS: do_connect(%d): revive %d\n", minor
, child
));
207 /* Wake up the accepting party. */
208 uds_unsuspend(child
);
213 dprintf(("UDS: adding %d to %d's backlog\n", minor
, i
));
215 /* Look for a free slot in the backlog. */
217 for (j
= 0; j
< uds_fd_table
[i
].backlog_size
; j
++) {
218 if (uds_fd_table
[i
].backlog
[j
] == -1) {
219 uds_fd_table
[i
].backlog
[j
] = minor
;
227 return ECONNREFUSED
; /* backlog is full */
229 /* See if the server is blocked on select(). */
230 if (uds_fd_table
[i
].sel_ops
& CDEV_OP_RD
) {
231 /* Satisfy a read-type select on the server. */
232 chardriver_reply_select(uds_fd_table
[i
].sel_endpt
, i
,
235 uds_fd_table
[i
].sel_ops
&= ~CDEV_OP_RD
;
238 /* We found our server. */
239 uds_fd_table
[minor
].peer
= i
;
241 memcpy(&uds_fd_table
[minor
].addr
, &addr
, sizeof(struct sockaddr_un
));
243 dprintf(("UDS: do_connect(%d): suspend\n", minor
));
245 /* Suspend until the server side accepts the connection. */
246 uds_fd_table
[minor
].suspended
= UDS_SUSPENDED_CONNECT
;
252 do_listen(devminor_t minor
, endpoint_t endpt
, cp_grant_id_t grant
)
257 dprintf(("UDS: do_listen(%d)\n", minor
));
259 /* Ensure the socket has a type and is bound. */
260 if (uds_fd_table
[minor
].type
== -1 ||
261 uds_fd_table
[minor
].addr
.sun_family
!= AF_UNIX
)
264 /* listen(2) supports only two socket types. */
265 if (uds_fd_table
[minor
].type
!= SOCK_STREAM
&&
266 uds_fd_table
[minor
].type
!= SOCK_SEQPACKET
)
270 * The POSIX standard doesn't say what to do if listen() has
271 * already been called. Well, there isn't an errno. We silently
272 * let it happen, but if listen() has already been called, we
273 * don't allow the backlog to shrink.
275 if ((rc
= sys_safecopyfrom(endpt
, grant
, 0, (vir_bytes
) &backlog_size
,
276 sizeof(backlog_size
))) != OK
)
279 if (uds_fd_table
[minor
].listening
== 0) {
280 /* Set the backlog size to a reasonable value. */
281 if (backlog_size
<= 0 || backlog_size
> UDS_SOMAXCONN
)
282 backlog_size
= UDS_SOMAXCONN
;
284 uds_fd_table
[minor
].backlog_size
= backlog_size
;
286 /* Allow the user to expand the backlog size. */
287 if (backlog_size
> uds_fd_table
[minor
].backlog_size
&&
288 backlog_size
< UDS_SOMAXCONN
)
289 uds_fd_table
[minor
].backlog_size
= backlog_size
;
292 * Don't let the user shrink the backlog_size, as we might
293 * have clients waiting in those slots.
297 /* This socket is now listening. */
298 uds_fd_table
[minor
].listening
= 1;
304 do_socket(devminor_t minor
, endpoint_t endpt
, cp_grant_id_t grant
)
308 dprintf(("UDS: do_socket(%d)\n", minor
));
310 /* The socket type can only be set once. */
311 if (uds_fd_table
[minor
].type
!= -1)
314 /* Get the requested type. */
315 if ((rc
= sys_safecopyfrom(endpt
, grant
, 0, (vir_bytes
) &type
,
316 sizeof(type
))) != OK
)
319 /* Assign the type if it is valid only. */
324 uds_fd_table
[minor
].type
= type
;
333 do_bind(devminor_t minor
, endpoint_t endpt
, cp_grant_id_t grant
)
335 struct sockaddr_un addr
;
338 dprintf(("UDS: do_bind(%d)\n", minor
));
340 /* If the type hasn't been set by do_socket() yet, OR an attempt
341 * to re-bind() a non-SOCK_DGRAM socket is made, fail the call.
343 if ((uds_fd_table
[minor
].type
== -1) ||
344 (uds_fd_table
[minor
].addr
.sun_family
== AF_UNIX
&&
345 uds_fd_table
[minor
].type
!= SOCK_DGRAM
))
348 if ((rc
= sys_safecopyfrom(endpt
, grant
, 0, (vir_bytes
) &addr
,
349 sizeof(struct sockaddr_un
))) != OK
)
352 /* Do some basic sanity checks on the address. */
353 if (addr
.sun_family
!= AF_UNIX
)
356 if (addr
.sun_path
[0] == '\0')
359 if ((rc
= checkperms(uds_fd_table
[minor
].owner
, addr
.sun_path
,
360 sizeof(addr
.sun_path
))) != OK
)
363 /* Make sure the address isn't already in use by another socket. */
364 for (i
= 0; i
< NR_FDS
; i
++) {
365 if (uds_fd_table
[i
].addr
.sun_family
== AF_UNIX
&&
366 !strncmp(addr
.sun_path
, uds_fd_table
[i
].addr
.sun_path
,
367 sizeof(uds_fd_table
[i
].addr
.sun_path
))) {
368 /* Another socket is bound to this sun_path. */
373 /* Looks good, perform the bind(). */
374 memcpy(&uds_fd_table
[minor
].addr
, &addr
, sizeof(struct sockaddr_un
));
380 do_getsockname(devminor_t minor
, endpoint_t endpt
, cp_grant_id_t grant
)
382 dprintf(("UDS: do_getsockname(%d)\n", minor
));
385 * Unconditionally send the address we have assigned to this socket.
386 * The POSIX standard doesn't say what to do if the address hasn't been
387 * set. If the address isn't currently set, then the user will get
388 * NULL bytes. Note: libc depends on this behavior.
390 return sys_safecopyto(endpt
, grant
, 0,
391 (vir_bytes
) &uds_fd_table
[minor
].addr
, sizeof(struct sockaddr_un
));
395 do_getpeername(devminor_t minor
, endpoint_t endpt
, cp_grant_id_t grant
)
399 dprintf(("UDS: do_getpeername(%d)\n", minor
));
401 /* Check that the socket is connected with a valid peer. */
402 if (uds_fd_table
[minor
].peer
!= -1) {
403 peer_minor
= uds_fd_table
[minor
].peer
;
405 /* Copy the address from the peer. */
406 return sys_safecopyto(endpt
, grant
, 0,
407 (vir_bytes
) &uds_fd_table
[peer_minor
].addr
,
408 sizeof(struct sockaddr_un
));
409 } else if (uds_fd_table
[minor
].err
== ECONNRESET
) {
410 uds_fd_table
[minor
].err
= 0;
418 do_shutdown(devminor_t minor
, endpoint_t endpt
, cp_grant_id_t grant
)
422 dprintf(("UDS: do_shutdown(%d)\n", minor
));
424 /* The socket must be connection oriented. */
425 if (uds_fd_table
[minor
].type
!= SOCK_STREAM
&&
426 uds_fd_table
[minor
].type
!= SOCK_SEQPACKET
)
429 if (uds_fd_table
[minor
].peer
== -1) {
430 /* shutdown(2) is only valid for connected sockets. */
431 if (uds_fd_table
[minor
].err
== ECONNRESET
)
437 /* Get the 'how' parameter from the caller. */
438 if ((rc
= sys_safecopyfrom(endpt
, grant
, 0, (vir_bytes
) &how
,
443 case SHUT_RD
: /* Take away read permission. */
444 uds_fd_table
[minor
].mode
&= ~UDS_R
;
447 case SHUT_WR
: /* Take away write permission. */
448 uds_fd_table
[minor
].mode
&= ~UDS_W
;
451 case SHUT_RDWR
: /* Shut down completely. */
452 uds_fd_table
[minor
].mode
= 0;
463 do_socketpair(devminor_t minorx
, endpoint_t endpt
, cp_grant_id_t grant
)
468 struct sockaddr_un addr
;
470 dprintf(("UDS: do_socketpair(%d)\n", minorx
));
472 /* The ioctl argument is the minor number of the second socket. */
473 if ((rc
= sys_safecopyfrom(endpt
, grant
, 0, (vir_bytes
) &minorin
,
474 sizeof(minorin
))) != OK
)
477 minory
= minor(minorin
);
479 dprintf(("UDS: socketpair(%d, %d,)\n", minorx
, minory
));
481 /* Security check: both sockets must have the same owner endpoint. */
482 if (uds_fd_table
[minorx
].owner
!= uds_fd_table
[minory
].owner
)
485 addr
.sun_family
= AF_UNIX
;
486 addr
.sun_path
[0] = 'X';
487 addr
.sun_path
[1] = '\0';
489 return perform_connection(minorx
, minory
, &addr
);
493 do_getsockopt_sotype(devminor_t minor
, endpoint_t endpt
, cp_grant_id_t grant
)
495 dprintf(("UDS: do_getsockopt_sotype(%d)\n", minor
));
497 /* If the type hasn't been set yet, we fail the call. */
498 if (uds_fd_table
[minor
].type
== -1)
501 return sys_safecopyto(endpt
, grant
, 0,
502 (vir_bytes
) &uds_fd_table
[minor
].type
, sizeof(int));
506 do_getsockopt_peercred(devminor_t minor
, endpoint_t endpt
, cp_grant_id_t grant
)
512 dprintf(("UDS: do_getsockopt_peercred(%d)\n", minor
));
514 if (uds_fd_table
[minor
].peer
== -1) {
515 if (uds_fd_table
[minor
].err
== ECONNRESET
) {
516 uds_fd_table
[minor
].err
= 0;
523 peer_minor
= uds_fd_table
[minor
].peer
;
525 /* Obtain the peer's credentials and copy them out. */
526 if ((rc
= getnucred(uds_fd_table
[peer_minor
].owner
, &cred
)) < 0)
529 return sys_safecopyto(endpt
, grant
, 0, (vir_bytes
) &cred
,
530 sizeof(struct uucred
));
534 do_getsockopt_sndbuf(devminor_t minor
, endpoint_t endpt
, cp_grant_id_t grant
)
536 size_t sndbuf
= UDS_BUF
;
538 dprintf(("UDS: do_getsockopt_sndbuf(%d)\n", minor
));
540 return sys_safecopyto(endpt
, grant
, 0, (vir_bytes
) &sndbuf
,
545 do_setsockopt_sndbuf(devminor_t minor
, endpoint_t endpt
, cp_grant_id_t grant
)
550 dprintf(("UDS: do_setsockopt_sndbuf(%d)\n", minor
));
552 if ((rc
= sys_safecopyfrom(endpt
, grant
, 0, (vir_bytes
) &sndbuf
,
553 sizeof(sndbuf
))) != OK
)
556 /* The send buffer is limited to 32KB at the moment. */
557 if (sndbuf
> UDS_BUF
)
560 /* FIXME: actually shrink the buffer. */
565 do_getsockopt_rcvbuf(devminor_t minor
, endpoint_t endpt
, cp_grant_id_t grant
)
567 size_t rcvbuf
= UDS_BUF
;
569 dprintf(("UDS: do_getsockopt_rcvbuf(%d)\n", minor
));
571 return sys_safecopyto(endpt
, grant
, 0, (vir_bytes
) &rcvbuf
,
576 do_setsockopt_rcvbuf(devminor_t minor
, endpoint_t endpt
, cp_grant_id_t grant
)
581 dprintf(("UDS: do_setsockopt_rcvbuf(%d)\n", minor
));
583 if ((rc
= sys_safecopyfrom(endpt
, grant
, 0, (vir_bytes
) &rcvbuf
,
584 sizeof(rcvbuf
))) != OK
)
587 /* The receive buffer is limited to 32KB at the moment. */
588 if (rcvbuf
> UDS_BUF
)
591 /* FIXME: actually shrink the buffer. */
596 do_sendto(devminor_t minor
, endpoint_t endpt
, cp_grant_id_t grant
)
599 struct sockaddr_un addr
;
601 dprintf(("UDS: do_sendto(%d)\n", minor
));
603 /* This IOCTL is only for SOCK_DGRAM sockets. */
604 if (uds_fd_table
[minor
].type
!= SOCK_DGRAM
)
607 if ((rc
= sys_safecopyfrom(endpt
, grant
, 0, (vir_bytes
) &addr
,
608 sizeof(struct sockaddr_un
))) != OK
)
611 /* Do some basic sanity checks on the address. */
612 if (addr
.sun_family
!= AF_UNIX
|| addr
.sun_path
[0] == '\0')
615 if ((rc
= checkperms(uds_fd_table
[minor
].owner
, addr
.sun_path
,
616 sizeof(addr
.sun_path
))) != OK
)
619 memcpy(&uds_fd_table
[minor
].target
, &addr
, sizeof(struct sockaddr_un
));
625 do_recvfrom(devminor_t minor
, endpoint_t endpt
, cp_grant_id_t grant
)
627 dprintf(("UDS: do_recvfrom(%d)\n", minor
));
629 return sys_safecopyto(endpt
, grant
, 0,
630 (vir_bytes
) &uds_fd_table
[minor
].source
,
631 sizeof(struct sockaddr_un
));
635 send_fds(devminor_t minor
, struct msg_control
*msg_ctrl
,
636 struct ancillary
*data
)
638 int i
, rc
, nfds
, totalfds
;
640 struct msghdr msghdr
;
641 struct cmsghdr
*cmsg
= NULL
;
643 dprintf(("UDS: send_fds(%d)\n", minor
));
645 from_ep
= uds_fd_table
[minor
].owner
;
647 /* Obtain this socket's credentials. */
648 if ((rc
= getnucred(from_ep
, &data
->cred
)) < 0)
651 dprintf(("UDS: minor=%d cred={%d,%d,%d}\n", minor
, data
->cred
.pid
,
652 data
->cred
.uid
, data
->cred
.gid
));
654 totalfds
= data
->nfiledes
;
656 memset(&msghdr
, '\0', sizeof(struct msghdr
));
657 msghdr
.msg_control
= msg_ctrl
->msg_control
;
658 msghdr
.msg_controllen
= msg_ctrl
->msg_controllen
;
660 for (cmsg
= CMSG_FIRSTHDR(&msghdr
); cmsg
!= NULL
;
661 cmsg
= CMSG_NXTHDR(&msghdr
, cmsg
)) {
662 if (cmsg
->cmsg_level
!= SOL_SOCKET
||
663 cmsg
->cmsg_type
!= SCM_RIGHTS
)
666 nfds
= MIN((cmsg
->cmsg_len
-CMSG_LEN(0))/sizeof(int), OPEN_MAX
);
668 for (i
= 0; i
< nfds
; i
++) {
669 if (totalfds
== OPEN_MAX
)
672 data
->fds
[totalfds
] = ((int *) CMSG_DATA(cmsg
))[i
];
673 dprintf(("UDS: minor=%d fd[%d]=%d\n", minor
, totalfds
,
674 data
->fds
[totalfds
]));
679 for (i
= data
->nfiledes
; i
< totalfds
; i
++) {
680 if ((rc
= copyfd(from_ep
, data
->fds
[i
], COPYFD_FROM
)) < 0) {
681 printf("UDS: copyfd(COPYFD_FROM) failed: %d\n", rc
);
683 /* Revert the successful copyfd() calls made so far. */
684 for (i
--; i
>= data
->nfiledes
; i
--)
690 dprintf(("UDS: send_fds(): %d -> %d\n", data
->fds
[i
], rc
));
692 data
->fds
[i
] = rc
; /* this is now the local FD */
695 data
->nfiledes
= totalfds
;
701 * This function calls close() for all of the FDs in flight. This is used
702 * when a Unix Domain Socket is closed and there exists references to file
703 * descriptors that haven't been received with recvmsg().
706 uds_clear_fds(devminor_t minor
, struct ancillary
*data
)
710 dprintf(("UDS: uds_clear_fds(%d)\n", minor
));
712 for (i
= 0; i
< data
->nfiledes
; i
++) {
713 dprintf(("UDS: uds_clear_fds() => %d\n", data
->fds
[i
]));
726 recv_fds(devminor_t minor
, struct ancillary
*data
,
727 struct msg_control
*msg_ctrl
)
729 int rc
, i
, j
, fds
[OPEN_MAX
];
730 struct msghdr msghdr
;
731 struct cmsghdr
*cmsg
;
734 dprintf(("UDS: recv_fds(%d)\n", minor
));
736 msghdr
.msg_control
= msg_ctrl
->msg_control
;
737 msghdr
.msg_controllen
= msg_ctrl
->msg_controllen
;
739 cmsg
= CMSG_FIRSTHDR(&msghdr
);
740 cmsg
->cmsg_len
= CMSG_LEN(sizeof(int) * data
->nfiledes
);
741 cmsg
->cmsg_level
= SOL_SOCKET
;
742 cmsg
->cmsg_type
= SCM_RIGHTS
;
744 to_ep
= uds_fd_table
[minor
].owner
;
746 /* Copy to the target endpoint. */
747 for (i
= 0; i
< data
->nfiledes
; i
++) {
748 if ((rc
= copyfd(to_ep
, data
->fds
[i
], COPYFD_TO
)) < 0) {
749 printf("UDS: copyfd(COPYFD_TO) failed: %d\n", rc
);
751 /* Revert the successful copyfd() calls made so far. */
752 for (i
--; i
>= 0; i
--)
753 (void) copyfd(to_ep
, fds
[i
], COPYFD_CLOSE
);
758 fds
[i
] = rc
; /* this is now the remote FD */
761 /* Close the local copies only once the entire procedure succeeded. */
762 for (i
= 0; i
< data
->nfiledes
; i
++) {
763 dprintf(("UDS: recv_fds(): %d -> %d\n", data
->fds
[i
], fds
[i
]));
765 ((int *)CMSG_DATA(cmsg
))[i
] = fds
[i
];
778 recv_cred(devminor_t minor
, struct ancillary
*data
,
779 struct msg_control
*msg_ctrl
)
781 struct msghdr msghdr
;
782 struct cmsghdr
*cmsg
;
784 dprintf(("UDS: recv_cred(%d)\n", minor
));
786 msghdr
.msg_control
= msg_ctrl
->msg_control
;
787 msghdr
.msg_controllen
= msg_ctrl
->msg_controllen
;
789 cmsg
= CMSG_FIRSTHDR(&msghdr
);
790 if (cmsg
->cmsg_len
> 0)
791 cmsg
= CMSG_NXTHDR(&msghdr
, cmsg
);
793 cmsg
->cmsg_len
= CMSG_LEN(sizeof(struct uucred
));
794 cmsg
->cmsg_level
= SOL_SOCKET
;
795 cmsg
->cmsg_type
= SCM_CREDS
;
796 memcpy(CMSG_DATA(cmsg
), &data
->cred
, sizeof(struct uucred
));
802 do_sendmsg(devminor_t minor
, endpoint_t endpt
, cp_grant_id_t grant
)
805 struct msg_control msg_ctrl
;
807 dprintf(("UDS: do_sendmsg(%d)\n", minor
));
809 memset(&msg_ctrl
, '\0', sizeof(struct msg_control
));
811 if ((rc
= sys_safecopyfrom(endpt
, grant
, 0, (vir_bytes
) &msg_ctrl
,
812 sizeof(struct msg_control
))) != OK
)
815 /* Locate the peer. */
817 if (uds_fd_table
[minor
].type
== SOCK_DGRAM
) {
818 if (uds_fd_table
[minor
].target
.sun_path
[0] == '\0' ||
819 uds_fd_table
[minor
].target
.sun_family
!= AF_UNIX
)
822 for (i
= 0; i
< NR_FDS
; i
++) {
824 * Look for a SOCK_DGRAM socket that is bound on the
827 if (uds_fd_table
[i
].type
== SOCK_DGRAM
&&
828 uds_fd_table
[i
].addr
.sun_family
== AF_UNIX
&&
829 !strncmp(uds_fd_table
[minor
].target
.sun_path
,
830 uds_fd_table
[i
].addr
.sun_path
,
831 sizeof(uds_fd_table
[i
].addr
.sun_path
))) {
840 peer
= uds_fd_table
[minor
].peer
;
845 dprintf(("UDS: sendmsg(%d) -- peer=%d\n", minor
, peer
));
848 * Note: it's possible that there is already some file descriptors in
849 * ancillary_data if the peer didn't call recvmsg() yet. That's okay.
850 * The receiver will get the current file descriptors plus the new
853 return send_fds(minor
, &msg_ctrl
, &uds_fd_table
[peer
].ancillary_data
);
857 do_recvmsg(devminor_t minor
, endpoint_t endpt
, cp_grant_id_t grant
)
860 struct msg_control msg_ctrl
;
861 socklen_t clen_avail
= 0;
862 socklen_t clen_needed
= 0;
863 socklen_t clen_desired
= 0;
865 dprintf(("UDS: do_recvmsg(%d)\n", minor
));
866 dprintf(("UDS: minor=%d credentials={pid:%d,uid:%d,gid:%d}\n", minor
,
867 uds_fd_table
[minor
].ancillary_data
.cred
.pid
,
868 uds_fd_table
[minor
].ancillary_data
.cred
.uid
,
869 uds_fd_table
[minor
].ancillary_data
.cred
.gid
));
871 memset(&msg_ctrl
, '\0', sizeof(struct msg_control
));
874 * Get the msg_control from the user. It will include the
875 * amount of space the user has allocated for control data.
877 if ((rc
= sys_safecopyfrom(endpt
, grant
, 0, (vir_bytes
) &msg_ctrl
,
878 sizeof(struct msg_control
))) != OK
)
881 clen_avail
= MIN(msg_ctrl
.msg_controllen
, MSG_CONTROL_MAX
);
883 if (uds_fd_table
[minor
].ancillary_data
.nfiledes
> 0) {
884 clen_needed
= CMSG_SPACE(sizeof(int) *
885 uds_fd_table
[minor
].ancillary_data
.nfiledes
);
888 /* if there is room we also include credentials */
889 clen_desired
= clen_needed
+ CMSG_SPACE(sizeof(struct uucred
));
891 if (clen_needed
> clen_avail
)
894 if (uds_fd_table
[minor
].ancillary_data
.nfiledes
> 0) {
895 if ((rc
= recv_fds(minor
, &uds_fd_table
[minor
].ancillary_data
,
900 if (clen_desired
<= clen_avail
) {
901 rc
= recv_cred(minor
, &uds_fd_table
[minor
].ancillary_data
,
905 msg_ctrl
.msg_controllen
= clen_desired
;
907 msg_ctrl
.msg_controllen
= clen_needed
;
909 /* Send the control data to the user. */
910 return sys_safecopyto(endpt
, grant
, 0, (vir_bytes
) &msg_ctrl
,
911 sizeof(struct msg_control
));
915 do_fionread(devminor_t minor
, endpoint_t endpt
, cp_grant_id_t grant
)
919 rc
= uds_perform_read(minor
, NONE
, GRANT_INVALID
, UDS_BUF
, 1);
921 /* What should we do on error? Just set to zero for now. */
925 return sys_safecopyto(endpt
, grant
, 0, (vir_bytes
) &rc
, sizeof(rc
));
929 uds_do_ioctl(devminor_t minor
, unsigned long request
, endpoint_t endpt
,
936 /* Connect to a listening socket -- connect(). */
937 rc
= do_connect(minor
, endpt
, grant
);
942 /* Accept an incoming connection -- accept(). */
943 rc
= do_accept(minor
, endpt
, grant
);
949 * Set the backlog_size and put the socket into the listening
952 rc
= do_listen(minor
, endpt
, grant
);
957 /* Set the SOCK_ type for this socket -- socket(). */
958 rc
= do_socket(minor
, endpt
, grant
);
963 /* Set the address for this socket -- bind(). */
964 rc
= do_bind(minor
, endpt
, grant
);
969 /* Get the address for this socket -- getsockname(). */
970 rc
= do_getsockname(minor
, endpt
, grant
);
975 /* Get the address for the peer -- getpeername(). */
976 rc
= do_getpeername(minor
, endpt
, grant
);
982 * Shut down a socket for reading, writing, or both --
985 rc
= do_shutdown(minor
, endpt
, grant
);
990 /* Connect two sockets -- socketpair(). */
991 rc
= do_socketpair(minor
, endpt
, grant
);
996 /* Get socket type -- getsockopt(SO_TYPE). */
997 rc
= do_getsockopt_sotype(minor
, endpt
, grant
);
1001 case NWIOGUDSPEERCRED
:
1002 /* Get peer endpoint -- getsockopt(SO_PEERCRED). */
1003 rc
= do_getsockopt_peercred(minor
, endpt
, grant
);
1008 /* Set target address -- sendto(). */
1009 rc
= do_sendto(minor
, endpt
, grant
);
1014 /* Get from address -- recvfrom(). */
1015 rc
= do_recvfrom(minor
, endpt
, grant
);
1019 case NWIOGUDSSNDBUF
:
1020 /* Get the send buffer size -- getsockopt(SO_SNDBUF). */
1021 rc
= do_getsockopt_sndbuf(minor
, endpt
, grant
);
1025 case NWIOSUDSSNDBUF
:
1026 /* Set the send buffer size -- setsockopt(SO_SNDBUF). */
1027 rc
= do_setsockopt_sndbuf(minor
, endpt
, grant
);
1031 case NWIOGUDSRCVBUF
:
1032 /* Get the send buffer size -- getsockopt(SO_SNDBUF). */
1033 rc
= do_getsockopt_rcvbuf(minor
, endpt
, grant
);
1037 case NWIOSUDSRCVBUF
:
1038 /* Set the send buffer size -- setsockopt(SO_SNDBUF). */
1039 rc
= do_setsockopt_rcvbuf(minor
, endpt
, grant
);
1044 /* Set the control data -- sendmsg(). */
1045 rc
= do_sendmsg(minor
, endpt
, grant
);
1050 /* Set the control data -- recvmsg(). */
1051 rc
= do_recvmsg(minor
, endpt
, grant
);
1057 * Get the number of bytes immediately available for reading.
1059 rc
= do_fionread(minor
, endpt
, grant
);
1065 * The IOCTL command is not valid for /dev/uds -- this happens
1066 * a lot and is normal. A lot of libc functions determine the
1067 * socket type with IOCTLs. Any unrecognized requests simply
1068 * get an ENOTTY response.