1 | /* $NetBSD: linux_socket.c,v 1.133 2016/09/13 07:01:07 martin Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 1995, 1998, 2008 The NetBSD Foundation, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Frank van der Linden and Eric Haszlakiewicz. |
9 | * |
10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions |
12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ |
31 | |
32 | /* |
33 | * Functions in multiarch: |
34 | * linux_sys_socketcall : linux_socketcall.c |
35 | */ |
36 | |
37 | #include <sys/cdefs.h> |
38 | __KERNEL_RCSID(0, "$NetBSD: linux_socket.c,v 1.133 2016/09/13 07:01:07 martin Exp $" ); |
39 | |
40 | #if defined(_KERNEL_OPT) |
41 | #include "opt_inet.h" |
42 | #endif /* defined(_KERNEL_OPT) */ |
43 | |
44 | #include <sys/param.h> |
45 | #include <sys/kernel.h> |
46 | #include <sys/systm.h> |
47 | #include <sys/buf.h> |
48 | #include <sys/ioctl.h> |
49 | #include <sys/tty.h> |
50 | #include <sys/file.h> |
51 | #include <sys/filedesc.h> |
52 | #include <sys/select.h> |
53 | #include <sys/socket.h> |
54 | #include <sys/socketvar.h> |
55 | #include <sys/domain.h> |
56 | #include <net/if.h> |
57 | #include <net/if_dl.h> |
58 | #include <net/if_types.h> |
59 | #include <netinet/in.h> |
60 | #include <netinet/tcp.h> |
61 | #include <sys/mount.h> |
62 | #include <sys/proc.h> |
63 | #include <sys/vnode.h> |
64 | #include <sys/device.h> |
65 | #include <sys/protosw.h> |
66 | #include <sys/mbuf.h> |
67 | #include <sys/syslog.h> |
68 | #include <sys/exec.h> |
69 | #include <sys/kauth.h> |
70 | #include <sys/syscallargs.h> |
71 | #include <sys/ktrace.h> |
72 | |
73 | #include <lib/libkern/libkern.h> |
74 | |
75 | #include <netinet/ip6.h> |
76 | #include <netinet6/ip6_var.h> |
77 | |
78 | #include <compat/sys/socket.h> |
79 | #include <compat/sys/sockio.h> |
80 | |
81 | #include <compat/linux/common/linux_types.h> |
82 | #include <compat/linux/common/linux_util.h> |
83 | #include <compat/linux/common/linux_signal.h> |
84 | #include <compat/linux/common/linux_ioctl.h> |
85 | #include <compat/linux/common/linux_socket.h> |
86 | #include <compat/linux/common/linux_fcntl.h> |
87 | #if !defined(__alpha__) && !defined(__amd64__) |
88 | #include <compat/linux/common/linux_socketcall.h> |
89 | #endif |
90 | #include <compat/linux/common/linux_sockio.h> |
91 | #include <compat/linux/common/linux_ipc.h> |
92 | #include <compat/linux/common/linux_sem.h> |
93 | |
94 | #include <compat/linux/linux_syscallargs.h> |
95 | |
96 | #ifdef DEBUG_LINUX |
97 | #define DPRINTF(a) uprintf a |
98 | #else |
99 | #define DPRINTF(a) |
100 | #endif |
101 | |
102 | /* |
103 | * The calls in this file are entered either via the linux_socketcall() |
104 | * interface or, on the Alpha, as individual syscalls. The |
105 | * linux_socketcall function does any massaging of arguments so that all |
106 | * the calls in here need not think that they are anything other |
107 | * than a normal syscall. |
108 | */ |
109 | |
110 | static int linux_to_bsd_domain(int); |
111 | static int bsd_to_linux_domain(int); |
112 | static int linux_to_bsd_type(int); |
113 | int linux_to_bsd_sopt_level(int); |
114 | int linux_to_bsd_so_sockopt(int); |
115 | int linux_to_bsd_ip_sockopt(int); |
116 | int linux_to_bsd_ipv6_sockopt(int); |
117 | int linux_to_bsd_tcp_sockopt(int); |
118 | int linux_to_bsd_udp_sockopt(int); |
119 | int linux_getifname(struct lwp *, register_t *, void *); |
120 | int linux_getifconf(struct lwp *, register_t *, void *); |
121 | int linux_getifhwaddr(struct lwp *, register_t *, u_int, void *); |
122 | static int linux_get_sa(struct lwp *, int, struct sockaddr_big *, |
123 | const struct osockaddr *, socklen_t); |
124 | static int linux_sa_put(struct osockaddr *osa); |
125 | static int linux_to_bsd_msg_flags(int); |
126 | static int bsd_to_linux_msg_flags(int); |
127 | static void linux_to_bsd_msghdr(struct linux_msghdr *, struct msghdr *); |
128 | static void bsd_to_linux_msghdr(struct msghdr *, struct linux_msghdr *); |
129 | |
130 | static const int linux_to_bsd_domain_[LINUX_AF_MAX] = { |
131 | AF_UNSPEC, |
132 | AF_UNIX, |
133 | AF_INET, |
134 | AF_CCITT, /* LINUX_AF_AX25 */ |
135 | AF_IPX, |
136 | AF_APPLETALK, |
137 | -1, /* LINUX_AF_NETROM */ |
138 | -1, /* LINUX_AF_BRIDGE */ |
139 | -1, /* LINUX_AF_ATMPVC */ |
140 | AF_CCITT, /* LINUX_AF_X25 */ |
141 | AF_INET6, |
142 | -1, /* LINUX_AF_ROSE */ |
143 | AF_DECnet, |
144 | -1, /* LINUX_AF_NETBEUI */ |
145 | -1, /* LINUX_AF_SECURITY */ |
146 | pseudo_AF_KEY, |
147 | AF_ROUTE, /* LINUX_AF_NETLINK */ |
148 | -1, /* LINUX_AF_PACKET */ |
149 | -1, /* LINUX_AF_ASH */ |
150 | -1, /* LINUX_AF_ECONET */ |
151 | -1, /* LINUX_AF_ATMSVC */ |
152 | AF_SNA, |
153 | /* rest up to LINUX_AF_MAX-1 is not allocated */ |
154 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
155 | }; |
156 | |
157 | static const int bsd_to_linux_domain_[AF_MAX] = { |
158 | LINUX_AF_UNSPEC, |
159 | LINUX_AF_UNIX, |
160 | LINUX_AF_INET, |
161 | -1, /* AF_IMPLINK */ |
162 | -1, /* AF_PUP */ |
163 | -1, /* AF_CHAOS */ |
164 | -1, /* AF_NS */ |
165 | -1, /* AF_ISO */ |
166 | -1, /* AF_ECMA */ |
167 | -1, /* AF_DATAKIT */ |
168 | LINUX_AF_AX25, /* AF_CCITT */ |
169 | LINUX_AF_SNA, |
170 | LINUX_AF_DECnet, |
171 | -1, /* AF_DLI */ |
172 | -1, /* AF_LAT */ |
173 | -1, /* AF_HYLINK */ |
174 | LINUX_AF_APPLETALK, |
175 | LINUX_AF_NETLINK, |
176 | -1, /* AF_LINK */ |
177 | -1, /* AF_XTP */ |
178 | -1, /* AF_COIP */ |
179 | -1, /* AF_CNT */ |
180 | -1, /* pseudo_AF_RTIP */ |
181 | LINUX_AF_IPX, |
182 | LINUX_AF_INET6, |
183 | -1, /* pseudo_AF_PIP */ |
184 | -1, /* AF_ISDN */ |
185 | -1, /* AF_NATM */ |
186 | -1, /* AF_ARP */ |
187 | LINUX_pseudo_AF_KEY, |
188 | -1, /* pseudo_AF_HDRCMPLT */ |
189 | }; |
190 | |
191 | static const struct { |
192 | int bfl; |
193 | int lfl; |
194 | } bsd_to_linux_msg_flags_[] = { |
195 | {MSG_OOB, LINUX_MSG_OOB}, |
196 | {MSG_PEEK, LINUX_MSG_PEEK}, |
197 | {MSG_DONTROUTE, LINUX_MSG_DONTROUTE}, |
198 | {MSG_EOR, LINUX_MSG_EOR}, |
199 | {MSG_TRUNC, LINUX_MSG_TRUNC}, |
200 | {MSG_CTRUNC, LINUX_MSG_CTRUNC}, |
201 | {MSG_WAITALL, LINUX_MSG_WAITALL}, |
202 | {MSG_DONTWAIT, LINUX_MSG_DONTWAIT}, |
203 | {MSG_BCAST, 0}, /* not supported, clear */ |
204 | {MSG_MCAST, 0}, /* not supported, clear */ |
205 | {MSG_NOSIGNAL, LINUX_MSG_NOSIGNAL}, |
206 | {-1, /* not supp */ LINUX_MSG_PROBE}, |
207 | {-1, /* not supp */ LINUX_MSG_FIN}, |
208 | {-1, /* not supp */ LINUX_MSG_SYN}, |
209 | {-1, /* not supp */ LINUX_MSG_CONFIRM}, |
210 | {-1, /* not supp */ LINUX_MSG_RST}, |
211 | {-1, /* not supp */ LINUX_MSG_ERRQUEUE}, |
212 | {-1, /* not supp */ LINUX_MSG_MORE}, |
213 | }; |
214 | |
215 | /* |
216 | * Convert between Linux and BSD socket domain values |
217 | */ |
218 | static int |
219 | linux_to_bsd_domain(int ldom) |
220 | { |
221 | if (ldom < 0 || ldom >= LINUX_AF_MAX) |
222 | return (-1); |
223 | |
224 | return linux_to_bsd_domain_[ldom]; |
225 | } |
226 | |
227 | /* |
228 | * Convert between BSD and Linux socket domain values |
229 | */ |
230 | static int |
231 | bsd_to_linux_domain(int bdom) |
232 | { |
233 | if (bdom < 0 || bdom >= AF_MAX) |
234 | return (-1); |
235 | |
236 | return bsd_to_linux_domain_[bdom]; |
237 | } |
238 | |
239 | static int |
240 | linux_to_bsd_type(int ltype) |
241 | { |
242 | int type, flags; |
243 | |
244 | /* Real types are identical between Linux and NetBSD */ |
245 | type = ltype & LINUX_SOCK_TYPE_MASK; |
246 | |
247 | /* But flags are not .. */ |
248 | flags = ltype & ~LINUX_SOCK_TYPE_MASK; |
249 | if (flags & ~(LINUX_SOCK_CLOEXEC|LINUX_SOCK_NONBLOCK)) |
250 | return -1; |
251 | |
252 | if (flags & LINUX_SOCK_CLOEXEC) |
253 | type |= SOCK_CLOEXEC; |
254 | if (flags & LINUX_SOCK_NONBLOCK) |
255 | type |= SOCK_NONBLOCK; |
256 | |
257 | return type; |
258 | } |
259 | |
260 | static int |
261 | linux_to_bsd_msg_flags(int lflag) |
262 | { |
263 | int i, lfl, bfl; |
264 | int bflag = 0; |
265 | |
266 | if (lflag == 0) |
267 | return (0); |
268 | |
269 | for(i = 0; i < __arraycount(bsd_to_linux_msg_flags_); i++) { |
270 | bfl = bsd_to_linux_msg_flags_[i].bfl; |
271 | lfl = bsd_to_linux_msg_flags_[i].lfl; |
272 | |
273 | if (lfl == 0) |
274 | continue; |
275 | |
276 | if (lflag & lfl) { |
277 | if (bfl < 0) |
278 | return (-1); |
279 | |
280 | bflag |= bfl; |
281 | } |
282 | } |
283 | |
284 | return (bflag); |
285 | } |
286 | |
287 | static int |
288 | bsd_to_linux_msg_flags(int bflag) |
289 | { |
290 | int i, lfl, bfl; |
291 | int lflag = 0; |
292 | |
293 | if (bflag == 0) |
294 | return (0); |
295 | |
296 | for(i = 0; i < __arraycount(bsd_to_linux_msg_flags_); i++) { |
297 | bfl = bsd_to_linux_msg_flags_[i].bfl; |
298 | lfl = bsd_to_linux_msg_flags_[i].lfl; |
299 | |
300 | if (bfl <= 0) |
301 | continue; |
302 | |
303 | if (bflag & bfl) { |
304 | if (lfl < 0) |
305 | return (-1); |
306 | |
307 | lflag |= lfl; |
308 | } |
309 | } |
310 | |
311 | return (lflag); |
312 | } |
313 | |
314 | int |
315 | linux_sys_socket(struct lwp *l, const struct linux_sys_socket_args *uap, register_t *retval) |
316 | { |
317 | /* { |
318 | syscallarg(int) domain; |
319 | syscallarg(int) type; |
320 | syscallarg(int) protocol; |
321 | } */ |
322 | struct sys___socket30_args bsa; |
323 | int error; |
324 | |
325 | |
326 | SCARG(&bsa, protocol) = SCARG(uap, protocol); |
327 | SCARG(&bsa, domain) = linux_to_bsd_domain(SCARG(uap, domain)); |
328 | if (SCARG(&bsa, domain) == -1) |
329 | return EINVAL; |
330 | SCARG(&bsa, type) = linux_to_bsd_type(SCARG(uap, type)); |
331 | if (SCARG(&bsa, type) == -1) |
332 | return EINVAL; |
333 | /* |
334 | * Apparently linux uses this to talk to ISDN sockets. If we fail |
335 | * now programs seems to handle it, but if we don't we are going |
336 | * to fail when we bind and programs don't handle this well. |
337 | */ |
338 | if (SCARG(&bsa, domain) == AF_ROUTE && SCARG(&bsa, type) == SOCK_RAW) |
339 | return ENOTSUP; |
340 | error = sys___socket30(l, &bsa, retval); |
341 | |
342 | #ifdef INET6 |
343 | /* |
344 | * Linux AF_INET6 socket has IPV6_V6ONLY setsockopt set to 0 by |
345 | * default and some apps depend on this. So, set V6ONLY to 0 |
346 | * for Linux apps if the sysctl value is set to 1. |
347 | */ |
348 | if (!error && ip6_v6only && SCARG(&bsa, domain) == PF_INET6) { |
349 | struct socket *so; |
350 | |
351 | if (fd_getsock(*retval, &so) == 0) { |
352 | int val = 0; |
353 | |
354 | /* ignore error */ |
355 | (void)so_setsockopt(l, so, IPPROTO_IPV6, IPV6_V6ONLY, |
356 | &val, sizeof(val)); |
357 | |
358 | fd_putfile(*retval); |
359 | } |
360 | } |
361 | #endif |
362 | |
363 | return (error); |
364 | } |
365 | |
366 | int |
367 | linux_sys_socketpair(struct lwp *l, const struct linux_sys_socketpair_args *uap, register_t *retval) |
368 | { |
369 | /* { |
370 | syscallarg(int) domain; |
371 | syscallarg(int) type; |
372 | syscallarg(int) protocol; |
373 | syscallarg(int *) rsv; |
374 | } */ |
375 | struct sys_socketpair_args bsa; |
376 | |
377 | SCARG(&bsa, domain) = linux_to_bsd_domain(SCARG(uap, domain)); |
378 | if (SCARG(&bsa, domain) == -1) |
379 | return EINVAL; |
380 | SCARG(&bsa, type) = linux_to_bsd_type(SCARG(uap, type)); |
381 | if (SCARG(&bsa, type) == -1) |
382 | return EINVAL; |
383 | SCARG(&bsa, protocol) = SCARG(uap, protocol); |
384 | SCARG(&bsa, rsv) = SCARG(uap, rsv); |
385 | |
386 | return sys_socketpair(l, &bsa, retval); |
387 | } |
388 | |
389 | int |
390 | linux_sys_sendto(struct lwp *l, const struct linux_sys_sendto_args *uap, register_t *retval) |
391 | { |
392 | /* { |
393 | syscallarg(int) s; |
394 | syscallarg(void *) msg; |
395 | syscallarg(int) len; |
396 | syscallarg(int) flags; |
397 | syscallarg(struct osockaddr *) to; |
398 | syscallarg(int) tolen; |
399 | } */ |
400 | struct msghdr msg; |
401 | struct iovec aiov; |
402 | struct sockaddr_big nam; |
403 | int bflags; |
404 | int error; |
405 | |
406 | /* Translate message flags. */ |
407 | bflags = linux_to_bsd_msg_flags(SCARG(uap, flags)); |
408 | if (bflags < 0) |
409 | /* Some supported flag */ |
410 | return EINVAL; |
411 | |
412 | msg.msg_flags = 0; |
413 | msg.msg_name = NULL; |
414 | msg.msg_control = NULL; |
415 | |
416 | if (SCARG(uap, tolen)) { |
417 | /* Read in and convert the sockaddr */ |
418 | error = linux_get_sa(l, SCARG(uap, s), &nam, SCARG(uap, to), |
419 | SCARG(uap, tolen)); |
420 | if (error) |
421 | return (error); |
422 | msg.msg_name = &nam; |
423 | msg.msg_namelen = SCARG(uap, tolen); |
424 | } |
425 | |
426 | msg.msg_iov = &aiov; |
427 | msg.msg_iovlen = 1; |
428 | aiov.iov_base = __UNCONST(SCARG(uap, msg)); |
429 | aiov.iov_len = SCARG(uap, len); |
430 | |
431 | return do_sys_sendmsg(l, SCARG(uap, s), &msg, bflags, |
432 | NULL, 0, retval); |
433 | } |
434 | |
435 | static void |
436 | linux_to_bsd_msghdr(struct linux_msghdr *lmsg, struct msghdr *bmsg) |
437 | { |
438 | bmsg->msg_name = lmsg->msg_name; |
439 | bmsg->msg_namelen = lmsg->msg_namelen; |
440 | bmsg->msg_iov = lmsg->msg_iov; |
441 | bmsg->msg_iovlen = lmsg->msg_iovlen; |
442 | bmsg->msg_control = lmsg->msg_control; |
443 | bmsg->msg_controllen = lmsg->msg_controllen; |
444 | bmsg->msg_flags = lmsg->msg_flags; |
445 | } |
446 | |
447 | static void |
448 | bsd_to_linux_msghdr(struct msghdr *bmsg, struct linux_msghdr *lmsg) |
449 | { |
450 | lmsg->msg_name = bmsg->msg_name; |
451 | lmsg->msg_namelen = bmsg->msg_namelen; |
452 | lmsg->msg_iov = bmsg->msg_iov; |
453 | lmsg->msg_iovlen = bmsg->msg_iovlen; |
454 | lmsg->msg_control = bmsg->msg_control; |
455 | lmsg->msg_controllen = bmsg->msg_controllen; |
456 | lmsg->msg_flags = bmsg->msg_flags; |
457 | } |
458 | |
459 | int |
460 | linux_sys_sendmsg(struct lwp *l, const struct linux_sys_sendmsg_args *uap, register_t *retval) |
461 | { |
462 | /* { |
463 | syscallarg(int) s; |
464 | syscallarg(struct linux_msghdr *) msg; |
465 | syscallarg(u_int) flags; |
466 | } */ |
467 | struct msghdr msg; |
468 | struct linux_msghdr lmsg; |
469 | int error; |
470 | int bflags; |
471 | struct sockaddr_big nam; |
472 | u_int8_t *control; |
473 | struct mbuf *ctl_mbuf = NULL; |
474 | |
475 | error = copyin(SCARG(uap, msg), &lmsg, sizeof(lmsg)); |
476 | if (error) |
477 | return error; |
478 | linux_to_bsd_msghdr(&lmsg, &msg); |
479 | |
480 | msg.msg_flags = MSG_IOVUSRSPACE; |
481 | |
482 | /* |
483 | * Translate message flags. |
484 | */ |
485 | bflags = linux_to_bsd_msg_flags(SCARG(uap, flags)); |
486 | if (bflags < 0) |
487 | /* Some supported flag */ |
488 | return EINVAL; |
489 | |
490 | if (lmsg.msg_name) { |
491 | /* Read in and convert the sockaddr */ |
492 | error = linux_get_sa(l, SCARG(uap, s), &nam, msg.msg_name, |
493 | msg.msg_namelen); |
494 | if (error) |
495 | return (error); |
496 | msg.msg_name = &nam; |
497 | } |
498 | |
499 | /* |
500 | * Handle cmsg if there is any. |
501 | */ |
502 | if (LINUX_CMSG_FIRSTHDR(&lmsg)) { |
503 | struct linux_cmsghdr l_cmsg, *l_cc; |
504 | struct cmsghdr *cmsg; |
505 | ssize_t resid = msg.msg_controllen; |
506 | size_t clen, cidx = 0, cspace; |
507 | |
508 | ctl_mbuf = m_get(M_WAIT, MT_CONTROL); |
509 | clen = MLEN; |
510 | control = mtod(ctl_mbuf, void *); |
511 | |
512 | l_cc = LINUX_CMSG_FIRSTHDR(&lmsg); |
513 | do { |
514 | error = copyin(l_cc, &l_cmsg, sizeof(l_cmsg)); |
515 | if (error) |
516 | goto done; |
517 | |
518 | /* |
519 | * Sanity check the control message length. |
520 | */ |
521 | if (l_cmsg.cmsg_len > resid |
522 | || l_cmsg.cmsg_len < sizeof l_cmsg) { |
523 | error = EINVAL; |
524 | goto done; |
525 | } |
526 | |
527 | /* |
528 | * Refuse unsupported control messages, and |
529 | * translate fields as appropriate. |
530 | */ |
531 | switch (l_cmsg.cmsg_level) { |
532 | case LINUX_SOL_SOCKET: |
533 | /* It only differs on some archs */ |
534 | if (LINUX_SOL_SOCKET != SOL_SOCKET) |
535 | l_cmsg.cmsg_level = SOL_SOCKET; |
536 | |
537 | switch(l_cmsg.cmsg_type) { |
538 | case LINUX_SCM_RIGHTS: |
539 | /* Linux SCM_RIGHTS is same as NetBSD */ |
540 | break; |
541 | |
542 | case LINUX_SCM_CREDENTIALS: |
543 | /* no native equivalent, just drop it */ |
544 | m_free(ctl_mbuf); |
545 | ctl_mbuf = NULL; |
546 | msg.msg_control = NULL; |
547 | msg.msg_controllen = 0; |
548 | goto skipcmsg; |
549 | |
550 | default: |
551 | /* other types not supported */ |
552 | error = EINVAL; |
553 | goto done; |
554 | } |
555 | break; |
556 | default: |
557 | /* pray and leave intact */ |
558 | break; |
559 | } |
560 | |
561 | cspace = CMSG_SPACE(l_cmsg.cmsg_len - sizeof(l_cmsg)); |
562 | |
563 | /* Check the buffer is big enough */ |
564 | if (__predict_false(cidx + cspace > clen)) { |
565 | u_int8_t *nc; |
566 | |
567 | clen = cidx + cspace; |
568 | if (clen >= PAGE_SIZE) { |
569 | error = EINVAL; |
570 | goto done; |
571 | } |
572 | nc = realloc(clen <= MLEN ? NULL : control, |
573 | clen, M_TEMP, M_WAITOK); |
574 | if (!nc) { |
575 | error = ENOMEM; |
576 | goto done; |
577 | } |
578 | if (cidx <= MLEN) |
579 | /* Old buffer was in mbuf... */ |
580 | memcpy(nc, control, cidx); |
581 | control = nc; |
582 | } |
583 | |
584 | /* Copy header */ |
585 | cmsg = (void *)&control[cidx]; |
586 | cmsg->cmsg_len = l_cmsg.cmsg_len + LINUX_CMSG_ALIGN_DELTA; |
587 | cmsg->cmsg_level = l_cmsg.cmsg_level; |
588 | cmsg->cmsg_type = l_cmsg.cmsg_type; |
589 | |
590 | /* Zero area between header and data */ |
591 | memset(cmsg + 1, 0, |
592 | CMSG_ALIGN(sizeof(*cmsg)) - sizeof(*cmsg)); |
593 | |
594 | /* Copyin the data */ |
595 | error = copyin(LINUX_CMSG_DATA(l_cc), |
596 | CMSG_DATA(cmsg), |
597 | l_cmsg.cmsg_len - sizeof(l_cmsg)); |
598 | if (error) |
599 | goto done; |
600 | |
601 | resid -= LINUX_CMSG_ALIGN(l_cmsg.cmsg_len); |
602 | cidx += cspace; |
603 | } while ((l_cc = LINUX_CMSG_NXTHDR(&msg, l_cc)) && resid > 0); |
604 | |
605 | /* If we allocated a buffer, attach to mbuf */ |
606 | if (cidx > MLEN) { |
607 | MEXTADD(ctl_mbuf, control, clen, M_MBUF, NULL, NULL); |
608 | ctl_mbuf->m_flags |= M_EXT_RW; |
609 | } |
610 | control = NULL; |
611 | ctl_mbuf->m_len = cidx; |
612 | |
613 | msg.msg_control = ctl_mbuf; |
614 | msg.msg_flags |= MSG_CONTROLMBUF; |
615 | |
616 | ktrkuser("mbcontrol" , mtod(ctl_mbuf, void *), |
617 | msg.msg_controllen); |
618 | } |
619 | |
620 | skipcmsg: |
621 | error = do_sys_sendmsg(l, SCARG(uap, s), &msg, bflags, |
622 | NULL, 0, retval); |
623 | /* Freed internally */ |
624 | ctl_mbuf = NULL; |
625 | |
626 | done: |
627 | if (ctl_mbuf != NULL) { |
628 | if (control != NULL && control != mtod(ctl_mbuf, void *)) |
629 | free(control, M_MBUF); |
630 | m_free(ctl_mbuf); |
631 | } |
632 | return (error); |
633 | } |
634 | |
635 | int |
636 | linux_sys_recvfrom(struct lwp *l, const struct linux_sys_recvfrom_args *uap, register_t *retval) |
637 | { |
638 | /* { |
639 | syscallarg(int) s; |
640 | syscallarg(void *) buf; |
641 | syscallarg(int) len; |
642 | syscallarg(int) flags; |
643 | syscallarg(struct osockaddr *) from; |
644 | syscallarg(int *) fromlenaddr; |
645 | } */ |
646 | int error; |
647 | struct sys_recvfrom_args bra; |
648 | |
649 | SCARG(&bra, s) = SCARG(uap, s); |
650 | SCARG(&bra, buf) = SCARG(uap, buf); |
651 | SCARG(&bra, len) = SCARG(uap, len); |
652 | SCARG(&bra, flags) = SCARG(uap, flags); |
653 | SCARG(&bra, from) = (struct sockaddr *) SCARG(uap, from); |
654 | SCARG(&bra, fromlenaddr) = (socklen_t *)SCARG(uap, fromlenaddr); |
655 | |
656 | if ((error = sys_recvfrom(l, &bra, retval))) |
657 | return (error); |
658 | |
659 | if (SCARG(uap, from) && (error = linux_sa_put(SCARG(uap, from)))) |
660 | return (error); |
661 | |
662 | return (0); |
663 | } |
664 | |
665 | static int |
666 | linux_copyout_msg_control(struct lwp *l, struct msghdr *mp, struct mbuf *control) |
667 | { |
668 | int dlen, error = 0; |
669 | struct cmsghdr *cmsg; |
670 | struct linux_cmsghdr linux_cmsg; |
671 | struct mbuf *m; |
672 | char *q, *q_end; |
673 | |
674 | if (mp->msg_controllen <= 0 || control == 0) { |
675 | mp->msg_controllen = 0; |
676 | free_control_mbuf(l, control, control); |
677 | return 0; |
678 | } |
679 | |
680 | ktrkuser("msgcontrol" , mtod(control, void *), mp->msg_controllen); |
681 | |
682 | q = (char *)mp->msg_control; |
683 | q_end = q + mp->msg_controllen; |
684 | |
685 | for (m = control; m != NULL; ) { |
686 | cmsg = mtod(m, struct cmsghdr *); |
687 | |
688 | /* |
689 | * Fixup cmsg. We handle two things: |
690 | * 0. different sizeof cmsg_len. |
691 | * 1. different values for level/type on some archs |
692 | * 2. different alignment of CMSG_DATA on some archs |
693 | */ |
694 | linux_cmsg.cmsg_len = cmsg->cmsg_len - LINUX_CMSG_ALIGN_DELTA; |
695 | linux_cmsg.cmsg_level = cmsg->cmsg_level; |
696 | linux_cmsg.cmsg_type = cmsg->cmsg_type; |
697 | |
698 | dlen = q_end - q; |
699 | if (linux_cmsg.cmsg_len > dlen) { |
700 | /* Not enough room for the parameter */ |
701 | dlen -= sizeof linux_cmsg; |
702 | if (dlen <= 0) |
703 | /* Discard if header wont fit */ |
704 | break; |
705 | mp->msg_flags |= MSG_CTRUNC; |
706 | if (linux_cmsg.cmsg_level == SOL_SOCKET |
707 | && linux_cmsg.cmsg_type == SCM_RIGHTS) |
708 | /* Do not truncate me ... */ |
709 | break; |
710 | } else |
711 | dlen = linux_cmsg.cmsg_len - sizeof linux_cmsg; |
712 | |
713 | switch (linux_cmsg.cmsg_level) { |
714 | case SOL_SOCKET: |
715 | linux_cmsg.cmsg_level = LINUX_SOL_SOCKET; |
716 | switch (linux_cmsg.cmsg_type) { |
717 | case SCM_RIGHTS: |
718 | /* Linux SCM_RIGHTS is same as NetBSD */ |
719 | break; |
720 | |
721 | default: |
722 | /* other types not supported */ |
723 | error = EINVAL; |
724 | goto done; |
725 | } |
726 | /* machine dependent ! */ |
727 | break; |
728 | default: |
729 | /* pray and leave intact */ |
730 | break; |
731 | } |
732 | |
733 | /* There can be padding between the header and data... */ |
734 | error = copyout(&linux_cmsg, q, sizeof linux_cmsg); |
735 | if (error != 0) { |
736 | error = copyout(CCMSG_DATA(cmsg), q + sizeof linux_cmsg, |
737 | dlen); |
738 | } |
739 | if (error != 0) { |
740 | /* We must free all the SCM_RIGHTS */ |
741 | m = control; |
742 | break; |
743 | } |
744 | m = m->m_next; |
745 | if (m == NULL || q + LINUX_CMSG_SPACE(dlen) > q_end) { |
746 | q += LINUX_CMSG_LEN(dlen); |
747 | break; |
748 | } |
749 | q += LINUX_CMSG_SPACE(dlen); |
750 | } |
751 | |
752 | done: |
753 | free_control_mbuf(l, control, m); |
754 | |
755 | mp->msg_controllen = q - (char *)mp->msg_control; |
756 | return error; |
757 | } |
758 | |
759 | int |
760 | linux_sys_recvmsg(struct lwp *l, const struct linux_sys_recvmsg_args *uap, register_t *retval) |
761 | { |
762 | /* { |
763 | syscallarg(int) s; |
764 | syscallarg(struct linux_msghdr *) msg; |
765 | syscallarg(u_int) flags; |
766 | } */ |
767 | struct msghdr msg; |
768 | struct linux_msghdr lmsg; |
769 | int error; |
770 | struct mbuf *from, *control; |
771 | |
772 | error = copyin(SCARG(uap, msg), &lmsg, sizeof(lmsg)); |
773 | if (error) |
774 | return (error); |
775 | linux_to_bsd_msghdr(&lmsg, &msg); |
776 | |
777 | msg.msg_flags = linux_to_bsd_msg_flags(SCARG(uap, flags)); |
778 | if (msg.msg_flags < 0) { |
779 | /* Some unsupported flag */ |
780 | return (EINVAL); |
781 | } |
782 | msg.msg_flags |= MSG_IOVUSRSPACE; |
783 | |
784 | error = do_sys_recvmsg(l, SCARG(uap, s), &msg, NULL, 0, &from, |
785 | msg.msg_control != NULL ? &control : NULL, retval); |
786 | if (error != 0) |
787 | return error; |
788 | |
789 | if (msg.msg_control != NULL) |
790 | error = linux_copyout_msg_control(l, &msg, control); |
791 | |
792 | if (error == 0 && from != 0) { |
793 | mtod(from, struct osockaddr *)->sa_family = |
794 | bsd_to_linux_domain(mtod(from, struct sockaddr *)->sa_family); |
795 | error = copyout_sockname(msg.msg_name, &msg.msg_namelen, 0, |
796 | from); |
797 | } else |
798 | msg.msg_namelen = 0; |
799 | |
800 | if (from != NULL) |
801 | m_free(from); |
802 | |
803 | if (error == 0) { |
804 | msg.msg_flags = bsd_to_linux_msg_flags(msg.msg_flags); |
805 | if (msg.msg_flags < 0) |
806 | /* Some flag unsupported by Linux */ |
807 | error = EINVAL; |
808 | else { |
809 | ktrkuser("msghdr" , &msg, sizeof(msg)); |
810 | bsd_to_linux_msghdr(&msg, &lmsg); |
811 | error = copyout(&lmsg, SCARG(uap, msg), sizeof(lmsg)); |
812 | } |
813 | } |
814 | |
815 | return (error); |
816 | } |
817 | |
818 | /* |
819 | * Convert socket option level from Linux to NetBSD value. Only SOL_SOCKET |
820 | * is different, the rest matches IPPROTO_* on both systems. |
821 | */ |
822 | int |
823 | linux_to_bsd_sopt_level(int llevel) |
824 | { |
825 | |
826 | switch (llevel) { |
827 | case LINUX_SOL_SOCKET: |
828 | return SOL_SOCKET; |
829 | case LINUX_SOL_IP: |
830 | return IPPROTO_IP; |
831 | #ifdef INET6 |
832 | case LINUX_SOL_IPV6: |
833 | return IPPROTO_IPV6; |
834 | #endif |
835 | case LINUX_SOL_TCP: |
836 | return IPPROTO_TCP; |
837 | case LINUX_SOL_UDP: |
838 | return IPPROTO_UDP; |
839 | default: |
840 | return -1; |
841 | } |
842 | } |
843 | |
844 | /* |
845 | * Convert Linux socket level socket option numbers to NetBSD values. |
846 | */ |
847 | int |
848 | linux_to_bsd_so_sockopt(int lopt) |
849 | { |
850 | |
851 | switch (lopt) { |
852 | case LINUX_SO_DEBUG: |
853 | return SO_DEBUG; |
854 | case LINUX_SO_REUSEADDR: |
855 | /* |
856 | * Linux does not implement SO_REUSEPORT, but allows reuse of a |
857 | * host:port pair through SO_REUSEADDR even if the address is not a |
858 | * multicast-address. Effectively, this means that we should use |
859 | * SO_REUSEPORT to allow Linux applications to not exit with |
860 | * EADDRINUSE |
861 | */ |
862 | return SO_REUSEPORT; |
863 | case LINUX_SO_TYPE: |
864 | return SO_TYPE; |
865 | case LINUX_SO_ERROR: |
866 | return SO_ERROR; |
867 | case LINUX_SO_DONTROUTE: |
868 | return SO_DONTROUTE; |
869 | case LINUX_SO_BROADCAST: |
870 | return SO_BROADCAST; |
871 | case LINUX_SO_SNDBUF: |
872 | return SO_SNDBUF; |
873 | case LINUX_SO_RCVBUF: |
874 | return SO_RCVBUF; |
875 | case LINUX_SO_SNDLOWAT: |
876 | return SO_SNDLOWAT; |
877 | case LINUX_SO_RCVLOWAT: |
878 | return SO_RCVLOWAT; |
879 | case LINUX_SO_KEEPALIVE: |
880 | return SO_KEEPALIVE; |
881 | case LINUX_SO_OOBINLINE: |
882 | return SO_OOBINLINE; |
883 | case LINUX_SO_LINGER: |
884 | return SO_LINGER; |
885 | case LINUX_SO_ACCEPTCONN: |
886 | return SO_ACCEPTCONN; |
887 | case LINUX_SO_PRIORITY: |
888 | case LINUX_SO_NO_CHECK: |
889 | default: |
890 | return -1; |
891 | } |
892 | } |
893 | |
894 | /* |
895 | * Convert Linux IP level socket option number to NetBSD values. |
896 | */ |
897 | int |
898 | linux_to_bsd_ip_sockopt(int lopt) |
899 | { |
900 | |
901 | switch (lopt) { |
902 | case LINUX_IP_TOS: |
903 | return IP_TOS; |
904 | case LINUX_IP_TTL: |
905 | return IP_TTL; |
906 | case LINUX_IP_HDRINCL: |
907 | return IP_HDRINCL; |
908 | case LINUX_IP_MULTICAST_TTL: |
909 | return IP_MULTICAST_TTL; |
910 | case LINUX_IP_MULTICAST_LOOP: |
911 | return IP_MULTICAST_LOOP; |
912 | case LINUX_IP_MULTICAST_IF: |
913 | return IP_MULTICAST_IF; |
914 | case LINUX_IP_ADD_MEMBERSHIP: |
915 | return IP_ADD_MEMBERSHIP; |
916 | case LINUX_IP_DROP_MEMBERSHIP: |
917 | return IP_DROP_MEMBERSHIP; |
918 | default: |
919 | return -1; |
920 | } |
921 | } |
922 | |
923 | /* |
924 | * Convert Linux IPV6 level socket option number to NetBSD values. |
925 | */ |
926 | #ifdef INET6 |
927 | int |
928 | linux_to_bsd_ipv6_sockopt(int lopt) |
929 | { |
930 | |
931 | switch (lopt) { |
932 | case LINUX_IPV6_V6ONLY: |
933 | return IPV6_V6ONLY; |
934 | default: |
935 | return -1; |
936 | } |
937 | } |
938 | #endif |
939 | |
940 | /* |
941 | * Convert Linux TCP level socket option number to NetBSD values. |
942 | */ |
943 | int |
944 | linux_to_bsd_tcp_sockopt(int lopt) |
945 | { |
946 | |
947 | switch (lopt) { |
948 | case LINUX_TCP_NODELAY: |
949 | return TCP_NODELAY; |
950 | case LINUX_TCP_MAXSEG: |
951 | return TCP_MAXSEG; |
952 | default: |
953 | return -1; |
954 | } |
955 | } |
956 | |
957 | /* |
958 | * Convert Linux UDP level socket option number to NetBSD values. |
959 | */ |
960 | int |
961 | linux_to_bsd_udp_sockopt(int lopt) |
962 | { |
963 | |
964 | switch (lopt) { |
965 | default: |
966 | return -1; |
967 | } |
968 | } |
969 | |
970 | /* |
971 | * Another reasonably straightforward function: setsockopt(2). |
972 | * The level and option numbers are converted; the values passed |
973 | * are not (yet) converted, the ones currently implemented don't |
974 | * need conversion, as they are the same on both systems. |
975 | */ |
976 | int |
977 | linux_sys_setsockopt(struct lwp *l, const struct linux_sys_setsockopt_args *uap, register_t *retval) |
978 | { |
979 | /* { |
980 | syscallarg(int) s; |
981 | syscallarg(int) level; |
982 | syscallarg(int) optname; |
983 | syscallarg(void *) optval; |
984 | syscallarg(int) optlen; |
985 | } */ |
986 | struct sys_setsockopt_args bsa; |
987 | int name; |
988 | |
989 | SCARG(&bsa, s) = SCARG(uap, s); |
990 | SCARG(&bsa, level) = linux_to_bsd_sopt_level(SCARG(uap, level)); |
991 | SCARG(&bsa, val) = SCARG(uap, optval); |
992 | SCARG(&bsa, valsize) = SCARG(uap, optlen); |
993 | |
994 | /* |
995 | * Linux supports only SOL_SOCKET for AF_LOCAL domain sockets |
996 | * and returns EOPNOTSUPP for other levels |
997 | */ |
998 | if (SCARG(&bsa, level) != SOL_SOCKET) { |
999 | struct socket *so; |
1000 | int error, family; |
1001 | |
1002 | /* fd_getsock() will use the descriptor for us */ |
1003 | if ((error = fd_getsock(SCARG(&bsa, s), &so)) != 0) |
1004 | return error; |
1005 | family = so->so_proto->pr_domain->dom_family; |
1006 | fd_putfile(SCARG(&bsa, s)); |
1007 | |
1008 | if (family == AF_LOCAL) |
1009 | return EOPNOTSUPP; |
1010 | } |
1011 | |
1012 | switch (SCARG(&bsa, level)) { |
1013 | case SOL_SOCKET: |
1014 | name = linux_to_bsd_so_sockopt(SCARG(uap, optname)); |
1015 | break; |
1016 | case IPPROTO_IP: |
1017 | name = linux_to_bsd_ip_sockopt(SCARG(uap, optname)); |
1018 | break; |
1019 | #ifdef INET6 |
1020 | case IPPROTO_IPV6: |
1021 | name = linux_to_bsd_ipv6_sockopt(SCARG(uap, optname)); |
1022 | break; |
1023 | #endif |
1024 | case IPPROTO_TCP: |
1025 | name = linux_to_bsd_tcp_sockopt(SCARG(uap, optname)); |
1026 | break; |
1027 | case IPPROTO_UDP: |
1028 | name = linux_to_bsd_udp_sockopt(SCARG(uap, optname)); |
1029 | break; |
1030 | default: |
1031 | return EINVAL; |
1032 | } |
1033 | |
1034 | if (name == -1) |
1035 | return EINVAL; |
1036 | SCARG(&bsa, name) = name; |
1037 | |
1038 | return sys_setsockopt(l, &bsa, retval); |
1039 | } |
1040 | |
1041 | /* |
1042 | * getsockopt(2) is very much the same as setsockopt(2) (see above) |
1043 | */ |
1044 | int |
1045 | linux_sys_getsockopt(struct lwp *l, const struct linux_sys_getsockopt_args *uap, register_t *retval) |
1046 | { |
1047 | /* { |
1048 | syscallarg(int) s; |
1049 | syscallarg(int) level; |
1050 | syscallarg(int) optname; |
1051 | syscallarg(void *) optval; |
1052 | syscallarg(int *) optlen; |
1053 | } */ |
1054 | struct sys_getsockopt_args bga; |
1055 | int name; |
1056 | |
1057 | SCARG(&bga, s) = SCARG(uap, s); |
1058 | SCARG(&bga, level) = linux_to_bsd_sopt_level(SCARG(uap, level)); |
1059 | SCARG(&bga, val) = SCARG(uap, optval); |
1060 | SCARG(&bga, avalsize) = (socklen_t *)SCARG(uap, optlen); |
1061 | |
1062 | switch (SCARG(&bga, level)) { |
1063 | case SOL_SOCKET: |
1064 | name = linux_to_bsd_so_sockopt(SCARG(uap, optname)); |
1065 | break; |
1066 | case IPPROTO_IP: |
1067 | name = linux_to_bsd_ip_sockopt(SCARG(uap, optname)); |
1068 | break; |
1069 | #ifdef INET6 |
1070 | case IPPROTO_IPV6: |
1071 | name = linux_to_bsd_ipv6_sockopt(SCARG(uap, optname)); |
1072 | break; |
1073 | #endif |
1074 | case IPPROTO_TCP: |
1075 | name = linux_to_bsd_tcp_sockopt(SCARG(uap, optname)); |
1076 | break; |
1077 | case IPPROTO_UDP: |
1078 | name = linux_to_bsd_udp_sockopt(SCARG(uap, optname)); |
1079 | break; |
1080 | default: |
1081 | return EINVAL; |
1082 | } |
1083 | |
1084 | if (name == -1) |
1085 | return EINVAL; |
1086 | SCARG(&bga, name) = name; |
1087 | |
1088 | return sys_getsockopt(l, &bga, retval); |
1089 | } |
1090 | |
1091 | int |
1092 | linux_getifname(struct lwp *l, register_t *retval, void *data) |
1093 | { |
1094 | struct ifnet *ifp; |
1095 | struct linux_ifreq ifr; |
1096 | int error; |
1097 | int s; |
1098 | |
1099 | error = copyin(data, &ifr, sizeof(ifr)); |
1100 | if (error) |
1101 | return error; |
1102 | |
1103 | s = pserialize_read_enter(); |
1104 | ifp = if_byindex(ifr.ifr_ifru.ifru_ifindex); |
1105 | if (ifp == NULL) { |
1106 | pserialize_read_exit(s); |
1107 | return ENODEV; |
1108 | } |
1109 | |
1110 | strncpy(ifr.ifr_name, ifp->if_xname, sizeof(ifr.ifr_name)); |
1111 | pserialize_read_exit(s); |
1112 | |
1113 | return copyout(&ifr, data, sizeof(ifr)); |
1114 | } |
1115 | |
1116 | int |
1117 | linux_getifconf(struct lwp *l, register_t *retval, void *data) |
1118 | { |
1119 | struct linux_ifreq ifr, *ifrp = NULL; |
1120 | struct linux_ifconf ifc; |
1121 | struct ifnet *ifp; |
1122 | struct sockaddr *sa; |
1123 | struct osockaddr *osa; |
1124 | int space = 0, error; |
1125 | const int sz = (int)sizeof(ifr); |
1126 | bool docopy; |
1127 | int s; |
1128 | int bound; |
1129 | struct psref psref; |
1130 | |
1131 | error = copyin(data, &ifc, sizeof(ifc)); |
1132 | if (error) |
1133 | return error; |
1134 | |
1135 | docopy = ifc.ifc_req != NULL; |
1136 | if (docopy) { |
1137 | space = ifc.ifc_len; |
1138 | ifrp = ifc.ifc_req; |
1139 | } |
1140 | |
1141 | bound = curlwp_bind(); |
1142 | s = pserialize_read_enter(); |
1143 | IFNET_READER_FOREACH(ifp) { |
1144 | struct ifaddr *ifa; |
1145 | psref_acquire(&psref, &ifp->if_psref, ifnet_psref_class); |
1146 | |
1147 | (void)strncpy(ifr.ifr_name, ifp->if_xname, |
1148 | sizeof(ifr.ifr_name)); |
1149 | if (ifr.ifr_name[sizeof(ifr.ifr_name) - 1] != '\0') { |
1150 | error = ENAMETOOLONG; |
1151 | goto release_exit; |
1152 | } |
1153 | |
1154 | IFADDR_READER_FOREACH(ifa, ifp) { |
1155 | struct psref psref_ifa; |
1156 | ifa_acquire(ifa, &psref_ifa); |
1157 | pserialize_read_exit(s); |
1158 | |
1159 | sa = ifa->ifa_addr; |
1160 | if (sa->sa_family != AF_INET || |
1161 | sa->sa_len > sizeof(*osa)) |
1162 | goto next; |
1163 | memcpy(&ifr.ifr_addr, sa, sa->sa_len); |
1164 | osa = (struct osockaddr *)&ifr.ifr_addr; |
1165 | osa->sa_family = sa->sa_family; |
1166 | if (space >= sz) { |
1167 | error = copyout(&ifr, ifrp, sz); |
1168 | if (error != 0) { |
1169 | s = pserialize_read_enter(); |
1170 | ifa_release(ifa, &psref_ifa); |
1171 | goto release_exit; |
1172 | } |
1173 | ifrp++; |
1174 | } |
1175 | space -= sz; |
1176 | next: |
1177 | s = pserialize_read_enter(); |
1178 | ifa_release(ifa, &psref_ifa); |
1179 | } |
1180 | |
1181 | psref_release(&psref, &ifp->if_psref, ifnet_psref_class); |
1182 | } |
1183 | pserialize_read_exit(s); |
1184 | curlwp_bindx(bound); |
1185 | |
1186 | if (docopy) |
1187 | ifc.ifc_len -= space; |
1188 | else |
1189 | ifc.ifc_len = -space; |
1190 | |
1191 | return copyout(&ifc, data, sizeof(ifc)); |
1192 | |
1193 | release_exit: |
1194 | pserialize_read_exit(s); |
1195 | psref_release(&psref, &ifp->if_psref, ifnet_psref_class); |
1196 | curlwp_bindx(bound); |
1197 | return error; |
1198 | } |
1199 | |
1200 | int |
1201 | linux_getifhwaddr(struct lwp *l, register_t *retval, u_int fd, |
1202 | void *data) |
1203 | { |
1204 | /* Not the full structure, just enough to map what we do here */ |
1205 | struct linux_ifreq lreq; |
1206 | file_t *fp; |
1207 | struct ifaddr *ifa; |
1208 | struct ifnet *ifp; |
1209 | struct sockaddr_dl *sadl; |
1210 | int error, found; |
1211 | int index, ifnum; |
1212 | int s; |
1213 | |
1214 | /* |
1215 | * We can't emulate this ioctl by calling sys_ioctl() to run |
1216 | * SIOCGIFCONF, because the user buffer is not of the right |
1217 | * type to take those results. We can't use kernel buffers to |
1218 | * receive the results, as the implementation of sys_ioctl() |
1219 | * and ifconf() [which implements SIOCGIFCONF] use |
1220 | * copyin()/copyout() which will fail on kernel addresses. |
1221 | * |
1222 | * So, we must duplicate code from sys_ioctl() and ifconf(). Ugh. |
1223 | */ |
1224 | |
1225 | if ((fp = fd_getfile(fd)) == NULL) |
1226 | return (EBADF); |
1227 | |
1228 | KERNEL_LOCK(1, NULL); |
1229 | |
1230 | if ((fp->f_flag & (FREAD | FWRITE)) == 0) { |
1231 | error = EBADF; |
1232 | goto out; |
1233 | } |
1234 | |
1235 | error = copyin(data, &lreq, sizeof(lreq)); |
1236 | if (error) |
1237 | goto out; |
1238 | lreq.ifr_name[LINUX_IFNAMSIZ-1] = '\0'; /* just in case */ |
1239 | |
1240 | /* |
1241 | * Try real interface name first, then fake "ethX" |
1242 | */ |
1243 | found = 0; |
1244 | s = pserialize_read_enter(); |
1245 | IFNET_READER_FOREACH(ifp) { |
1246 | if (found) |
1247 | break; |
1248 | if (strcmp(lreq.ifr_name, ifp->if_xname)) |
1249 | /* not this interface */ |
1250 | continue; |
1251 | |
1252 | found=1; |
1253 | if (IFADDR_READER_EMPTY(ifp)) { |
1254 | pserialize_read_exit(s); |
1255 | error = ENODEV; |
1256 | goto out; |
1257 | } |
1258 | IFADDR_READER_FOREACH(ifa, ifp) { |
1259 | sadl = satosdl(ifa->ifa_addr); |
1260 | /* only return ethernet addresses */ |
1261 | /* XXX what about FDDI, etc. ? */ |
1262 | if (sadl->sdl_family != AF_LINK || |
1263 | sadl->sdl_type != IFT_ETHER) |
1264 | continue; |
1265 | memcpy(&lreq.ifr_hwaddr.sa_data, CLLADDR(sadl), |
1266 | MIN(sadl->sdl_alen, |
1267 | sizeof(lreq.ifr_hwaddr.sa_data))); |
1268 | lreq.ifr_hwaddr.sa_family = |
1269 | sadl->sdl_family; |
1270 | pserialize_read_exit(s); |
1271 | |
1272 | error = copyout(&lreq, data, sizeof(lreq)); |
1273 | goto out; |
1274 | } |
1275 | } |
1276 | pserialize_read_exit(s); |
1277 | |
1278 | if (strncmp(lreq.ifr_name, "eth" , 3) != 0) { |
1279 | /* unknown interface, not even an "eth*" name */ |
1280 | error = ENODEV; |
1281 | goto out; |
1282 | } |
1283 | |
1284 | for (ifnum = 0, index = 3; |
1285 | index < LINUX_IFNAMSIZ && lreq.ifr_name[index] != '\0'; |
1286 | index++) { |
1287 | ifnum *= 10; |
1288 | ifnum += lreq.ifr_name[index] - '0'; |
1289 | } |
1290 | |
1291 | error = EINVAL; /* in case we don't find one */ |
1292 | s = pserialize_read_enter(); |
1293 | IFNET_READER_FOREACH(ifp) { |
1294 | memcpy(lreq.ifr_name, ifp->if_xname, |
1295 | MIN(LINUX_IFNAMSIZ, IFNAMSIZ)); |
1296 | IFADDR_READER_FOREACH(ifa, ifp) { |
1297 | sadl = satosdl(ifa->ifa_addr); |
1298 | /* only return ethernet addresses */ |
1299 | /* XXX what about FDDI, etc. ? */ |
1300 | if (sadl->sdl_family != AF_LINK || |
1301 | sadl->sdl_type != IFT_ETHER) |
1302 | continue; |
1303 | if (ifnum--) |
1304 | /* not the reqested iface */ |
1305 | continue; |
1306 | memcpy(&lreq.ifr_hwaddr.sa_data, |
1307 | CLLADDR(sadl), |
1308 | MIN(sadl->sdl_alen, |
1309 | sizeof(lreq.ifr_hwaddr.sa_data))); |
1310 | lreq.ifr_hwaddr.sa_family = |
1311 | sadl->sdl_family; |
1312 | pserialize_read_exit(s); |
1313 | |
1314 | error = copyout(&lreq, data, sizeof(lreq)); |
1315 | goto out; |
1316 | } |
1317 | } |
1318 | pserialize_read_exit(s); |
1319 | |
1320 | out: |
1321 | KERNEL_UNLOCK_ONE(NULL); |
1322 | fd_putfile(fd); |
1323 | return error; |
1324 | } |
1325 | |
1326 | int |
1327 | linux_ioctl_socket(struct lwp *l, const struct linux_sys_ioctl_args *uap, register_t *retval) |
1328 | { |
1329 | /* { |
1330 | syscallarg(int) fd; |
1331 | syscallarg(u_long) com; |
1332 | syscallarg(void *) data; |
1333 | } */ |
1334 | u_long com; |
1335 | int error = 0, isdev = 0, dosys = 1; |
1336 | struct sys_ioctl_args ia; |
1337 | file_t *fp; |
1338 | struct vnode *vp; |
1339 | int (*ioctlf)(file_t *, u_long, void *); |
1340 | struct ioctl_pt pt; |
1341 | |
1342 | if ((fp = fd_getfile(SCARG(uap, fd))) == NULL) |
1343 | return (EBADF); |
1344 | |
1345 | if (fp->f_type == DTYPE_VNODE) { |
1346 | vp = (struct vnode *)fp->f_data; |
1347 | isdev = vp->v_type == VCHR; |
1348 | } |
1349 | |
1350 | /* |
1351 | * Don't try to interpret socket ioctl calls that are done |
1352 | * on a device filedescriptor, just pass them through, to |
1353 | * emulate Linux behaviour. Use PTIOCLINUX so that the |
1354 | * device will only handle these if it's prepared to do |
1355 | * so, to avoid unexpected things from happening. |
1356 | */ |
1357 | if (isdev) { |
1358 | dosys = 0; |
1359 | ioctlf = fp->f_ops->fo_ioctl; |
1360 | pt.com = SCARG(uap, com); |
1361 | pt.data = SCARG(uap, data); |
1362 | error = ioctlf(fp, PTIOCLINUX, &pt); |
1363 | /* |
1364 | * XXX hack: if the function returns EJUSTRETURN, |
1365 | * it has stuffed a sysctl return value in pt.data. |
1366 | */ |
1367 | if (error == EJUSTRETURN) { |
1368 | retval[0] = (register_t)pt.data; |
1369 | error = 0; |
1370 | } |
1371 | goto out; |
1372 | } |
1373 | |
1374 | com = SCARG(uap, com); |
1375 | retval[0] = 0; |
1376 | |
1377 | switch (com) { |
1378 | case LINUX_SIOCGIFNAME: |
1379 | error = linux_getifname(l, retval, SCARG(uap, data)); |
1380 | dosys = 0; |
1381 | break; |
1382 | case LINUX_SIOCGIFCONF: |
1383 | error = linux_getifconf(l, retval, SCARG(uap, data)); |
1384 | dosys = 0; |
1385 | break; |
1386 | case LINUX_SIOCGIFFLAGS: |
1387 | SCARG(&ia, com) = OSIOCGIFFLAGS; |
1388 | break; |
1389 | case LINUX_SIOCSIFFLAGS: |
1390 | SCARG(&ia, com) = OSIOCSIFFLAGS; |
1391 | break; |
1392 | case LINUX_SIOCGIFADDR: |
1393 | SCARG(&ia, com) = OOSIOCGIFADDR; |
1394 | break; |
1395 | case LINUX_SIOCGIFDSTADDR: |
1396 | SCARG(&ia, com) = OOSIOCGIFDSTADDR; |
1397 | break; |
1398 | case LINUX_SIOCGIFBRDADDR: |
1399 | SCARG(&ia, com) = OOSIOCGIFBRDADDR; |
1400 | break; |
1401 | case LINUX_SIOCGIFNETMASK: |
1402 | SCARG(&ia, com) = OOSIOCGIFNETMASK; |
1403 | break; |
1404 | case LINUX_SIOCGIFMTU: |
1405 | SCARG(&ia, com) = OSIOCGIFMTU; |
1406 | break; |
1407 | case LINUX_SIOCADDMULTI: |
1408 | SCARG(&ia, com) = OSIOCADDMULTI; |
1409 | break; |
1410 | case LINUX_SIOCDELMULTI: |
1411 | SCARG(&ia, com) = OSIOCDELMULTI; |
1412 | break; |
1413 | case LINUX_SIOCGIFHWADDR: |
1414 | error = linux_getifhwaddr(l, retval, SCARG(uap, fd), |
1415 | SCARG(uap, data)); |
1416 | dosys = 0; |
1417 | break; |
1418 | default: |
1419 | error = EINVAL; |
1420 | } |
1421 | |
1422 | out: |
1423 | fd_putfile(SCARG(uap, fd)); |
1424 | |
1425 | if (error ==0 && dosys) { |
1426 | SCARG(&ia, fd) = SCARG(uap, fd); |
1427 | SCARG(&ia, data) = SCARG(uap, data); |
1428 | error = sys_ioctl(curlwp, &ia, retval); |
1429 | } |
1430 | |
1431 | return error; |
1432 | } |
1433 | |
1434 | int |
1435 | linux_sys_connect(struct lwp *l, const struct linux_sys_connect_args *uap, register_t *retval) |
1436 | { |
1437 | /* { |
1438 | syscallarg(int) s; |
1439 | syscallarg(const struct sockaddr *) name; |
1440 | syscallarg(int) namelen; |
1441 | } */ |
1442 | int error; |
1443 | struct sockaddr_big sb; |
1444 | |
1445 | error = linux_get_sa(l, SCARG(uap, s), &sb, SCARG(uap, name), |
1446 | SCARG(uap, namelen)); |
1447 | if (error) |
1448 | return (error); |
1449 | |
1450 | error = do_sys_connect(l, SCARG(uap, s), (struct sockaddr *)&sb); |
1451 | |
1452 | if (error == EISCONN) { |
1453 | struct socket *so; |
1454 | int state, prflags; |
1455 | |
1456 | /* fd_getsock() will use the descriptor for us */ |
1457 | if (fd_getsock(SCARG(uap, s), &so) != 0) |
1458 | return EISCONN; |
1459 | |
1460 | solock(so); |
1461 | state = so->so_state; |
1462 | prflags = so->so_proto->pr_flags; |
1463 | sounlock(so); |
1464 | fd_putfile(SCARG(uap, s)); |
1465 | /* |
1466 | * We should only let this call succeed once per |
1467 | * non-blocking connect; however we don't have |
1468 | * a convenient place to keep that state.. |
1469 | */ |
1470 | if ((state & (SS_ISCONNECTED|SS_NBIO)) == |
1471 | (SS_ISCONNECTED|SS_NBIO) && |
1472 | (prflags & PR_CONNREQUIRED)) |
1473 | return 0; |
1474 | } |
1475 | |
1476 | return (error); |
1477 | } |
1478 | |
1479 | int |
1480 | linux_sys_bind(struct lwp *l, const struct linux_sys_bind_args *uap, register_t *retval) |
1481 | { |
1482 | /* { |
1483 | syscallarg(int) s; |
1484 | syscallarg(const struct osockaddr *) name; |
1485 | syscallarg(int) namelen; |
1486 | } */ |
1487 | int error; |
1488 | struct sockaddr_big sb; |
1489 | |
1490 | error = linux_get_sa(l, SCARG(uap, s), &sb, SCARG(uap, name), |
1491 | SCARG(uap, namelen)); |
1492 | if (error) |
1493 | return (error); |
1494 | |
1495 | return do_sys_bind(l, SCARG(uap, s), (struct sockaddr *)&sb); |
1496 | } |
1497 | |
1498 | int |
1499 | linux_sys_getsockname(struct lwp *l, const struct linux_sys_getsockname_args *uap, register_t *retval) |
1500 | { |
1501 | /* { |
1502 | syscallarg(int) fdes; |
1503 | syscallarg(void *) asa; |
1504 | syscallarg(int *) alen; |
1505 | } */ |
1506 | int error; |
1507 | |
1508 | if ((error = sys_getsockname(l, (const void *)uap, retval)) != 0) |
1509 | return (error); |
1510 | |
1511 | if ((error = linux_sa_put((struct osockaddr *)SCARG(uap, asa)))) |
1512 | return (error); |
1513 | |
1514 | return (0); |
1515 | } |
1516 | |
1517 | int |
1518 | linux_sys_getpeername(struct lwp *l, const struct linux_sys_getpeername_args *uap, register_t *retval) |
1519 | { |
1520 | /* { |
1521 | syscallarg(int) fdes; |
1522 | syscallarg(void *) asa; |
1523 | syscallarg(int *) alen; |
1524 | } */ |
1525 | int error; |
1526 | |
1527 | if ((error = sys_getpeername(l, (const void *)uap, retval)) != 0) |
1528 | return (error); |
1529 | |
1530 | if ((error = linux_sa_put((struct osockaddr *)SCARG(uap, asa)))) |
1531 | return (error); |
1532 | |
1533 | return (0); |
1534 | } |
1535 | |
1536 | /* |
1537 | * Copy the osockaddr structure pointed to by name to sb, adjust |
1538 | * family and convert to sockaddr. |
1539 | */ |
1540 | static int |
1541 | linux_get_sa(struct lwp *l, int s, struct sockaddr_big *sb, |
1542 | const struct osockaddr *name, socklen_t namelen) |
1543 | { |
1544 | int error, bdom; |
1545 | |
1546 | if (namelen > UCHAR_MAX || |
1547 | namelen <= offsetof(struct sockaddr_big, sb_data)) |
1548 | return EINVAL; |
1549 | |
1550 | error = copyin(name, sb, namelen); |
1551 | if (error) |
1552 | return error; |
1553 | |
1554 | bdom = linux_to_bsd_domain(sb->sb_family); |
1555 | if (bdom == -1) |
1556 | return EINVAL; |
1557 | |
1558 | /* |
1559 | * If the family is unspecified, use address family of the socket. |
1560 | * This avoid triggering strict family checks in netinet/in_pcb.c et.al. |
1561 | */ |
1562 | if (bdom == AF_UNSPEC) { |
1563 | struct socket *so; |
1564 | |
1565 | /* fd_getsock() will use the descriptor for us */ |
1566 | if ((error = fd_getsock(s, &so)) != 0) |
1567 | return error; |
1568 | |
1569 | bdom = so->so_proto->pr_domain->dom_family; |
1570 | fd_putfile(s); |
1571 | } |
1572 | |
1573 | /* |
1574 | * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6, |
1575 | * which lacks the scope id compared with RFC2553 one. If we detect |
1576 | * the situation, reject the address and write a message to system log. |
1577 | * |
1578 | * Still accept addresses for which the scope id is not used. |
1579 | */ |
1580 | if (bdom == AF_INET6 && |
1581 | namelen == sizeof(struct sockaddr_in6) - sizeof(uint32_t)) { |
1582 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sb; |
1583 | if (!IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) && |
1584 | (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || |
1585 | IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) || |
1586 | IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) || |
1587 | IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) || |
1588 | IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) { |
1589 | struct proc *p = l->l_proc; |
1590 | int uid = l->l_cred ? kauth_cred_geteuid(l->l_cred) : -1; |
1591 | |
1592 | log(LOG_DEBUG, |
1593 | "pid %d (%s), uid %d: obsolete pre-RFC2553 " |
1594 | "sockaddr_in6 rejected" , |
1595 | p->p_pid, p->p_comm, uid); |
1596 | return EINVAL; |
1597 | } |
1598 | namelen = sizeof(struct sockaddr_in6); |
1599 | sin6->sin6_scope_id = 0; |
1600 | } |
1601 | |
1602 | if (bdom == AF_INET) |
1603 | namelen = sizeof(struct sockaddr_in); |
1604 | |
1605 | sb->sb_family = bdom; |
1606 | sb->sb_len = namelen; |
1607 | ktrkuser("mbsoname" , sb, namelen); |
1608 | return 0; |
1609 | } |
1610 | |
1611 | static int |
1612 | linux_sa_put(struct osockaddr *osa) |
1613 | { |
1614 | struct sockaddr sa; |
1615 | struct osockaddr *kosa; |
1616 | int error, bdom, len; |
1617 | |
1618 | /* |
1619 | * Only read/write the sockaddr family and length part, the rest is |
1620 | * not changed. |
1621 | */ |
1622 | len = sizeof(sa.sa_len) + sizeof(sa.sa_family); |
1623 | |
1624 | error = copyin(osa, &sa, len); |
1625 | if (error) |
1626 | return (error); |
1627 | |
1628 | bdom = bsd_to_linux_domain(sa.sa_family); |
1629 | if (bdom == -1) |
1630 | return (EINVAL); |
1631 | |
1632 | /* Note: we convert from sockaddr to osockaddr here, too */ |
1633 | kosa = (struct osockaddr *) &sa; |
1634 | kosa->sa_family = bdom; |
1635 | error = copyout(kosa, osa, len); |
1636 | if (error) |
1637 | return (error); |
1638 | |
1639 | return (0); |
1640 | } |
1641 | |
1642 | #ifndef __amd64__ |
1643 | int |
1644 | linux_sys_recv(struct lwp *l, const struct linux_sys_recv_args *uap, register_t *retval) |
1645 | { |
1646 | /* { |
1647 | syscallarg(int) s; |
1648 | syscallarg(void *) buf; |
1649 | syscallarg(int) len; |
1650 | syscallarg(int) flags; |
1651 | } */ |
1652 | struct sys_recvfrom_args bra; |
1653 | |
1654 | |
1655 | SCARG(&bra, s) = SCARG(uap, s); |
1656 | SCARG(&bra, buf) = SCARG(uap, buf); |
1657 | SCARG(&bra, len) = (size_t) SCARG(uap, len); |
1658 | SCARG(&bra, flags) = SCARG(uap, flags); |
1659 | SCARG(&bra, from) = NULL; |
1660 | SCARG(&bra, fromlenaddr) = NULL; |
1661 | |
1662 | return (sys_recvfrom(l, &bra, retval)); |
1663 | } |
1664 | |
1665 | int |
1666 | linux_sys_send(struct lwp *l, const struct linux_sys_send_args *uap, register_t *retval) |
1667 | { |
1668 | /* { |
1669 | syscallarg(int) s; |
1670 | syscallarg(void *) buf; |
1671 | syscallarg(int) len; |
1672 | syscallarg(int) flags; |
1673 | } */ |
1674 | struct sys_sendto_args bsa; |
1675 | |
1676 | SCARG(&bsa, s) = SCARG(uap, s); |
1677 | SCARG(&bsa, buf) = SCARG(uap, buf); |
1678 | SCARG(&bsa, len) = SCARG(uap, len); |
1679 | SCARG(&bsa, flags) = SCARG(uap, flags); |
1680 | SCARG(&bsa, to) = NULL; |
1681 | SCARG(&bsa, tolen) = 0; |
1682 | |
1683 | return (sys_sendto(l, &bsa, retval)); |
1684 | } |
1685 | #endif |
1686 | |
1687 | int |
1688 | linux_sys_accept(struct lwp *l, const struct linux_sys_accept_args *uap, register_t *retval) |
1689 | { |
1690 | /* { |
1691 | syscallarg(int) s; |
1692 | syscallarg(struct osockaddr *) name; |
1693 | syscallarg(int *) anamelen; |
1694 | } */ |
1695 | int error; |
1696 | struct sys_accept_args baa; |
1697 | |
1698 | SCARG(&baa, s) = SCARG(uap, s); |
1699 | SCARG(&baa, name) = (struct sockaddr *) SCARG(uap, name); |
1700 | SCARG(&baa, anamelen) = (unsigned int *) SCARG(uap, anamelen); |
1701 | |
1702 | if ((error = sys_accept(l, &baa, retval))) |
1703 | return (error); |
1704 | |
1705 | if (SCARG(uap, name) && (error = linux_sa_put(SCARG(uap, name)))) |
1706 | return (error); |
1707 | |
1708 | return (0); |
1709 | } |
1710 | |