2 * Copyright (c) 2015 Nuxi, https://nuxi.nl/
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
29 #include <sys/param.h>
30 #include <sys/capsicum.h>
32 #include <sys/malloc.h>
33 #include <sys/mutex.h>
34 #include <sys/protosw.h>
35 #include <sys/socket.h>
36 #include <sys/socketvar.h>
37 #include <sys/syscallsubr.h>
38 #include <sys/sysproto.h>
39 #include <sys/systm.h>
44 #include <netinet/in.h>
46 #include <contrib/cloudabi/cloudabi_types_common.h>
48 #include <compat/cloudabi/cloudabi_proto.h>
49 #include <compat/cloudabi/cloudabi_util.h>
51 /* Converts FreeBSD's struct sockaddr to CloudABI's cloudabi_sockaddr_t. */
53 cloudabi_convert_sockaddr(const struct sockaddr *sa, socklen_t sal,
54 cloudabi_sockaddr_t *rsa)
56 const struct sockaddr_in *sin;
57 const struct sockaddr_in6 *sin6;
59 /* Zero-sized socket address. */
60 if (sal < offsetof(struct sockaddr, sa_family) + sizeof(sa->sa_family))
63 switch (sa->sa_family) {
65 if (sal < sizeof(struct sockaddr_in))
67 sin = (const struct sockaddr_in *)sa;
68 rsa->sa_family = CLOUDABI_AF_INET;
69 memcpy(&rsa->sa_inet.addr, &sin->sin_addr,
70 sizeof(rsa->sa_inet.addr));
71 rsa->sa_inet.port = ntohs(sin->sin_port);
74 if (sal < sizeof(struct sockaddr_in6))
76 sin6 = (const struct sockaddr_in6 *)sa;
77 rsa->sa_family = CLOUDABI_AF_INET6;
78 memcpy(&rsa->sa_inet6.addr, &sin6->sin6_addr,
79 sizeof(rsa->sa_inet6.addr));
80 rsa->sa_inet6.port = ntohs(sin6->sin6_port);
83 rsa->sa_family = CLOUDABI_AF_UNIX;
88 /* Copies a pathname into a UNIX socket address structure. */
90 copyin_sockaddr_un(const char *path, size_t pathlen, struct sockaddr_un *sun)
94 /* Copy in pathname string if there's enough space. */
95 if (pathlen >= sizeof(sun->sun_path))
96 return (ENAMETOOLONG);
97 error = copyin(path, &sun->sun_path, pathlen);
100 if (memchr(sun->sun_path, '\0', pathlen) != NULL)
103 /* Initialize the rest of the socket address. */
104 sun->sun_path[pathlen] = '\0';
105 sun->sun_family = AF_UNIX;
106 sun->sun_len = sizeof(*sun);
111 cloudabi_sys_sock_accept(struct thread *td,
112 struct cloudabi_sys_sock_accept_args *uap)
115 cloudabi_sockstat_t ss = {};
119 if (uap->buf == NULL) {
120 /* Only return the new file descriptor number. */
121 return (kern_accept(td, uap->sock, NULL, NULL, NULL));
123 /* Also return properties of the new socket descriptor. */
124 sal = MAX(sizeof(struct sockaddr_in),
125 sizeof(struct sockaddr_in6));
126 error = kern_accept(td, uap->sock, (void *)&sa, &sal, NULL);
130 /* TODO(ed): Fill the other members of cloudabi_sockstat_t. */
131 cloudabi_convert_sockaddr(sa, sal, &ss.ss_peername);
133 return (copyout(&ss, uap->buf, sizeof(ss)));
138 cloudabi_sys_sock_bind(struct thread *td,
139 struct cloudabi_sys_sock_bind_args *uap)
141 struct sockaddr_un sun;
144 error = copyin_sockaddr_un(uap->path, uap->pathlen, &sun);
147 return (kern_bindat(td, uap->fd, uap->sock, (struct sockaddr *)&sun));
151 cloudabi_sys_sock_connect(struct thread *td,
152 struct cloudabi_sys_sock_connect_args *uap)
154 struct sockaddr_un sun;
157 error = copyin_sockaddr_un(uap->path, uap->pathlen, &sun);
160 return (kern_connectat(td, uap->fd, uap->sock,
161 (struct sockaddr *)&sun));
165 cloudabi_sys_sock_listen(struct thread *td,
166 struct cloudabi_sys_sock_listen_args *uap)
168 struct listen_args listen_args = {
170 .backlog = uap->backlog,
173 return (sys_listen(td, &listen_args));
177 cloudabi_sys_sock_shutdown(struct thread *td,
178 struct cloudabi_sys_sock_shutdown_args *uap)
180 struct shutdown_args shutdown_args = {
185 case CLOUDABI_SHUT_RD:
186 shutdown_args.how = SHUT_RD;
188 case CLOUDABI_SHUT_WR:
189 shutdown_args.how = SHUT_WR;
191 case CLOUDABI_SHUT_RD | CLOUDABI_SHUT_WR:
192 shutdown_args.how = SHUT_RDWR;
198 return (sys_shutdown(td, &shutdown_args));
202 cloudabi_sys_sock_stat_get(struct thread *td,
203 struct cloudabi_sys_sock_stat_get_args *uap)
205 cloudabi_sockstat_t ss = {};
212 error = getsock_cap(td, uap->sock, cap_rights_init(&rights,
213 CAP_GETSOCKOPT, CAP_GETPEERNAME, CAP_GETSOCKNAME), &fp, NULL, NULL);
218 CURVNET_SET(so->so_vnet);
220 /* Set ss_sockname. */
221 error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
223 cloudabi_convert_sockaddr(sa, sa->sa_len, &ss.ss_sockname);
227 /* Set ss_peername. */
228 if ((so->so_state & (SS_ISCONNECTED | SS_ISCONFIRMING)) != 0) {
229 error = so->so_proto->pr_usrreqs->pru_peeraddr(so, &sa);
231 cloudabi_convert_sockaddr(sa, sa->sa_len,
241 ss.ss_error = cloudabi_convert_errno(so->so_error);
242 if ((uap->flags & CLOUDABI_SOCKSTAT_CLEAR_ERROR) != 0)
247 if ((so->so_options & SO_ACCEPTCONN) != 0)
248 ss.ss_state |= CLOUDABI_SOCKSTATE_ACCEPTCONN;
251 return (copyout(&ss, uap->buf, sizeof(ss)));