]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/compat/cloudabi/cloudabi_sock.c
hyperv/vmbus: Expose channel management taskqueue for driver to use.
[FreeBSD/FreeBSD.git] / sys / compat / cloudabi / cloudabi_sock.c
1 /*-
2  * Copyright (c) 2015 Nuxi, https://nuxi.nl/
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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
23  * SUCH DAMAGE.
24  */
25
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28
29 #include <sys/param.h>
30 #include <sys/capsicum.h>
31 #include <sys/lock.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>
40 #include <sys/un.h>
41
42 #include <net/vnet.h>
43
44 #include <netinet/in.h>
45
46 #include <contrib/cloudabi/cloudabi_types_common.h>
47
48 #include <compat/cloudabi/cloudabi_proto.h>
49 #include <compat/cloudabi/cloudabi_util.h>
50
51 /* Converts FreeBSD's struct sockaddr to CloudABI's cloudabi_sockaddr_t. */
52 void
53 cloudabi_convert_sockaddr(const struct sockaddr *sa, socklen_t sal,
54     cloudabi_sockaddr_t *rsa)
55 {
56         const struct sockaddr_in *sin;
57         const struct sockaddr_in6 *sin6;
58
59         /* Zero-sized socket address. */
60         if (sal < offsetof(struct sockaddr, sa_family) + sizeof(sa->sa_family))
61                 return;
62
63         switch (sa->sa_family) {
64         case AF_INET:
65                 if (sal < sizeof(struct sockaddr_in))
66                         return;
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);
72                 return;
73         case AF_INET6:
74                 if (sal < sizeof(struct sockaddr_in6))
75                         return;
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);
81                 return;
82         case AF_UNIX:
83                 rsa->sa_family = CLOUDABI_AF_UNIX;
84                 return;
85         }
86 }
87
88 /* Copies a pathname into a UNIX socket address structure. */
89 static int
90 copyin_sockaddr_un(const char *path, size_t pathlen, struct sockaddr_un *sun)
91 {
92         int error;
93
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);
98         if (error != 0)
99                 return (error);
100         if (memchr(sun->sun_path, '\0', pathlen) != NULL)
101                 return (EINVAL);
102
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);
107         return (0);
108 }
109
110 int
111 cloudabi_sys_sock_accept(struct thread *td,
112     struct cloudabi_sys_sock_accept_args *uap)
113 {
114         struct sockaddr *sa;
115         cloudabi_sockstat_t ss = {};
116         socklen_t sal;
117         int error;
118
119         if (uap->buf == NULL) {
120                 /* Only return the new file descriptor number. */
121                 return (kern_accept(td, uap->sock, NULL, NULL, NULL));
122         } else {
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);
127                 if (error != 0)
128                         return (error);
129
130                 /* TODO(ed): Fill the other members of cloudabi_sockstat_t. */
131                 cloudabi_convert_sockaddr(sa, sal, &ss.ss_peername);
132                 free(sa, M_SONAME);
133                 return (copyout(&ss, uap->buf, sizeof(ss)));
134         }
135 }
136
137 int
138 cloudabi_sys_sock_bind(struct thread *td,
139     struct cloudabi_sys_sock_bind_args *uap)
140 {
141         struct sockaddr_un sun;
142         int error;
143
144         error = copyin_sockaddr_un(uap->path, uap->pathlen, &sun);
145         if (error != 0)
146                 return (error);
147         return (kern_bindat(td, uap->fd, uap->sock, (struct sockaddr *)&sun));
148 }
149
150 int
151 cloudabi_sys_sock_connect(struct thread *td,
152     struct cloudabi_sys_sock_connect_args *uap)
153 {
154         struct sockaddr_un sun;
155         int error;
156
157         error = copyin_sockaddr_un(uap->path, uap->pathlen, &sun);
158         if (error != 0)
159                 return (error);
160         return (kern_connectat(td, uap->fd, uap->sock,
161             (struct sockaddr *)&sun));
162 }
163
164 int
165 cloudabi_sys_sock_listen(struct thread *td,
166     struct cloudabi_sys_sock_listen_args *uap)
167 {
168         struct listen_args listen_args = {
169                 .s = uap->sock,
170                 .backlog = uap->backlog,
171         };
172
173         return (sys_listen(td, &listen_args));
174 }
175
176 int
177 cloudabi_sys_sock_shutdown(struct thread *td,
178     struct cloudabi_sys_sock_shutdown_args *uap)
179 {
180         struct shutdown_args shutdown_args = {
181                 .s = uap->sock,
182         };
183
184         switch (uap->how) {
185         case CLOUDABI_SHUT_RD:
186                 shutdown_args.how = SHUT_RD;
187                 break;
188         case CLOUDABI_SHUT_WR:
189                 shutdown_args.how = SHUT_WR;
190                 break;
191         case CLOUDABI_SHUT_RD | CLOUDABI_SHUT_WR:
192                 shutdown_args.how = SHUT_RDWR;
193                 break;
194         default:
195                 return (EINVAL);
196         }
197
198         return (sys_shutdown(td, &shutdown_args));
199 }
200
201 int
202 cloudabi_sys_sock_stat_get(struct thread *td,
203     struct cloudabi_sys_sock_stat_get_args *uap)
204 {
205         cloudabi_sockstat_t ss = {};
206         cap_rights_t rights;
207         struct file *fp;
208         struct sockaddr *sa;
209         struct socket *so;
210         int error;
211
212         error = getsock_cap(td, uap->sock, cap_rights_init(&rights,
213             CAP_GETSOCKOPT, CAP_GETPEERNAME, CAP_GETSOCKNAME), &fp, NULL, NULL);
214         if (error != 0)
215                 return (error);
216         so = fp->f_data;
217
218         CURVNET_SET(so->so_vnet);
219
220         /* Set ss_sockname. */
221         error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
222         if (error == 0) {
223                 cloudabi_convert_sockaddr(sa, sa->sa_len, &ss.ss_sockname);
224                 free(sa, M_SONAME);
225         }
226
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);
230                 if (error == 0) {
231                         cloudabi_convert_sockaddr(sa, sa->sa_len,
232                             &ss.ss_peername);
233                         free(sa, M_SONAME);
234                 }
235         }
236
237         CURVNET_RESTORE();
238
239         /* Set ss_error. */
240         SOCK_LOCK(so);
241         ss.ss_error = cloudabi_convert_errno(so->so_error);
242         if ((uap->flags & CLOUDABI_SOCKSTAT_CLEAR_ERROR) != 0)
243                 so->so_error = 0;
244         SOCK_UNLOCK(so);
245
246         /* Set ss_state. */
247         if ((so->so_options & SO_ACCEPTCONN) != 0)
248                 ss.ss_state |= CLOUDABI_SOCKSTATE_ACCEPTCONN;
249
250         fdrop(fp, td);
251         return (copyout(&ss, uap->buf, sizeof(ss)));
252 }