1 | /* $NetBSD: linux32_socket.c,v 1.26 2016/08/01 03:15:30 ozaki-r Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 2006 Emmanuel Dreyfus, all rights reserved. |
5 | * |
6 | * Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions |
8 | * are met: |
9 | * 1. Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following disclaimer. |
11 | * 2. Redistributions in binary form must reproduce the above copyright |
12 | * notice, this list of conditions and the following disclaimer in the |
13 | * documentation and/or other materials provided with the distribution. |
14 | * 3. All advertising materials mentioning features or use of this software |
15 | * must display the following acknowledgement: |
16 | * This product includes software developed by Emmanuel Dreyfus |
17 | * 4. The name of the author may not be used to endorse or promote |
18 | * products derived from this software without specific prior written |
19 | * permission. |
20 | * |
21 | * THIS SOFTWARE IS PROVIDED BY THE THE AUTHOR AND CONTRIBUTORS ``AS IS'' |
22 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
23 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
24 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS |
25 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
31 | * POSSIBILITY OF SUCH DAMAGE. |
32 | */ |
33 | |
34 | #include <sys/cdefs.h> |
35 | |
36 | __KERNEL_RCSID(0, "$NetBSD: linux32_socket.c,v 1.26 2016/08/01 03:15:30 ozaki-r Exp $" ); |
37 | |
38 | #include <sys/types.h> |
39 | #include <sys/param.h> |
40 | #include <sys/fstypes.h> |
41 | #include <sys/signal.h> |
42 | #include <sys/dirent.h> |
43 | #include <sys/kernel.h> |
44 | #include <sys/fcntl.h> |
45 | #include <sys/select.h> |
46 | #include <sys/proc.h> |
47 | #include <sys/ucred.h> |
48 | #include <sys/swap.h> |
49 | #include <sys/file.h> |
50 | #include <sys/vnode.h> |
51 | #include <sys/filedesc.h> |
52 | |
53 | #include <machine/types.h> |
54 | |
55 | #include <net/if.h> |
56 | #include <net/if_dl.h> |
57 | #include <net/if_types.h> |
58 | #include <net/route.h> |
59 | |
60 | #include <netinet/in.h> |
61 | #include <netinet/ip_mroute.h> |
62 | |
63 | #include <sys/syscallargs.h> |
64 | |
65 | #include <compat/netbsd32/netbsd32.h> |
66 | #include <compat/netbsd32/netbsd32_ioctl.h> |
67 | #include <compat/netbsd32/netbsd32_conv.h> |
68 | #include <compat/netbsd32/netbsd32_syscallargs.h> |
69 | |
70 | #include <compat/sys/socket.h> |
71 | #include <compat/sys/sockio.h> |
72 | |
73 | #include <compat/linux/common/linux_types.h> |
74 | #include <compat/linux/common/linux_types.h> |
75 | #include <compat/linux/common/linux_signal.h> |
76 | #include <compat/linux/common/linux_machdep.h> |
77 | #include <compat/linux/common/linux_misc.h> |
78 | #include <compat/linux/common/linux_oldolduname.h> |
79 | #include <compat/linux/common/linux_ioctl.h> |
80 | #include <compat/linux/common/linux_sockio.h> |
81 | #include <compat/linux/common/linux_ipc.h> |
82 | #include <compat/linux/common/linux_sem.h> |
83 | #include <compat/linux/linux_syscallargs.h> |
84 | |
85 | #include <compat/linux32/common/linux32_types.h> |
86 | #include <compat/linux32/common/linux32_signal.h> |
87 | #include <compat/linux32/common/linux32_machdep.h> |
88 | #include <compat/linux32/common/linux32_sysctl.h> |
89 | #include <compat/linux32/common/linux32_socketcall.h> |
90 | #include <compat/linux32/common/linux32_sockio.h> |
91 | #include <compat/linux32/common/linux32_ioctl.h> |
92 | #include <compat/linux32/linux32_syscallargs.h> |
93 | |
94 | int linux32_getifname(struct lwp *, register_t *, void *); |
95 | int linux32_getifconf(struct lwp *, register_t *, void *); |
96 | int linux32_getifhwaddr(struct lwp *, register_t *, u_int, void *); |
97 | |
98 | int |
99 | linux32_sys_socketpair(struct lwp *l, const struct linux32_sys_socketpair_args *uap, register_t *retval) |
100 | { |
101 | /* { |
102 | syscallarg(int) domain; |
103 | syscallarg(int) type; |
104 | syscallarg(int) protocol; |
105 | syscallarg(netbsd32_intp) rsv; |
106 | } */ |
107 | struct linux_sys_socketpair_args ua; |
108 | |
109 | NETBSD32TO64_UAP(domain); |
110 | NETBSD32TO64_UAP(type); |
111 | NETBSD32TO64_UAP(protocol); |
112 | NETBSD32TOP_UAP(rsv, int); |
113 | |
114 | return linux_sys_socketpair(l, &ua, retval); |
115 | } |
116 | |
117 | int |
118 | linux32_sys_sendto(struct lwp *l, const struct linux32_sys_sendto_args *uap, register_t *retval) |
119 | { |
120 | /* { |
121 | syscallarg(int) s; |
122 | syscallarg(netbsd32_voidp) msg; |
123 | syscallarg(int) len; |
124 | syscallarg(int) flags; |
125 | syscallarg(netbsd32_osockaddrp_t) to; |
126 | syscallarg(int) tolen; |
127 | } */ |
128 | struct linux_sys_sendto_args ua; |
129 | |
130 | NETBSD32TO64_UAP(s); |
131 | NETBSD32TOP_UAP(msg, void); |
132 | NETBSD32TO64_UAP(len); |
133 | NETBSD32TO64_UAP(flags); |
134 | NETBSD32TOP_UAP(to, struct osockaddr); |
135 | NETBSD32TO64_UAP(tolen); |
136 | |
137 | return linux_sys_sendto(l, &ua, retval); |
138 | } |
139 | |
140 | |
141 | int |
142 | linux32_sys_recvfrom(struct lwp *l, const struct linux32_sys_recvfrom_args *uap, register_t *retval) |
143 | { |
144 | /* { |
145 | syscallarg(int) s; |
146 | syscallarg(netbsd32_voidp) buf; |
147 | syscallarg(netbsd32_size_t) len; |
148 | syscallarg(int) flags; |
149 | syscallarg(netbsd32_osockaddrp_t) from; |
150 | syscallarg(netbsd32_intp) fromlenaddr; |
151 | } */ |
152 | struct linux_sys_recvfrom_args ua; |
153 | |
154 | NETBSD32TO64_UAP(s); |
155 | NETBSD32TOP_UAP(buf, void); |
156 | NETBSD32TO64_UAP(len); |
157 | NETBSD32TO64_UAP(flags); |
158 | NETBSD32TOP_UAP(from, struct osockaddr); |
159 | NETBSD32TOP_UAP(fromlenaddr, unsigned int); |
160 | |
161 | return linux_sys_recvfrom(l, &ua, retval); |
162 | } |
163 | |
164 | int |
165 | linux32_sys_setsockopt(struct lwp *l, const struct linux32_sys_setsockopt_args *uap, register_t *retval) |
166 | { |
167 | /* { |
168 | syscallarg(int) s; |
169 | syscallarg(int) level; |
170 | syscallarg(int) optname; |
171 | syscallarg(netbsd32_voidp) optval; |
172 | syscallarg(int) optlen; |
173 | } */ |
174 | struct linux_sys_setsockopt_args ua; |
175 | |
176 | NETBSD32TO64_UAP(s); |
177 | NETBSD32TO64_UAP(level); |
178 | NETBSD32TO64_UAP(optname); |
179 | NETBSD32TOP_UAP(optval, void); |
180 | NETBSD32TO64_UAP(optlen); |
181 | |
182 | return linux_sys_setsockopt(l, &ua, retval); |
183 | } |
184 | |
185 | |
186 | int |
187 | linux32_sys_getsockopt(struct lwp *l, const struct linux32_sys_getsockopt_args *uap, register_t *retval) |
188 | { |
189 | /* { |
190 | syscallarg(int) s; |
191 | syscallarg(int) level; |
192 | syscallarg(int) optname; |
193 | syscallarg(netbsd32_voidp) optval; |
194 | syscallarg(netbsd32_intp) optlen; |
195 | } */ |
196 | struct linux_sys_getsockopt_args ua; |
197 | |
198 | NETBSD32TO64_UAP(s); |
199 | NETBSD32TO64_UAP(level); |
200 | NETBSD32TO64_UAP(optname); |
201 | NETBSD32TOP_UAP(optval, void); |
202 | NETBSD32TOP_UAP(optlen, int); |
203 | |
204 | return linux_sys_getsockopt(l, &ua, retval); |
205 | } |
206 | |
207 | int |
208 | linux32_sys_socket(struct lwp *l, const struct linux32_sys_socket_args *uap, register_t *retval) |
209 | { |
210 | /* { |
211 | syscallarg(int) domain; |
212 | syscallarg(int) type; |
213 | syscallarg(int) protocol; |
214 | } */ |
215 | struct linux_sys_socket_args ua; |
216 | |
217 | NETBSD32TO64_UAP(domain); |
218 | NETBSD32TO64_UAP(type); |
219 | NETBSD32TO64_UAP(protocol); |
220 | |
221 | return linux_sys_socket(l, &ua, retval); |
222 | } |
223 | |
224 | int |
225 | linux32_sys_bind(struct lwp *l, const struct linux32_sys_bind_args *uap, register_t *retval) |
226 | { |
227 | /* { |
228 | syscallarg(int) s; |
229 | syscallarg(netbsd32_osockaddrp_t) name; |
230 | syscallarg(int) namelen; |
231 | } */ |
232 | struct linux_sys_bind_args ua; |
233 | |
234 | NETBSD32TO64_UAP(s); |
235 | NETBSD32TOP_UAP(name, struct osockaddr); |
236 | NETBSD32TO64_UAP(namelen); |
237 | |
238 | return linux_sys_bind(l, &ua, retval); |
239 | } |
240 | |
241 | int |
242 | linux32_sys_connect(struct lwp *l, const struct linux32_sys_connect_args *uap, register_t *retval) |
243 | { |
244 | /* { |
245 | syscallarg(int) s; |
246 | syscallarg(netbsd32_osockaddrp_t) name; |
247 | syscallarg(int) namelen; |
248 | } */ |
249 | struct linux_sys_connect_args ua; |
250 | |
251 | NETBSD32TO64_UAP(s); |
252 | NETBSD32TOP_UAP(name, struct osockaddr); |
253 | NETBSD32TO64_UAP(namelen); |
254 | |
255 | #ifdef DEBUG_LINUX |
256 | printf("linux32_sys_connect: s = %d, name = %p, namelen = %d\n" , |
257 | SCARG(&ua, s), SCARG(&ua, name), SCARG(&ua, namelen)); |
258 | #endif |
259 | |
260 | return linux_sys_connect(l, &ua, retval); |
261 | } |
262 | |
263 | int |
264 | linux32_sys_accept(struct lwp *l, const struct linux32_sys_accept_args *uap, register_t *retval) |
265 | { |
266 | /* { |
267 | syscallarg(int) s; |
268 | syscallarg(netbsd32_osockaddrp_t) name; |
269 | syscallarg(netbsd32_intp) anamelen; |
270 | } */ |
271 | struct linux_sys_accept_args ua; |
272 | |
273 | NETBSD32TO64_UAP(s); |
274 | NETBSD32TOP_UAP(name, struct osockaddr); |
275 | NETBSD32TOP_UAP(anamelen, int); |
276 | |
277 | return linux_sys_accept(l, &ua, retval); |
278 | } |
279 | |
280 | int |
281 | linux32_sys_getpeername(struct lwp *l, const struct linux32_sys_getpeername_args *uap, register_t *retval) |
282 | { |
283 | /* { |
284 | syscallarg(int) fdes; |
285 | syscallarg(netbsd32_sockaddrp_t) asa; |
286 | syscallarg(netbsd32_intp) alen; |
287 | } */ |
288 | struct linux_sys_getpeername_args ua; |
289 | |
290 | NETBSD32TO64_UAP(fdes); |
291 | NETBSD32TOP_UAP(asa, struct sockaddr); |
292 | NETBSD32TOP_UAP(alen, int); |
293 | |
294 | return linux_sys_getpeername(l, &ua, retval); |
295 | } |
296 | |
297 | int |
298 | linux32_sys_getsockname(struct lwp *l, const struct linux32_sys_getsockname_args *uap, register_t *retval) |
299 | { |
300 | /* { |
301 | syscallarg(int) fdec; |
302 | syscallarg(netbsd32_charp) asa; |
303 | syscallarg(netbsd32_intp) alen; |
304 | } */ |
305 | struct linux_sys_getsockname_args ua; |
306 | |
307 | NETBSD32TO64_UAP(fdec); |
308 | NETBSD32TOP_UAP(asa, char); |
309 | NETBSD32TOP_UAP(alen, int); |
310 | |
311 | return linux_sys_getsockname(l, &ua, retval); |
312 | } |
313 | |
314 | int |
315 | linux32_sys_sendmsg(struct lwp *l, const struct linux32_sys_sendmsg_args *uap, register_t *retval) |
316 | { |
317 | /* { |
318 | syscallarg(int) s; |
319 | syscallarg(netbsd32_msghdrp_t) msg; |
320 | syscallarg(int) flags; |
321 | } */ |
322 | struct linux_sys_sendmsg_args ua; |
323 | |
324 | NETBSD32TO64_UAP(s); |
325 | NETBSD32TOP_UAP(msg, struct msghdr); |
326 | NETBSD32TO64_UAP(flags); |
327 | |
328 | return linux_sys_sendmsg(l, &ua, retval); |
329 | } |
330 | |
331 | int |
332 | linux32_sys_recvmsg(struct lwp *l, const struct linux32_sys_recvmsg_args *uap, register_t *retval) |
333 | { |
334 | /* { |
335 | syscallarg(int) s; |
336 | syscallarg(netbsd32_msghdrp_t) msg; |
337 | syscallarg(int) flags; |
338 | } */ |
339 | struct linux_sys_recvmsg_args ua; |
340 | |
341 | NETBSD32TO64_UAP(s); |
342 | NETBSD32TOP_UAP(msg, struct msghdr); |
343 | NETBSD32TO64_UAP(flags); |
344 | |
345 | return linux_sys_recvmsg(l, &ua, retval); |
346 | } |
347 | |
348 | int |
349 | linux32_sys_send(struct lwp *l, const struct linux32_sys_send_args *uap, register_t *retval) |
350 | { |
351 | /* { |
352 | syscallarg(int) s; |
353 | syscallarg(netbsd32_voidp) buf; |
354 | syscallarg(int) len; |
355 | syscallarg(int) flags; |
356 | } */ |
357 | struct sys_sendto_args ua; |
358 | |
359 | NETBSD32TO64_UAP(s); |
360 | NETBSD32TOP_UAP(buf, void); |
361 | NETBSD32TO64_UAP(len); |
362 | NETBSD32TO64_UAP(flags); |
363 | SCARG(&ua, to) = NULL; |
364 | SCARG(&ua, tolen) = 0; |
365 | |
366 | return sys_sendto(l, &ua, retval); |
367 | } |
368 | |
369 | int |
370 | linux32_sys_recv(struct lwp *l, const struct linux32_sys_recv_args *uap, register_t *retval) |
371 | { |
372 | /* { |
373 | syscallarg(int) s; |
374 | syscallarg(netbsd32_voidp) buf; |
375 | syscallarg(int) len; |
376 | syscallarg(int) flags; |
377 | } */ |
378 | struct sys_recvfrom_args ua; |
379 | |
380 | NETBSD32TO64_UAP(s); |
381 | NETBSD32TOP_UAP(buf, void); |
382 | NETBSD32TO64_UAP(len); |
383 | NETBSD32TO64_UAP(flags); |
384 | SCARG(&ua, from) = NULL; |
385 | SCARG(&ua, fromlenaddr) = NULL; |
386 | |
387 | return sys_recvfrom(l, &ua, retval); |
388 | } |
389 | |
390 | int |
391 | linux32_getifname(struct lwp *l, register_t *retval, void *data) |
392 | { |
393 | struct ifnet *ifp; |
394 | struct linux32_ifreq ifr; |
395 | int error; |
396 | int s; |
397 | |
398 | error = copyin(data, &ifr, sizeof(ifr)); |
399 | if (error) |
400 | return error; |
401 | |
402 | s = pserialize_read_enter(); |
403 | ifp = if_byindex(ifr.ifr_ifru.ifru_ifindex); |
404 | if (ifp == NULL) { |
405 | pserialize_read_exit(s); |
406 | return ENODEV; |
407 | } |
408 | |
409 | strncpy(ifr.ifr_name, ifp->if_xname, sizeof(ifr.ifr_name)); |
410 | pserialize_read_exit(s); |
411 | |
412 | return copyout(&ifr, data, sizeof(ifr)); |
413 | } |
414 | |
415 | int |
416 | linux32_getifconf(struct lwp *l, register_t *retval, void *data) |
417 | { |
418 | struct linux32_ifreq ifr, *ifrp = NULL; |
419 | struct linux32_ifconf ifc; |
420 | struct ifnet *ifp; |
421 | struct sockaddr *sa; |
422 | struct osockaddr *osa; |
423 | int space = 0, error; |
424 | const int sz = (int)sizeof(ifr); |
425 | bool docopy; |
426 | int s; |
427 | int bound; |
428 | struct psref psref; |
429 | |
430 | error = copyin(data, &ifc, sizeof(ifc)); |
431 | if (error) |
432 | return error; |
433 | |
434 | docopy = NETBSD32PTR64(ifc.ifc_req) != NULL; |
435 | if (docopy) { |
436 | space = ifc.ifc_len; |
437 | ifrp = NETBSD32PTR64(ifc.ifc_req); |
438 | } |
439 | |
440 | bound = curlwp_bind(); |
441 | s = pserialize_read_enter(); |
442 | IFNET_READER_FOREACH(ifp) { |
443 | struct ifaddr *ifa; |
444 | psref_acquire(&psref, &ifp->if_psref, ifnet_psref_class); |
445 | |
446 | (void)strncpy(ifr.ifr_name, ifp->if_xname, |
447 | sizeof(ifr.ifr_name)); |
448 | if (ifr.ifr_name[sizeof(ifr.ifr_name) - 1] != '\0') { |
449 | error = ENAMETOOLONG; |
450 | goto release_exit; |
451 | } |
452 | |
453 | IFADDR_READER_FOREACH(ifa, ifp) { |
454 | struct psref psref_ifa; |
455 | ifa_acquire(ifa, &psref_ifa); |
456 | pserialize_read_exit(s); |
457 | |
458 | sa = ifa->ifa_addr; |
459 | if (sa->sa_family != AF_INET || |
460 | sa->sa_len > sizeof(*osa)) |
461 | goto next; |
462 | memcpy(&ifr.ifr_addr, sa, sa->sa_len); |
463 | osa = (struct osockaddr *)&ifr.ifr_addr; |
464 | osa->sa_family = sa->sa_family; |
465 | if (space >= sz) { |
466 | error = copyout(&ifr, ifrp, sz); |
467 | if (error != 0) { |
468 | s = pserialize_read_enter(); |
469 | ifa_release(ifa, &psref_ifa); |
470 | goto release_exit; |
471 | } |
472 | ifrp++; |
473 | } |
474 | space -= sz; |
475 | next: |
476 | s = pserialize_read_enter(); |
477 | ifa_release(ifa, &psref_ifa); |
478 | } |
479 | |
480 | psref_release(&psref, &ifp->if_psref, ifnet_psref_class); |
481 | } |
482 | pserialize_read_exit(s); |
483 | curlwp_bindx(bound); |
484 | |
485 | if (docopy) |
486 | ifc.ifc_len -= space; |
487 | else |
488 | ifc.ifc_len = -space; |
489 | |
490 | return copyout(&ifc, data, sizeof(ifc)); |
491 | |
492 | release_exit: |
493 | pserialize_read_exit(s); |
494 | psref_release(&psref, &ifp->if_psref, ifnet_psref_class); |
495 | curlwp_bindx(bound); |
496 | return error; |
497 | } |
498 | |
499 | int |
500 | linux32_getifhwaddr(struct lwp *l, register_t *retval, u_int fd, |
501 | void *data) |
502 | { |
503 | struct linux32_ifreq lreq; |
504 | file_t *fp; |
505 | struct ifaddr *ifa; |
506 | struct ifnet *ifp; |
507 | struct sockaddr_dl *sadl; |
508 | int error, found; |
509 | int index, ifnum; |
510 | int s; |
511 | |
512 | /* |
513 | * We can't emulate this ioctl by calling sys_ioctl() to run |
514 | * SIOCGIFCONF, because the user buffer is not of the right |
515 | * type to take those results. We can't use kernel buffers to |
516 | * receive the results, as the implementation of sys_ioctl() |
517 | * and ifconf() [which implements SIOCGIFCONF] use |
518 | * copyin()/copyout() which will fail on kernel addresses. |
519 | * |
520 | * So, we must duplicate code from sys_ioctl() and ifconf(). Ugh. |
521 | */ |
522 | |
523 | if ((fp = fd_getfile(fd)) == NULL) |
524 | return (EBADF); |
525 | |
526 | KERNEL_LOCK(1, NULL); |
527 | |
528 | if ((fp->f_flag & (FREAD | FWRITE)) == 0) { |
529 | error = EBADF; |
530 | goto out; |
531 | } |
532 | |
533 | error = copyin(data, &lreq, sizeof(lreq)); |
534 | if (error) |
535 | goto out; |
536 | lreq.ifr_name[LINUX32_IFNAMSIZ-1] = '\0'; /* just in case */ |
537 | |
538 | /* |
539 | * Try real interface name first, then fake "ethX" |
540 | */ |
541 | found = 0; |
542 | s = pserialize_read_enter(); |
543 | IFNET_READER_FOREACH(ifp) { |
544 | if (found) |
545 | break; |
546 | if (strcmp(lreq.ifr_name, ifp->if_xname)) |
547 | /* not this interface */ |
548 | continue; |
549 | found=1; |
550 | if (IFADDR_READER_EMPTY(ifp)) { |
551 | error = ENODEV; |
552 | goto out; |
553 | } |
554 | IFADDR_READER_FOREACH(ifa, ifp) { |
555 | sadl = satosdl(ifa->ifa_addr); |
556 | /* only return ethernet addresses */ |
557 | /* XXX what about FDDI, etc. ? */ |
558 | if (sadl->sdl_family != AF_LINK || |
559 | sadl->sdl_type != IFT_ETHER) |
560 | continue; |
561 | memcpy(&lreq.ifr_hwaddr.sa_data, CLLADDR(sadl), |
562 | MIN(sadl->sdl_alen, |
563 | sizeof(lreq.ifr_hwaddr.sa_data))); |
564 | lreq.ifr_hwaddr.sa_family = |
565 | sadl->sdl_family; |
566 | pserialize_read_exit(s); |
567 | |
568 | error = copyout(&lreq, data, sizeof(lreq)); |
569 | goto out; |
570 | } |
571 | } |
572 | pserialize_read_exit(s); |
573 | |
574 | if (strncmp(lreq.ifr_name, "eth" , 3) == 0) { |
575 | for (ifnum = 0, index = 3; |
576 | index < LINUX32_IFNAMSIZ && lreq.ifr_name[index] != '\0'; |
577 | index++) { |
578 | ifnum *= 10; |
579 | ifnum += lreq.ifr_name[index] - '0'; |
580 | } |
581 | |
582 | error = EINVAL; /* in case we don't find one */ |
583 | s = pserialize_read_enter(); |
584 | IFNET_READER_FOREACH(ifp) { |
585 | memcpy(lreq.ifr_name, ifp->if_xname, |
586 | MIN(LINUX32_IFNAMSIZ, IFNAMSIZ)); |
587 | IFADDR_READER_FOREACH(ifa, ifp) { |
588 | sadl = satosdl(ifa->ifa_addr); |
589 | /* only return ethernet addresses */ |
590 | /* XXX what about FDDI, etc. ? */ |
591 | if (sadl->sdl_family != AF_LINK || |
592 | sadl->sdl_type != IFT_ETHER) |
593 | continue; |
594 | if (ifnum--) |
595 | /* not the reqested iface */ |
596 | continue; |
597 | memcpy(&lreq.ifr_hwaddr.sa_data, |
598 | CLLADDR(sadl), |
599 | MIN(sadl->sdl_alen, |
600 | sizeof(lreq.ifr_hwaddr.sa_data))); |
601 | lreq.ifr_hwaddr.sa_family = |
602 | sadl->sdl_family; |
603 | pserialize_read_exit(s); |
604 | |
605 | error = copyout(&lreq, data, sizeof(lreq)); |
606 | goto out; |
607 | } |
608 | } |
609 | pserialize_read_exit(s); |
610 | } else { |
611 | /* unknown interface, not even an "eth*" name */ |
612 | error = ENODEV; |
613 | } |
614 | |
615 | out: |
616 | KERNEL_UNLOCK_ONE(NULL); |
617 | fd_putfile(fd); |
618 | return error; |
619 | } |
620 | |
621 | int |
622 | linux32_ioctl_socket(struct lwp *l, const struct linux32_sys_ioctl_args *uap, register_t *retval) |
623 | { |
624 | /* { |
625 | syscallarg(int) fd; |
626 | syscallarg(u_long) com; |
627 | syscallarg(void *) data; |
628 | } */ |
629 | u_long com; |
630 | int error = 0, isdev = 0, dosys = 1; |
631 | struct netbsd32_ioctl_args ia; |
632 | file_t *fp; |
633 | struct vnode *vp; |
634 | int (*ioctlf)(file_t *, u_long, void *); |
635 | struct ioctl_pt pt; |
636 | |
637 | if ((fp = fd_getfile(SCARG(uap, fd))) == NULL) |
638 | return (EBADF); |
639 | |
640 | if (fp->f_type == DTYPE_VNODE) { |
641 | vp = (struct vnode *)fp->f_data; |
642 | isdev = vp->v_type == VCHR; |
643 | } |
644 | |
645 | /* |
646 | * Don't try to interpret socket ioctl calls that are done |
647 | * on a device filedescriptor, just pass them through, to |
648 | * emulate Linux behaviour. Use PTIOCLINUX so that the |
649 | * device will only handle these if it's prepared to do |
650 | * so, to avoid unexpected things from happening. |
651 | */ |
652 | if (isdev) { |
653 | dosys = 0; |
654 | ioctlf = fp->f_ops->fo_ioctl; |
655 | pt.com = SCARG(uap, com); |
656 | pt.data = (void *)NETBSD32PTR64(SCARG(uap, data)); |
657 | error = ioctlf(fp, PTIOCLINUX, &pt); |
658 | /* |
659 | * XXX hack: if the function returns EJUSTRETURN, |
660 | * it has stuffed a sysctl return value in pt.data. |
661 | */ |
662 | if (error == EJUSTRETURN) { |
663 | retval[0] = (register_t)pt.data; |
664 | error = 0; |
665 | } |
666 | goto out; |
667 | } |
668 | |
669 | com = SCARG(uap, com); |
670 | retval[0] = 0; |
671 | |
672 | switch (com) { |
673 | case LINUX_SIOCGIFNAME: |
674 | error = linux32_getifname(l, retval, SCARG_P32(uap, data)); |
675 | dosys = 0; |
676 | break; |
677 | case LINUX_SIOCGIFCONF: |
678 | error = linux32_getifconf(l, retval, SCARG_P32(uap, data)); |
679 | dosys = 0; |
680 | break; |
681 | case LINUX_SIOCGIFFLAGS: |
682 | SCARG(&ia, com) = OSIOCGIFFLAGS32; |
683 | break; |
684 | case LINUX_SIOCSIFFLAGS: |
685 | SCARG(&ia, com) = OSIOCSIFFLAGS32; |
686 | break; |
687 | case LINUX_SIOCGIFADDR: |
688 | SCARG(&ia, com) = OOSIOCGIFADDR32; |
689 | break; |
690 | case LINUX_SIOCGIFDSTADDR: |
691 | SCARG(&ia, com) = OOSIOCGIFDSTADDR32; |
692 | break; |
693 | case LINUX_SIOCGIFBRDADDR: |
694 | SCARG(&ia, com) = OOSIOCGIFBRDADDR32; |
695 | break; |
696 | case LINUX_SIOCGIFNETMASK: |
697 | SCARG(&ia, com) = OOSIOCGIFNETMASK32; |
698 | break; |
699 | case LINUX_SIOCGIFMTU: |
700 | SCARG(&ia, com) = OSIOCGIFMTU32; |
701 | break; |
702 | case LINUX_SIOCADDMULTI: |
703 | SCARG(&ia, com) = OSIOCADDMULTI32; |
704 | break; |
705 | case LINUX_SIOCDELMULTI: |
706 | SCARG(&ia, com) = OSIOCDELMULTI32; |
707 | break; |
708 | case LINUX_SIOCGIFHWADDR: |
709 | error = linux32_getifhwaddr(l, retval, SCARG(uap, fd), |
710 | SCARG_P32(uap, data)); |
711 | dosys = 0; |
712 | break; |
713 | default: |
714 | error = EINVAL; |
715 | } |
716 | |
717 | out: |
718 | fd_putfile(SCARG(uap, fd)); |
719 | |
720 | if (error == 0 && dosys) { |
721 | SCARG(&ia, fd) = SCARG(uap, fd); |
722 | SCARG(&ia, data) = SCARG(uap, data); |
723 | error = netbsd32_ioctl(curlwp, &ia, retval); |
724 | } |
725 | |
726 | return error; |
727 | } |
728 | |