1 /*        $NetBSD: linux32_socket.c,v 1.32 2022/12/24 15:23:02 andvar 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.32 2022/12/24 15:23:02 andvar 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
linux32_sys_socketpair(struct lwp * l,const struct linux32_sys_socketpair_args * uap,register_t * retval)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
linux32_sys_sendto(struct lwp * l,const struct linux32_sys_sendto_args * uap,register_t * retval)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
linux32_sys_recvfrom(struct lwp * l,const struct linux32_sys_recvfrom_args * uap,register_t * retval)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
linux32_sys_setsockopt(struct lwp * l,const struct linux32_sys_setsockopt_args * uap,register_t * retval)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
linux32_sys_getsockopt(struct lwp * l,const struct linux32_sys_getsockopt_args * uap,register_t * retval)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
linux32_sys_socket(struct lwp * l,const struct linux32_sys_socket_args * uap,register_t * retval)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
linux32_sys_bind(struct lwp * l,const struct linux32_sys_bind_args * uap,register_t * retval)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
linux32_sys_connect(struct lwp * l,const struct linux32_sys_connect_args * uap,register_t * retval)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
linux32_sys_accept(struct lwp * l,const struct linux32_sys_accept_args * uap,register_t * retval)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
linux32_sys_getpeername(struct lwp * l,const struct linux32_sys_getpeername_args * uap,register_t * retval)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
linux32_sys_getsockname(struct lwp * l,const struct linux32_sys_getsockname_args * uap,register_t * retval)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
linux32_sys_sendmsg(struct lwp * l,const struct linux32_sys_sendmsg_args * uap,register_t * retval)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
linux32_sys_recvmsg(struct lwp * l,const struct linux32_sys_recvmsg_args * uap,register_t * retval)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
linux32_sys_send(struct lwp * l,const struct linux32_sys_send_args * uap,register_t * retval)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
linux32_sys_recv(struct lwp * l,const struct linux32_sys_recv_args * uap,register_t * retval)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
linux32_getifname(struct lwp * l,register_t * retval,void * data)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
linux32_getifconf(struct lwp * l,register_t * retval,void * data)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                     if (ifc.ifc_len < 0)
437                               return EINVAL;
438 
439                     space = ifc.ifc_len;
440                     ifrp = NETBSD32PTR64(ifc.ifc_req);
441           }
442           memset(&ifr, 0, sizeof(ifr));
443 
444           bound = curlwp_bind();
445           s = pserialize_read_enter();
446           IFNET_READER_FOREACH(ifp) {
447                     struct ifaddr *ifa;
448                     if_acquire(ifp, &psref);
449                     pserialize_read_exit(s);
450 
451                     (void)strncpy(ifr.ifr_name, ifp->if_xname,
452                         sizeof(ifr.ifr_name));
453                     if (ifr.ifr_name[sizeof(ifr.ifr_name) - 1] != '\0') {
454                               error = ENAMETOOLONG;
455                               goto release_exit;
456                     }
457 
458                     s = pserialize_read_enter();
459                     IFADDR_READER_FOREACH(ifa, ifp) {
460                               struct psref psref_ifa;
461                               ifa_acquire(ifa, &psref_ifa);
462                               pserialize_read_exit(s);
463 
464                               sa = ifa->ifa_addr;
465                               if (sa->sa_family != AF_INET ||
466                                   sa->sa_len > sizeof(*osa))
467                                         goto next;
468                               memcpy(&ifr.ifr_addr, sa, sa->sa_len);
469                               osa = (struct osockaddr *)&ifr.ifr_addr;
470                               osa->sa_family = sa->sa_family;
471                               if (space >= sz) {
472                                         error = copyout(&ifr, ifrp, sz);
473                                         if (error != 0) {
474                                                   ifa_release(ifa, &psref_ifa);
475                                                   goto release_exit;
476                                         }
477                                         ifrp++;
478                               }
479                               space -= sz;
480                     next:
481                               s = pserialize_read_enter();
482                               ifa_release(ifa, &psref_ifa);
483                     }
484 
485                     KASSERT(pserialize_in_read_section());
486                     if_release(ifp, &psref);
487           }
488           pserialize_read_exit(s);
489           curlwp_bindx(bound);
490 
491           if (docopy)
492                     ifc.ifc_len -= space;
493           else
494                     ifc.ifc_len = -space;
495 
496           return copyout(&ifc, data, sizeof(ifc));
497 
498 release_exit:
499           if_release(ifp, &psref);
500           curlwp_bindx(bound);
501           return error;
502 }
503 
504 int
linux32_getifhwaddr(struct lwp * l,register_t * retval,u_int fd,void * data)505 linux32_getifhwaddr(struct lwp *l, register_t *retval, u_int fd,
506     void *data)
507 {
508           struct linux32_ifreq lreq;
509           file_t *fp;
510           struct ifaddr *ifa;
511           struct ifnet *ifp;
512           struct sockaddr_dl *sadl;
513           int error, found;
514           int index, ifnum;
515           int s;
516 
517           /*
518            * We can't emulate this ioctl by calling sys_ioctl() to run
519            * SIOCGIFCONF, because the user buffer is not of the right
520            * type to take those results.  We can't use kernel buffers to
521            * receive the results, as the implementation of sys_ioctl()
522            * and ifconf() [which implements SIOCGIFCONF] use
523            * copyin()/copyout() which will fail on kernel addresses.
524            *
525            * So, we must duplicate code from sys_ioctl() and ifconf().  Ugh.
526            */
527 
528           if ((fp = fd_getfile(fd)) == NULL)
529                     return (EBADF);
530 
531           KERNEL_LOCK(1, NULL);
532 
533           if ((fp->f_flag & (FREAD | FWRITE)) == 0) {
534                     error = EBADF;
535                     goto out;
536           }
537 
538           error = copyin(data, &lreq, sizeof(lreq));
539           if (error)
540                     goto out;
541           lreq.ifr_name[LINUX32_IFNAMSIZ-1] = '\0';                   /* just in case */
542 
543           /*
544            * Try real interface name first, then fake "ethX"
545            */
546           found = 0;
547           s = pserialize_read_enter();
548           IFNET_READER_FOREACH(ifp) {
549                     if (found)
550                               break;
551                     if (strcmp(lreq.ifr_name, ifp->if_xname))
552                               /* not this interface */
553                               continue;
554                     found=1;
555                     if (IFADDR_READER_EMPTY(ifp)) {
556                               error = ENODEV;
557                               goto out;
558                     }
559                     IFADDR_READER_FOREACH(ifa, ifp) {
560                               sadl = satosdl(ifa->ifa_addr);
561                               /* only return ethernet addresses */
562                               /* XXX what about FDDI, etc. ? */
563                               if (sadl->sdl_family != AF_LINK ||
564                                   sadl->sdl_type != IFT_ETHER)
565                                         continue;
566                               memcpy(&lreq.ifr_hwaddr.sa_data, CLLADDR(sadl),
567                                      MIN(sadl->sdl_alen,
568                                            sizeof(lreq.ifr_hwaddr.sa_data)));
569                               lreq.ifr_hwaddr.sa_family =
570                                         sadl->sdl_family;
571                               pserialize_read_exit(s);
572 
573                               error = copyout(&lreq, data, sizeof(lreq));
574                               goto out;
575                     }
576           }
577           pserialize_read_exit(s);
578 
579           if (strncmp(lreq.ifr_name, "eth", 3) == 0) {
580                     for (ifnum = 0, index = 3;
581                          index < LINUX32_IFNAMSIZ && lreq.ifr_name[index] != '\0';
582                          index++) {
583                               ifnum *= 10;
584                               ifnum += lreq.ifr_name[index] - '0';
585                     }
586 
587                     error = EINVAL;                         /* in case we don't find one */
588                     s = pserialize_read_enter();
589                     IFNET_READER_FOREACH(ifp) {
590                               memcpy(lreq.ifr_name, ifp->if_xname,
591                                      MIN(LINUX32_IFNAMSIZ, IFNAMSIZ));
592                               IFADDR_READER_FOREACH(ifa, ifp) {
593                                         sadl = satosdl(ifa->ifa_addr);
594                                         /* only return ethernet addresses */
595                                         /* XXX what about FDDI, etc. ? */
596                                         if (sadl->sdl_family != AF_LINK ||
597                                             sadl->sdl_type != IFT_ETHER)
598                                                   continue;
599                                         if (ifnum--)
600                                                   /* not the requested iface */
601                                                   continue;
602                                         memcpy(&lreq.ifr_hwaddr.sa_data,
603                                                CLLADDR(sadl),
604                                                MIN(sadl->sdl_alen,
605                                                      sizeof(lreq.ifr_hwaddr.sa_data)));
606                                         lreq.ifr_hwaddr.sa_family =
607                                                   sadl->sdl_family;
608                                         pserialize_read_exit(s);
609 
610                                         error = copyout(&lreq, data, sizeof(lreq));
611                                         goto out;
612                               }
613                     }
614                     pserialize_read_exit(s);
615           } else {
616                     /* unknown interface, not even an "eth*" name */
617                     error = ENODEV;
618           }
619 
620 out:
621           KERNEL_UNLOCK_ONE(NULL);
622           fd_putfile(fd);
623           return error;
624 }
625 
626 int
linux32_ioctl_socket(struct lwp * l,const struct linux32_sys_ioctl_args * uap,register_t * retval)627 linux32_ioctl_socket(struct lwp *l, const struct linux32_sys_ioctl_args *uap, register_t *retval)
628 {
629           /* {
630                     syscallarg(int) fd;
631                     syscallarg(u_long) com;
632                     syscallarg(void *) data;
633           } */
634           u_long com;
635           int error = 0, isdev = 0, dosys = 1;
636           struct netbsd32_ioctl_args ia;
637           file_t *fp;
638           struct vnode *vp;
639           int (*ioctlf)(file_t *, u_long, void *);
640           struct ioctl_pt pt;
641 
642           if ((fp = fd_getfile(SCARG(uap, fd))) == NULL)
643                     return (EBADF);
644 
645           if (fp->f_type == DTYPE_VNODE) {
646                     vp = (struct vnode *)fp->f_data;
647                     isdev = vp->v_type == VCHR;
648           }
649 
650           /*
651            * Don't try to interpret socket ioctl calls that are done
652            * on a device filedescriptor, just pass them through, to
653            * emulate Linux behaviour. Use PTIOCLINUX so that the
654            * device will only handle these if it's prepared to do
655            * so, to avoid unexpected things from happening.
656            */
657           if (isdev) {
658                     dosys = 0;
659                     ioctlf = fp->f_ops->fo_ioctl;
660                     pt.com = SCARG(uap, com);
661                     pt.data = (void *)NETBSD32PTR64(SCARG(uap, data));
662                     error = ioctlf(fp, PTIOCLINUX, &pt);
663                     /*
664                      * XXX hack: if the function returns EJUSTRETURN,
665                      * it has stuffed a sysctl return value in pt.data.
666                      */
667                     if (error == EJUSTRETURN) {
668                               retval[0] = (register_t)pt.data;
669                               error = 0;
670                     }
671                     goto out;
672           }
673 
674           com = SCARG(uap, com);
675           retval[0] = 0;
676 
677           switch (com) {
678           case LINUX_SIOCGIFNAME:
679                     error = linux32_getifname(l, retval, SCARG_P32(uap, data));
680                     dosys = 0;
681                     break;
682           case LINUX_SIOCGIFCONF:
683                     error = linux32_getifconf(l, retval, SCARG_P32(uap, data));
684                     dosys = 0;
685                     break;
686           case LINUX_SIOCGIFFLAGS:
687                     SCARG(&ia, com) = OSIOCGIFFLAGS32;
688                     break;
689           case LINUX_SIOCSIFFLAGS:
690                     SCARG(&ia, com) = OSIOCSIFFLAGS32;
691                     break;
692           case LINUX_SIOCGIFADDR:
693                     SCARG(&ia, com) = OOSIOCGIFADDR32;
694                     break;
695           case LINUX_SIOCGIFDSTADDR:
696                     SCARG(&ia, com) = OOSIOCGIFDSTADDR32;
697                     break;
698           case LINUX_SIOCGIFBRDADDR:
699                     SCARG(&ia, com) = OOSIOCGIFBRDADDR32;
700                     break;
701           case LINUX_SIOCGIFNETMASK:
702                     SCARG(&ia, com) = OOSIOCGIFNETMASK32;
703                     break;
704           case LINUX_SIOCGIFMTU:
705                     SCARG(&ia, com) = OSIOCGIFMTU32;
706                     break;
707           case LINUX_SIOCADDMULTI:
708                     SCARG(&ia, com) = OSIOCADDMULTI32;
709                     break;
710           case LINUX_SIOCDELMULTI:
711                     SCARG(&ia, com) = OSIOCDELMULTI32;
712                     break;
713           case LINUX_SIOCGIFHWADDR:
714                     error = linux32_getifhwaddr(l, retval, SCARG(uap, fd),
715                         SCARG_P32(uap, data));
716                     dosys = 0;
717                     break;
718           default:
719                     error = EINVAL;
720           }
721 
722  out:
723           fd_putfile(SCARG(uap, fd));
724 
725           if (error == 0 && dosys) {
726                     SCARG(&ia, fd) = SCARG(uap, fd);
727                     SCARG(&ia, data) = SCARG(uap, data);
728                     error = netbsd32_ioctl(curlwp, &ia, retval);
729           }
730 
731           return error;
732 }
733