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.
6 * The entry points into this file are...
8 * uds_init: initialize the descriptor table.
9 * do_accept: handles the accept(2) syscall.
10 * do_connect: handles the connect(2) syscall.
11 * do_listen: handles the listen(2) syscall.
12 * do_socket: handles the socket(2) syscall.
13 * do_bind: handles the bind(2) syscall.
14 * do_getsockname: handles the getsockname(2) syscall.
15 * do_getpeername: handles the getpeername(2) syscall.
16 * do_shutdown: handles the shutdown(2) syscall.
17 * do_socketpair: handles the socketpair(2) syscall.
18 * do_getsockopt_sotype: handles the getsockopt(2) syscall.
19 * do_getsockopt_peercred: handles the getsockopt(2) syscall.
20 * do_getsockopt_sndbuf: handles the getsockopt(2) syscall.
21 * do_setsockopt_sndbuf: handles the setsockopt(2) syscall.
22 * do_getsockopt_rcvbuf: handles the getsockopt(2) syscall.
23 * do_setsockopt_rcvbuf: handles the setsockopt(2) syscall.
24 * do_sendto: handles the sendto(2) syscall.
25 * do_recvfrom: handles the recvfrom(2) syscall.
26 * do_sendmsg: handles the sendmsg(2) syscall.
27 * do_recvmsg: handles the recvmsg(2) syscall.
28 * perform_connection: performs the connection of two descriptors.
29 * clear_fds: calls put_filp for undelivered FDs.
33 * table.c, dev_uds.c, uds.h
43 /* File Descriptor Table */
44 uds_fd_t uds_fd_table
[NR_FDS
];
46 /* initialize the descriptor table */
50 * Setting everything to NULL implicitly sets the
53 memset(uds_fd_table
, '\0', sizeof(uds_fd_t
) * NR_FDS
);
56 /* check the permissions of a socket file */
57 static int check_perms(int minor
, struct sockaddr_un
*addr
)
61 cp_grant_id_t grant_id
;
63 grant_id
= cpf_grant_direct(VFS_PROC_NR
, (vir_bytes
) addr
->sun_path
,
64 UNIX_PATH_MAX
, CPF_READ
| CPF_WRITE
);
66 /* ask the VFS to verify the permissions */
67 memset(&vfs_m
, '\0', sizeof(message
));
69 vfs_m
.m_type
= PFS_REQ_CHECK_PERMS
;
70 vfs_m
.USER_ENDPT
= uds_fd_table
[minor
].owner
;
71 vfs_m
.IO_GRANT
= (char *) grant_id
;
72 vfs_m
.COUNT
= UNIX_PATH_MAX
;
74 rc
= sendrec(VFS_PROC_NR
, &vfs_m
);
77 printf("(uds) sendrec error... req_nr: %d err: %d\n",
84 printf("(uds) VFS reply => %d\n", vfs_m
.m_type
);
85 printf("(uds) Canonical Path => %s\n", addr
->sun_path
);
88 return vfs_m
.m_type
; /* return reply code OK, ELOOP, etc. */
91 static filp_id_t
verify_fd(endpoint_t ep
, int fd
)
97 static int call_count
= 0;
98 printf("(uds) verify_fd(%d,%d) call_count=%d\n", ep
, fd
,
102 memset(&vfs_m
, '\0', sizeof(message
));
104 vfs_m
.m_type
= PFS_REQ_VERIFY_FD
;
105 vfs_m
.USER_ENDPT
= ep
;
108 rc
= sendrec(VFS_PROC_NR
, &vfs_m
);
110 printf("(uds) sendrec error... req_nr: %d err: %d\n",
116 printf("(uds) VFS reply => %d\n", vfs_m
.m_type
);
119 return vfs_m
.ADDRESS
;
122 static int set_filp(filp_id_t sfilp
)
128 static int call_count
= 0;
129 printf("(uds) set_filp(0x%x) call_count=%d\n", sfilp
, ++call_count
);
132 memset(&vfs_m
, '\0', sizeof(message
));
134 vfs_m
.m_type
= PFS_REQ_SET_FILP
;
135 vfs_m
.ADDRESS
= sfilp
;
137 rc
= sendrec(VFS_PROC_NR
, &vfs_m
);
139 printf("(uds) sendrec error... req_nr: %d err: %d\n",
145 printf("(uds) VFS reply => %d\n", vfs_m
.m_type
);
147 return vfs_m
.m_type
; /* return reply code OK, ELOOP, etc. */
150 static int copy_filp(endpoint_t to_ep
, filp_id_t cfilp
)
156 static int call_count
= 0;
157 printf("(uds) copy_filp(%d, 0x%x) call_count=%d\n",to_ep
, cfilp
,
161 memset(&vfs_m
, '\0', sizeof(message
));
163 vfs_m
.m_type
= PFS_REQ_COPY_FILP
;
164 vfs_m
.USER_ENDPT
= to_ep
;
165 vfs_m
.ADDRESS
= cfilp
;
167 rc
= sendrec(VFS_PROC_NR
, &vfs_m
);
169 printf("(uds) sendrec error... req_nr: %d err: %d\n",
175 printf("(uds) VFS reply => %d\n", vfs_m
.m_type
);
180 static int put_filp(filp_id_t pfilp
)
186 static int call_count
= 0;
187 printf("(uds) put_filp(0x%x) call_count=%d\n", pfilp
, ++call_count
);
190 memset(&vfs_m
, '\0', sizeof(message
));
192 vfs_m
.m_type
= PFS_REQ_PUT_FILP
;
193 vfs_m
.ADDRESS
= pfilp
;
195 rc
= sendrec(VFS_PROC_NR
, &vfs_m
);
197 printf("(uds) sendrec error... req_nr: %d err: %d\n",
203 printf("(uds) VFS reply => %d\n", vfs_m
.m_type
);
205 return vfs_m
.m_type
; /* return reply code OK, ELOOP, etc. */
208 static int cancel_fd(endpoint_t ep
, int fd
)
214 static int call_count
= 0;
215 printf("(uds) cancel_fd(%d,%d) call_count=%d\n", ep
, fd
, ++call_count
);
218 memset(&vfs_m
, '\0', sizeof(message
));
220 vfs_m
.m_type
= PFS_REQ_CANCEL_FD
;
221 vfs_m
.USER_ENDPT
= ep
;
224 rc
= sendrec(VFS_PROC_NR
, &vfs_m
);
226 printf("(uds) sendrec error... req_nr: %d err: %d\n",
232 printf("(uds) VFS reply => %d\n", vfs_m
.m_type
);
234 return vfs_m
.m_type
; /* return reply code OK, ELOOP, etc. */
237 int perform_connection(message
*dev_m_in
, message
*dev_m_out
,
238 struct sockaddr_un
*addr
, int minorx
, int minory
)
240 /* there are several places were a connection is established. */
241 /* accept(2), connect(2), uds_status(2), socketpair(2) */
242 /* This is a helper function to make sure it is done in the */
243 /* same way in each place with the same validation checks. */
246 static int call_count
= 0;
247 printf("(uds) [%d] perform_connection() call_count=%d\n",
248 uds_minor(dev_m_in
), ++call_count
);
251 /* only connection oriented types are acceptable and only like
252 * types can connect to each other
254 if ((uds_fd_table
[minorx
].type
!= SOCK_SEQPACKET
&&
255 uds_fd_table
[minorx
].type
!= SOCK_STREAM
) ||
256 uds_fd_table
[minorx
].type
!= uds_fd_table
[minory
].type
) {
258 /* sockets are not in a valid state */
262 /* connect the pair of sockets */
263 uds_fd_table
[minorx
].peer
= minory
;
264 uds_fd_table
[minory
].peer
= minorx
;
266 /* Set the address of both sockets */
267 memcpy(&(uds_fd_table
[minorx
].addr
), addr
, sizeof(struct sockaddr_un
));
268 memcpy(&(uds_fd_table
[minory
].addr
), addr
, sizeof(struct sockaddr_un
));
274 int do_accept(message
*dev_m_in
, message
*dev_m_out
)
277 int minorparent
; /* minor number of parent (server) */
280 struct sockaddr_un addr
;
283 static int call_count
= 0;
284 printf("(uds) [%d] do_accept() call_count=%d\n",
285 uds_minor(dev_m_in
), ++call_count
);
288 /* Somewhat weird logic is used in this function, so here's an
289 * overview... The minor number is the server's client socket
290 * (the socket to be returned by accept()). The data waiting
291 * for us in the IO Grant is the address that the server is
292 * listening on. This function uses the address to find the
293 * server's descriptor. From there we can perform the
294 * connection or suspend and wait for a connect().
297 minor
= uds_minor(dev_m_in
);
299 if (uds_fd_table
[minor
].type
!= -1) {
300 /* this IOCTL must be called on a 'fresh' socket */
304 /* Get the server's address */
305 rc
= sys_safecopyfrom(VFS_PROC_NR
, (cp_grant_id_t
) dev_m_in
->IO_GRANT
,
306 (vir_bytes
) 0, (vir_bytes
) &addr
, sizeof(struct sockaddr_un
));
312 /* locate server socket */
313 rc
= -1; /* to trap error */
315 for (i
= 0; i
< NR_FDS
; i
++) {
317 if (uds_fd_table
[i
].addr
.sun_family
== AF_UNIX
&&
318 !strncmp(addr
.sun_path
,
319 uds_fd_table
[i
].addr
.sun_path
,
321 uds_fd_table
[i
].listening
== 1) {
329 /* there is no server listening on addr. Maybe someone
330 * screwed up the ioctl()?
335 minorparent
= i
; /* parent */
337 /* we are the parent's child */
338 uds_fd_table
[minorparent
].child
= minor
;
340 /* the peer has the same type as the parent. we need to be that
343 uds_fd_table
[minor
].type
= uds_fd_table
[minorparent
].type
;
345 /* locate peer to accept in the parent's backlog */
346 minorpeer
= -1; /* to trap error */
347 for (i
= 0; i
< uds_fd_table
[minorparent
].backlog_size
; i
++) {
348 if (uds_fd_table
[minorparent
].backlog
[i
] != -1) {
349 minorpeer
= uds_fd_table
[minorparent
].backlog
[i
];
350 uds_fd_table
[minorparent
].backlog
[i
] = -1;
356 if (minorpeer
== -1) {
359 printf("(uds) [%d] {do_accept} suspend\n", minor
);
362 /* there are no peers in the backlog, suspend and wait
363 * for some to show up
365 uds_fd_table
[minor
].suspended
= UDS_SUSPENDED_ACCEPT
;
371 printf("(uds) [%d] connecting to %d -- parent is %d\n", minor
,
372 minorpeer
, minorparent
);
375 rc
= perform_connection(dev_m_in
, dev_m_out
, &addr
, minor
, minorpeer
);
378 printf("(uds) [%d] {do_accept} connection not performed\n",
384 uds_fd_table
[minorparent
].child
= -1;
386 /* if peer is blocked on connect() revive peer */
387 if (uds_fd_table
[minorpeer
].suspended
) {
389 printf("(uds) [%d] {do_accept} revive %d\n", minor
,
392 uds_fd_table
[minorpeer
].ready_to_revive
= 1;
393 uds_unsuspend(dev_m_in
->m_source
, minorpeer
);
399 int do_connect(message
*dev_m_in
, message
*dev_m_out
)
402 struct sockaddr_un addr
;
406 static int call_count
= 0;
407 printf("(uds) [%d] do_connect() call_count=%d\n", uds_minor(dev_m_in
),
411 minor
= uds_minor(dev_m_in
);
413 /* only connection oriented sockets can connect */
414 if (uds_fd_table
[minor
].type
!= SOCK_STREAM
&&
415 uds_fd_table
[minor
].type
!= SOCK_SEQPACKET
) {
419 if (uds_fd_table
[minor
].peer
!= -1) {
420 /* socket is already connected */
424 rc
= sys_safecopyfrom(VFS_PROC_NR
, (cp_grant_id_t
) dev_m_in
->IO_GRANT
,
425 (vir_bytes
) 0, (vir_bytes
) &addr
,
426 sizeof(struct sockaddr_un
));
432 rc
= check_perms(minor
, &addr
);
434 /* permission denied, socket file doesn't exist, etc. */
438 /* look for a socket of the same type that is listening on the
439 * address we want to connect to
441 for (i
= 0; i
< NR_FDS
; i
++) {
443 if (uds_fd_table
[minor
].type
== uds_fd_table
[i
].type
&&
444 uds_fd_table
[i
].listening
&&
445 uds_fd_table
[i
].addr
.sun_family
== AF_UNIX
&&
446 !strncmp(addr
.sun_path
, uds_fd_table
[i
].addr
.sun_path
,
449 if (uds_fd_table
[i
].child
!= -1) {
451 /* the server is blocked on accept(2) --
452 * perform connection to the child
455 rc
= perform_connection(dev_m_in
, dev_m_out
,
456 &addr
, minor
, uds_fd_table
[i
].child
);
460 uds_fd_table
[i
].child
= -1;
463 printf("(uds) [%d] {do_connect} revive %d\n", minor
, i
);
466 /* wake the parent (server) */
467 uds_fd_table
[i
].ready_to_revive
= 1;
468 uds_unsuspend(dev_m_in
->m_source
, i
);
476 printf("(uds) [%d] adding to %d's backlog\n",
480 /* tell the server were waiting to be served */
482 /* look for a free slot in the backlog */
483 rc
= -1; /* to trap error */
484 for (j
= 0; j
< uds_fd_table
[i
].backlog_size
;
487 if (uds_fd_table
[i
].backlog
[j
] == -1) {
489 uds_fd_table
[i
].backlog
[j
] =
499 /* backlog is full */
503 /* see if the server is blocked on select() */
504 if (uds_fd_table
[i
].selecting
== 1) {
506 /* if the server wants to know
507 * about data ready to read and
508 * it doesn't know about it
509 * already, then let the server
510 * know we have data for it.
512 if ((uds_fd_table
[i
].sel_ops_in
&
514 !(uds_fd_table
[i
].sel_ops_out
&
517 uds_fd_table
[i
].sel_ops_out
|=
519 uds_fd_table
[i
].status_updated
523 dev_m_in
->m_source
, i
);
527 /* we found our server */
528 uds_fd_table
[minor
].peer
= i
;
530 /* set the address */
531 memcpy(&(uds_fd_table
[minor
].addr
), &addr
,
532 sizeof(struct sockaddr_un
));
539 if (uds_fd_table
[minor
].peer
== -1) {
540 /* could not find another open socket listening on the
541 * specified address with room in the backlog
547 printf("(uds) [%d] {do_connect} suspend\n", minor
);
550 /* suspend until the server side completes the connection with accept()
553 uds_fd_table
[minor
].suspended
= UDS_SUSPENDED_CONNECT
;
558 int do_listen(message
*dev_m_in
, message
*dev_m_out
)
565 static int call_count
= 0;
566 printf("(uds) [%d] do_listen() call_count=%d\n", uds_minor(dev_m_in
),
570 minor
= uds_minor(dev_m_in
);
572 /* ensure the socket has a type and is bound */
573 if (uds_fd_table
[minor
].type
== -1 ||
574 uds_fd_table
[minor
].addr
.sun_family
!= AF_UNIX
) {
576 /* probably trying to call listen() before bind() */
580 /* the two supported types for listen(2) are SOCK_STREAM and
583 if (uds_fd_table
[minor
].type
!= SOCK_STREAM
&&
584 uds_fd_table
[minor
].type
!= SOCK_SEQPACKET
) {
586 /* probably trying to call listen() with a SOCK_DGRAM */
590 /* The POSIX standard doesn't say what to do if listen() has
591 * already been called. Well, there isn't an errno. we silently
592 * let it happen, but if listen() has already been called, we
593 * don't allow the backlog to shrink
595 rc
= sys_safecopyfrom(VFS_PROC_NR
, (cp_grant_id_t
) dev_m_in
->IO_GRANT
,
596 (vir_bytes
) 0, (vir_bytes
) &backlog_size
, sizeof(int));
602 if (uds_fd_table
[minor
].listening
== 0) {
604 /* See if backlog_size is between 0 and UDS_SOMAXCONN */
605 if (backlog_size
>= 0 && backlog_size
< UDS_SOMAXCONN
) {
607 /* use the user provided backlog_size */
608 uds_fd_table
[minor
].backlog_size
= backlog_size
;
612 /* the user gave an invalid size, use
613 * UDS_SOMAXCONN instead
615 uds_fd_table
[minor
].backlog_size
= UDS_SOMAXCONN
;
619 /* See if the user is trying to expand the backlog_size */
620 if (backlog_size
> uds_fd_table
[minor
].backlog_size
&&
621 backlog_size
< UDS_SOMAXCONN
) {
623 /* expand backlog_size */
624 uds_fd_table
[minor
].backlog_size
= backlog_size
;
627 /* Don't let the user shrink the backlog_size (we might
628 * have clients waiting in those slots
632 /* perform listen(2) */
633 uds_fd_table
[minor
].listening
= 1;
638 int do_socket(message
*dev_m_in
, message
*dev_m_out
)
644 static int call_count
= 0;
645 printf("(uds) [%d] do_socket() call_count=%d\n", uds_minor(dev_m_in
),
649 minor
= uds_minor(dev_m_in
);
651 /* see if this socket already has a type */
652 if (uds_fd_table
[minor
].type
!= -1) {
653 /* socket type can only be set once */
657 /* get the requested type */
658 rc
= sys_safecopyfrom(VFS_PROC_NR
, (cp_grant_id_t
) dev_m_in
->IO_GRANT
,
659 (vir_bytes
) 0, (vir_bytes
) &(uds_fd_table
[minor
].type
),
664 /* something went wrong and we couldn't get the type */
668 /* validate the type */
669 switch (uds_fd_table
[minor
].type
) {
674 /* the type is one of the 3 valid socket types */
679 /* if the type isn't one of the 3 valid socket
680 * types, then it must be invalid.
683 /* set the type back to '-1' (no type set) */
684 uds_fd_table
[minor
].type
= -1;
690 int do_bind(message
*dev_m_in
, message
*dev_m_out
)
693 struct sockaddr_un addr
;
697 static int call_count
= 0;
698 printf("(uds) [%d] do_bind() call_count=%d\n", uds_minor(dev_m_in
),
702 minor
= uds_minor(dev_m_in
);
704 if ((uds_fd_table
[minor
].type
== -1) ||
705 (uds_fd_table
[minor
].addr
.sun_family
== AF_UNIX
&&
706 uds_fd_table
[minor
].type
!= SOCK_DGRAM
)) {
708 /* the type hasn't been set by do_socket() yet OR attempting
709 * to re-bind() a non-SOCK_DGRAM socket
714 rc
= sys_safecopyfrom(VFS_PROC_NR
, (cp_grant_id_t
) dev_m_in
->IO_GRANT
,
715 (vir_bytes
) 0, (vir_bytes
) &addr
, sizeof(struct sockaddr_un
));
721 /* do some basic sanity checks on the address */
722 if (addr
.sun_family
!= AF_UNIX
) {
728 if (addr
.sun_path
[0] == '\0') {
734 rc
= check_perms(minor
, &addr
);
736 /* permission denied, socket file doesn't exist, etc. */
740 /* make sure the address isn't already in use by another socket. */
741 for (i
= 0; i
< NR_FDS
; i
++) {
742 if ((uds_fd_table
[i
].addr
.sun_family
== AF_UNIX
) &&
743 !strncmp(addr
.sun_path
,
744 uds_fd_table
[i
].addr
.sun_path
, UNIX_PATH_MAX
)) {
746 /* another socket is bound to this sun_path */
751 /* looks good, perform the bind() */
752 memcpy(&(uds_fd_table
[minor
].addr
), &addr
, sizeof(struct sockaddr_un
));
757 int do_getsockname(message
*dev_m_in
, message
*dev_m_out
)
763 static int call_count
= 0;
764 printf("(uds) [%d] do_getsockname() call_count=%d\n",
765 uds_minor(dev_m_in
), ++call_count
);
768 minor
= uds_minor(dev_m_in
);
770 /* Unconditionally send the address we have assigned to this socket.
771 * The POSIX standard doesn't say what to do if the address
772 * hasn't been set. If the address isn't currently set, then
773 * the user will get NULL bytes. Note: libc depends on this
776 rc
= sys_safecopyto(VFS_PROC_NR
, (cp_grant_id_t
) dev_m_in
->IO_GRANT
,
777 (vir_bytes
) 0, (vir_bytes
) &(uds_fd_table
[minor
].addr
),
778 sizeof(struct sockaddr_un
));
780 return rc
? EIO
: OK
;
783 int do_getpeername(message
*dev_m_in
, message
*dev_m_out
)
789 static int call_count
= 0;
790 printf("(uds) [%d] do_getpeername() call_count=%d\n",
791 uds_minor(dev_m_in
), ++call_count
);
794 minor
= uds_minor(dev_m_in
);
796 /* check that the socket is connected with a valid peer */
797 if (uds_fd_table
[minor
].peer
!= -1) {
800 peer_minor
= uds_fd_table
[minor
].peer
;
802 /* copy the address from the peer */
803 rc
= sys_safecopyto(VFS_PROC_NR
,
804 (cp_grant_id_t
) dev_m_in
->IO_GRANT
, (vir_bytes
) 0,
805 (vir_bytes
) &(uds_fd_table
[peer_minor
].addr
),
806 sizeof(struct sockaddr_un
));
808 return rc
? EIO
: OK
;
810 if (uds_fd_table
[minor
].err
== ECONNRESET
) {
811 uds_fd_table
[minor
].err
= 0;
820 int do_shutdown(message
*dev_m_in
, message
*dev_m_out
)
826 static int call_count
= 0;
827 printf("(uds) [%d] do_shutdown() call_count=%d\n",
828 uds_minor(dev_m_in
), ++call_count
);
831 minor
= uds_minor(dev_m_in
);
833 if (uds_fd_table
[minor
].type
!= SOCK_STREAM
&&
834 uds_fd_table
[minor
].type
!= SOCK_SEQPACKET
) {
836 /* socket must be a connection oriented socket */
840 if (uds_fd_table
[minor
].peer
== -1) {
841 /* shutdown(2) is only valid for connected sockets */
842 if (uds_fd_table
[minor
].err
== ECONNRESET
) {
849 /* get the 'how' parameter from the process */
850 rc
= sys_safecopyfrom(VFS_PROC_NR
, (cp_grant_id_t
) dev_m_in
->IO_GRANT
,
851 (vir_bytes
) 0, (vir_bytes
) &how
, sizeof(int));
859 /* take away read permission */
860 uds_fd_table
[minor
].mode
=
861 uds_fd_table
[minor
].mode
^ S_IRUSR
;
865 /* take away write permission */
866 uds_fd_table
[minor
].mode
=
867 uds_fd_table
[minor
].mode
^ S_IWUSR
;
871 /* completely shutdown */
872 uds_fd_table
[minor
].mode
= 0;
876 /* the 'how' parameter is invalid */
883 int do_socketpair_old(message
*dev_m_in
, message
*dev_m_out
)
888 struct sockaddr_un addr
;
891 static int call_count
= 0;
892 printf("(uds) [%d] do_socketpair() call_count=%d\n",
893 uds_minor(dev_m_in
), ++call_count
);
896 /* first ioctl param is the first socket */
897 minorx
= uds_minor_old(dev_m_in
);
899 /* third ioctl param is the minor number of the second socket */
900 rc
= sys_safecopyfrom(VFS_PROC_NR
, (cp_grant_id_t
) dev_m_in
->IO_GRANT
,
901 (vir_bytes
) 0, (vir_bytes
) &minorin
, sizeof(short));
907 minory
= minor(minorin
);
910 printf("socketpair() %d - %d\n", minorx
, minory
);
913 /* security check - both sockets must have the same endpoint (owner) */
914 if (uds_fd_table
[minorx
].owner
!= uds_fd_table
[minory
].owner
) {
916 /* we won't allow you to magically connect your socket to
917 * someone elses socket
922 addr
.sun_family
= AF_UNIX
;
923 addr
.sun_path
[0] = 'X';
924 addr
.sun_path
[1] = '\0';
926 uds_fd_table
[minorx
].syscall_done
= 1;
927 return perform_connection(dev_m_in
, dev_m_out
, &addr
, minorx
, minory
);
930 int do_socketpair(message
*dev_m_in
, message
*dev_m_out
)
935 struct sockaddr_un addr
;
938 static int call_count
= 0;
939 printf("(uds) [%d] do_socketpair() call_count=%d\n",
940 uds_minor(dev_m_in
), ++call_count
);
943 /* first ioctl param is the first socket */
944 minorx
= uds_minor(dev_m_in
);
946 /* third ioctl param is the minor number of the second socket */
947 rc
= sys_safecopyfrom(VFS_PROC_NR
, (cp_grant_id_t
) dev_m_in
->IO_GRANT
,
948 (vir_bytes
) 0, (vir_bytes
) &minorin
, sizeof(dev_t
));
954 minory
= minor(minorin
);
957 printf("socketpair() %d - %d\n", minorx
, minory
);
960 /* security check - both sockets must have the same endpoint (owner) */
961 if (uds_fd_table
[minorx
].owner
!= uds_fd_table
[minory
].owner
) {
963 /* we won't allow you to magically connect your socket to
964 * someone elses socket
969 addr
.sun_family
= AF_UNIX
;
970 addr
.sun_path
[0] = 'X';
971 addr
.sun_path
[1] = '\0';
973 uds_fd_table
[minorx
].syscall_done
= 1;
974 return perform_connection(dev_m_in
, dev_m_out
, &addr
, minorx
, minory
);
977 int do_getsockopt_sotype(message
*dev_m_in
, message
*dev_m_out
)
983 static int call_count
= 0;
984 printf("(uds) [%d] do_getsockopt_sotype() call_count=%d\n",
985 uds_minor(dev_m_in
), ++call_count
);
988 minor
= uds_minor(dev_m_in
);
990 if (uds_fd_table
[minor
].type
== -1) {
992 /* the type hasn't been set yet. instead of returning an
993 * invalid type, we fail with EINVAL
998 rc
= sys_safecopyto(VFS_PROC_NR
, (cp_grant_id_t
) dev_m_in
->IO_GRANT
,
999 (vir_bytes
) 0, (vir_bytes
) &(uds_fd_table
[minor
].type
),
1002 return rc
? EIO
: OK
;
1005 int do_getsockopt_peercred(message
*dev_m_in
, message
*dev_m_out
)
1013 static int call_count
= 0;
1014 printf("(uds) [%d] do_getsockopt_peercred() call_count=%d\n",
1015 uds_minor(dev_m_in
), ++call_count
);
1018 minor
= uds_minor(dev_m_in
);
1020 if (uds_fd_table
[minor
].peer
== -1) {
1022 if (uds_fd_table
[minor
].err
== ECONNRESET
) {
1023 uds_fd_table
[minor
].err
= 0;
1031 peer_minor
= uds_fd_table
[minor
].peer
;
1033 /* obtain the peer's credentials */
1034 rc
= getnucred(uds_fd_table
[peer_minor
].owner
, &cred
);
1036 /* likely error: invalid endpoint / proc doesn't exist */
1040 rc
= sys_safecopyto(VFS_PROC_NR
, (cp_grant_id_t
) dev_m_in
->IO_GRANT
,
1041 (vir_bytes
) 0, (vir_bytes
) &cred
, sizeof(struct ucred
));
1043 return rc
? EIO
: OK
;
1046 int do_getsockopt_peercred_old(message
*dev_m_in
, message
*dev_m_out
)
1052 struct ucred_old cred_old
;
1055 static int call_count
= 0;
1056 printf("(uds) [%d] do_getsockopt_peercred() call_count=%d\n",
1057 uds_minor(dev_m_in
), ++call_count
);
1060 minor
= uds_minor(dev_m_in
);
1062 if (uds_fd_table
[minor
].peer
== -1) {
1064 if (uds_fd_table
[minor
].err
== ECONNRESET
) {
1065 uds_fd_table
[minor
].err
= 0;
1073 peer_minor
= uds_fd_table
[minor
].peer
;
1075 /* obtain the peer's credentials */
1076 rc
= getnucred(uds_fd_table
[peer_minor
].owner
, &cred
);
1078 /* likely error: invalid endpoint / proc doesn't exist */
1082 /* copy to old structure */
1083 cred_old
.pid
= cred
.pid
;
1084 cred_old
.uid
= (short) cred
.uid
;
1085 cred_old
.gid
= (char) cred
.gid
;
1087 rc
= sys_safecopyto(VFS_PROC_NR
, (cp_grant_id_t
) dev_m_in
->IO_GRANT
,
1088 (vir_bytes
) 0, (vir_bytes
) &cred_old
, sizeof(struct ucred_old
));
1090 return rc
? EIO
: OK
;
1093 int do_getsockopt_sndbuf(message
*dev_m_in
, message
*dev_m_out
)
1096 size_t sndbuf
= PIPE_BUF
;
1099 static int call_count
= 0;
1100 printf("(uds) [%d] do_getsockopt_sndbuf() call_count=%d\n",
1101 uds_minor(dev_m_in
), ++call_count
);
1104 rc
= sys_safecopyto(VFS_PROC_NR
, (cp_grant_id_t
) dev_m_in
->IO_GRANT
,
1105 (vir_bytes
) 0, (vir_bytes
) &(sndbuf
), sizeof(size_t));
1107 return rc
? EIO
: OK
;
1110 int do_setsockopt_sndbuf(message
*dev_m_in
, message
*dev_m_out
)
1116 static int call_count
= 0;
1117 printf("(uds) [%d] do_setsockopt_rcvbuf() call_count=%d\n",
1118 uds_minor(dev_m_in
), ++call_count
);
1121 rc
= sys_safecopyfrom(VFS_PROC_NR
, (cp_grant_id_t
) dev_m_in
->IO_GRANT
,
1122 (vir_bytes
) 0, (vir_bytes
) &sndbuf
,
1129 if (sndbuf
> PIPE_BUF
) {
1130 /* The send buffer is limited to 32K at the moment. */
1134 /* There is no way to reduce the send buffer, do we have to
1135 * let this call fail for smaller buffers?
1140 int do_getsockopt_rcvbuf(message
*dev_m_in
, message
*dev_m_out
)
1143 size_t rcvbuf
= PIPE_BUF
;
1146 static int call_count
= 0;
1147 printf("(uds) [%d] do_getsockopt_rcvbuf() call_count=%d\n",
1148 uds_minor(dev_m_in
), ++call_count
);
1151 rc
= sys_safecopyto(VFS_PROC_NR
, (cp_grant_id_t
) dev_m_in
->IO_GRANT
,
1152 (vir_bytes
) 0, (vir_bytes
) &(rcvbuf
), sizeof(size_t));
1154 return rc
? EIO
: OK
;
1157 int do_setsockopt_rcvbuf(message
*dev_m_in
, message
*dev_m_out
)
1163 static int call_count
= 0;
1164 printf("(uds) [%d] do_setsockopt_rcvbuf() call_count=%d\n",
1165 uds_minor(dev_m_in
), ++call_count
);
1168 rc
= sys_safecopyfrom(VFS_PROC_NR
, (cp_grant_id_t
) dev_m_in
->IO_GRANT
,
1169 (vir_bytes
) 0, (vir_bytes
) &rcvbuf
,
1176 if (rcvbuf
> PIPE_BUF
) {
1177 /* The send buffer is limited to 32K at the moment. */
1181 /* There is no way to reduce the send buffer, do we have to
1182 * let this call fail for smaller buffers?
1188 int do_sendto(message
*dev_m_in
, message
*dev_m_out
)
1192 struct sockaddr_un addr
;
1195 static int call_count
= 0;
1196 printf("(uds) [%d] do_sendto() call_count=%d\n", uds_minor(dev_m_in
),
1200 minor
= uds_minor(dev_m_in
);
1202 if (uds_fd_table
[minor
].type
!= SOCK_DGRAM
) {
1203 /* This IOCTL is only for SOCK_DGRAM sockets */
1207 rc
= sys_safecopyfrom(VFS_PROC_NR
, (cp_grant_id_t
) dev_m_in
->IO_GRANT
,
1208 (vir_bytes
) 0, (vir_bytes
) &addr
, sizeof(struct sockaddr_un
));
1214 /* do some basic sanity checks on the address */
1215 if (addr
.sun_family
!= AF_UNIX
|| addr
.sun_path
[0] == '\0') {
1220 rc
= check_perms(minor
, &addr
);
1225 memcpy(&(uds_fd_table
[minor
].target
), &addr
,
1226 sizeof(struct sockaddr_un
));
1231 int do_recvfrom(message
*dev_m_in
, message
*dev_m_out
)
1237 static int call_count
= 0;
1238 printf("(uds) [%d] do_recvfrom() call_count=%d\n",
1239 uds_minor(dev_m_in
), ++call_count
);
1242 minor
= uds_minor(dev_m_in
);
1244 rc
= sys_safecopyto(VFS_PROC_NR
, (cp_grant_id_t
) dev_m_in
->IO_GRANT
,
1245 (vir_bytes
) 0, (vir_bytes
) &(uds_fd_table
[minor
].source
),
1246 sizeof(struct sockaddr_un
));
1248 return rc
? EIO
: OK
;
1251 int msg_control_read(struct msg_control
*msg_ctrl
, struct ancillary
*data
,
1255 struct msghdr msghdr
;
1256 struct cmsghdr
*cmsg
= NULL
;
1259 static int call_count
= 0;
1260 printf("(uds) [%d] msg_control_read() call_count=%d\n", minor
,
1266 memset(&msghdr
, '\0', sizeof(struct msghdr
));
1267 msghdr
.msg_control
= msg_ctrl
->msg_control
;
1268 msghdr
.msg_controllen
= msg_ctrl
->msg_controllen
;
1270 for(cmsg
= CMSG_FIRSTHDR(&msghdr
); cmsg
!= NULL
;
1271 cmsg
= CMSG_NXTHDR(&msghdr
, cmsg
)) {
1273 if (cmsg
->cmsg_level
== SOL_SOCKET
&&
1274 cmsg
->cmsg_type
== SCM_RIGHTS
) {
1278 MIN((cmsg
->cmsg_len
-CMSG_LEN(0))/sizeof(int),
1281 for (i
= 0; i
< nfds
; i
++) {
1282 if (data
->nfiledes
== OPEN_MAX
) {
1286 data
->fds
[data
->nfiledes
] =
1287 ((int *) CMSG_DATA(cmsg
))[i
];
1289 printf("(uds) [%d] fd[%d]=%d\n", minor
,
1290 data
->nfiledes
, data
->fds
[data
->nfiledes
]);
1297 /* obtain this socket's credentials */
1298 rc
= getnucred(uds_fd_table
[minor
].owner
, &(data
->cred
));
1303 printf("(uds) [%d] cred={%d,%d,%d}\n", minor
,
1304 data
->cred
.pid
, data
->cred
.uid
,
1310 static int send_fds(int minor
, struct ancillary
*data
)
1315 static int call_count
= 0;
1316 printf("(uds) [%d] send_fds() call_count=%d\n", minor
, ++call_count
);
1319 /* verify the file descriptors and get their filps. */
1320 for (i
= 0; i
< data
->nfiledes
; i
++) {
1321 data
->filps
[i
] = verify_fd(uds_fd_table
[minor
].owner
,
1324 if (data
->filps
[i
] == NULL
) {
1329 /* set them as in-flight */
1330 for (i
= 0; i
< data
->nfiledes
; i
++) {
1331 rc
= set_filp(data
->filps
[i
]);
1333 /* revert set_filp() calls */
1334 for (j
= i
; j
>= 0; j
--) {
1335 put_filp(data
->filps
[j
]);
1344 int clear_fds(int minor
, struct ancillary
*data
)
1346 /* This function calls put_filp() for all of the FDs in data.
1347 * This is used when a Unix Domain Socket is closed and there
1348 * exists references to file descriptors that haven't been received
1354 static int call_count
= 0;
1355 printf("(uds) [%d] recv_fds() call_count=%d\n", minor
,
1359 for (i
= 0; i
< data
->nfiledes
; i
++) {
1360 put_filp(data
->filps
[i
]);
1362 printf("(uds) clear_fds() => %d\n", data
->fds
[i
]);
1365 data
->filps
[i
] = NULL
;
1373 static int recv_fds(int minor
, struct ancillary
*data
,
1374 struct msg_control
*msg_ctrl
)
1377 struct msghdr msghdr
;
1378 struct cmsghdr
*cmsg
;
1382 static int call_count
= 0;
1383 printf("(uds) [%d] recv_fds() call_count=%d\n", minor
,
1387 msghdr
.msg_control
= msg_ctrl
->msg_control
;
1388 msghdr
.msg_controllen
= msg_ctrl
->msg_controllen
;
1390 cmsg
= CMSG_FIRSTHDR(&msghdr
);
1391 cmsg
->cmsg_len
= CMSG_LEN(sizeof(int) * data
->nfiledes
);
1392 cmsg
->cmsg_level
= SOL_SOCKET
;
1393 cmsg
->cmsg_type
= SCM_RIGHTS
;
1395 to_ep
= uds_fd_table
[minor
].owner
;
1397 /* copy to the target endpoint */
1398 for (i
= 0; i
< data
->nfiledes
; i
++) {
1399 rc
= copy_filp(to_ep
, data
->filps
[i
]);
1401 /* revert set_filp() calls */
1402 for (j
= 0; j
< data
->nfiledes
; j
++) {
1403 put_filp(data
->filps
[j
]);
1405 /* revert copy_filp() calls */
1406 for (j
= i
; j
>= 0; j
--) {
1407 cancel_fd(to_ep
, data
->fds
[j
]);
1411 data
->fds
[i
] = rc
; /* data->fds[i] now has the new FD */
1414 for (i
= 0; i
< data
->nfiledes
; i
++) {
1415 put_filp(data
->filps
[i
]);
1417 printf("(uds) recv_fds() => %d\n", data
->fds
[i
]);
1419 ((int *)CMSG_DATA(cmsg
))[i
] = data
->fds
[i
];
1421 data
->filps
[i
] = NULL
;
1429 static int recv_cred(int minor
, struct ancillary
*data
,
1430 struct msg_control
*msg_ctrl
)
1432 struct msghdr msghdr
;
1433 struct cmsghdr
*cmsg
;
1436 static int call_count
= 0;
1437 printf("(uds) [%d] recv_cred() call_count=%d\n", minor
,
1441 msghdr
.msg_control
= msg_ctrl
->msg_control
;
1442 msghdr
.msg_controllen
= msg_ctrl
->msg_controllen
;
1444 cmsg
= CMSG_FIRSTHDR(&msghdr
);
1445 if (cmsg
->cmsg_len
> 0) {
1446 cmsg
= CMSG_NXTHDR(&msghdr
, cmsg
);
1449 cmsg
->cmsg_len
= CMSG_LEN(sizeof(struct ucred
));
1450 cmsg
->cmsg_level
= SOL_SOCKET
;
1451 cmsg
->cmsg_type
= SCM_CREDENTIALS
;
1452 memcpy(CMSG_DATA(cmsg
), &(data
->cred
), sizeof(struct ucred
));
1457 int do_sendmsg(message
*dev_m_in
, message
*dev_m_out
)
1459 int minor
, peer
, rc
, i
;
1460 struct msg_control msg_ctrl
;
1463 static int call_count
= 0;
1464 printf("(uds) [%d] do_sendmsg() call_count=%d\n",
1465 uds_minor(dev_m_in
), ++call_count
);
1468 minor
= uds_minor(dev_m_in
);
1470 memset(&msg_ctrl
, '\0', sizeof(struct msg_control
));
1472 rc
= sys_safecopyfrom(VFS_PROC_NR
, (cp_grant_id_t
) dev_m_in
->IO_GRANT
,
1473 (vir_bytes
) 0, (vir_bytes
) &msg_ctrl
,
1474 sizeof(struct msg_control
));
1482 if (uds_fd_table
[minor
].type
== SOCK_DGRAM
) {
1483 if (uds_fd_table
[minor
].target
.sun_path
[0] == '\0' ||
1484 uds_fd_table
[minor
].target
.sun_family
!= AF_UNIX
) {
1486 return EDESTADDRREQ
;
1489 for (i
= 0; i
< NR_FDS
; i
++) {
1491 /* look for a SOCK_DGRAM socket that is bound on
1492 * the target address
1494 if (uds_fd_table
[i
].type
== SOCK_DGRAM
&&
1495 uds_fd_table
[i
].addr
.sun_family
== AF_UNIX
&&
1496 !strncmp(uds_fd_table
[minor
].target
.sun_path
,
1497 uds_fd_table
[i
].addr
.sun_path
, UNIX_PATH_MAX
)){
1508 peer
= uds_fd_table
[minor
].peer
;
1515 printf("(uds) [%d] sendmsg() -- peer=%d\n", minor
, peer
);
1517 /* note: it's possible that there is already some file
1518 * descriptors in ancillary_data if the peer didn't call
1519 * recvmsg() yet. That's okay. The receiver will
1520 * get the current file descriptors plus the new ones.
1522 rc
= msg_control_read(&msg_ctrl
, &uds_fd_table
[peer
].ancillary_data
,
1528 return send_fds(minor
, &uds_fd_table
[peer
].ancillary_data
);
1531 int do_recvmsg(message
*dev_m_in
, message
*dev_m_out
)
1535 struct msg_control msg_ctrl
;
1536 socklen_t controllen_avail
= 0;
1537 socklen_t controllen_needed
= 0;
1538 socklen_t controllen_desired
= 0;
1541 static int call_count
= 0;
1542 printf("(uds) [%d] do_sendmsg() call_count=%d\n",
1543 uds_minor(dev_m_in
), ++call_count
);
1546 minor
= uds_minor(dev_m_in
);
1550 printf("(uds) [%d] CREDENTIALS {pid:%d,uid:%d,gid:%d}\n", minor
,
1551 uds_fd_table
[minor
].ancillary_data
.cred
.pid
,
1552 uds_fd_table
[minor
].ancillary_data
.cred
.uid
,
1553 uds_fd_table
[minor
].ancillary_data
.cred
.gid
);
1556 memset(&msg_ctrl
, '\0', sizeof(struct msg_control
));
1558 /* get the msg_control from the user, it will include the
1559 * amount of space the user has allocated for control data.
1561 rc
= sys_safecopyfrom(VFS_PROC_NR
, (cp_grant_id_t
) dev_m_in
->IO_GRANT
,
1562 (vir_bytes
) 0, (vir_bytes
) &msg_ctrl
,
1563 sizeof(struct msg_control
));
1569 controllen_avail
= MIN(msg_ctrl
.msg_controllen
, MSG_CONTROL_MAX
);
1571 if (uds_fd_table
[minor
].ancillary_data
.nfiledes
> 0) {
1572 controllen_needed
= CMSG_LEN(sizeof(int) *
1573 (uds_fd_table
[minor
].ancillary_data
.nfiledes
));
1576 /* if there is room we also include credentials */
1577 controllen_desired
= controllen_needed
+
1578 CMSG_LEN(sizeof(struct ucred
));
1580 if (controllen_needed
> controllen_avail
) {
1584 rc
= recv_fds(minor
, &uds_fd_table
[minor
].ancillary_data
, &msg_ctrl
);
1589 if (controllen_desired
<= controllen_avail
) {
1590 rc
= recv_cred(minor
, &uds_fd_table
[minor
].ancillary_data
,
1597 /* send the user the control data */
1598 rc
= sys_safecopyto(VFS_PROC_NR
, (cp_grant_id_t
) dev_m_in
->IO_GRANT
,
1599 (vir_bytes
) 0, (vir_bytes
) &msg_ctrl
,
1600 sizeof(struct msg_control
));
1602 return rc
? EIO
: OK
;