linux32_socket.c revision 1.5.6.1 1 /* $NetBSD: linux32_socket.c,v 1.5.6.1 2008/06/29 09:33:03 mjf 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.5.6.1 2008/06/29 09:33:03 mjf 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/linux_syscallargs.h>
82
83 #include <compat/linux32/common/linux32_types.h>
84 #include <compat/linux32/common/linux32_signal.h>
85 #include <compat/linux32/common/linux32_machdep.h>
86 #include <compat/linux32/common/linux32_sysctl.h>
87 #include <compat/linux32/common/linux32_socketcall.h>
88 #include <compat/linux32/common/linux32_sockio.h>
89 #include <compat/linux32/common/linux32_ioctl.h>
90 #include <compat/linux32/linux32_syscallargs.h>
91
92 int linux32_getifhwaddr(struct lwp *, register_t *, u_int, void *);
93
94 int
95 linux32_sys_socketpair(struct lwp *l, const struct linux32_sys_socketpair_args *uap, register_t *retval)
96 {
97 /* {
98 syscallarg(int) domain;
99 syscallarg(int) type;
100 syscallarg(int) protocol;
101 syscallarg(netbsd32_intp) rsv;
102 } */
103 struct linux_sys_socketpair_args ua;
104
105 NETBSD32TO64_UAP(domain);
106 NETBSD32TO64_UAP(type);
107 NETBSD32TO64_UAP(protocol);
108 NETBSD32TOP_UAP(rsv, int)
109
110 return linux_sys_socketpair(l, &ua, retval);
111 }
112
113 int
114 linux32_sys_sendto(struct lwp *l, const struct linux32_sys_sendto_args *uap, register_t *retval)
115 {
116 /* {
117 syscallarg(int) s;
118 syscallarg(netbsd32_voidp) msg;
119 syscallarg(int) len;
120 syscallarg(int) flags;
121 syscallarg(netbsd32_osockaddrp_t) to;
122 syscallarg(int) tolen;
123 } */
124 struct linux_sys_sendto_args ua;
125
126 NETBSD32TO64_UAP(s);
127 NETBSD32TOP_UAP(msg, void);
128 NETBSD32TO64_UAP(len);
129 NETBSD32TO64_UAP(flags);
130 NETBSD32TOP_UAP(to, struct osockaddr);
131 NETBSD32TO64_UAP(tolen);
132
133 return linux_sys_sendto(l, &ua, retval);
134 }
135
136
137 int
138 linux32_sys_recvfrom(struct lwp *l, const struct linux32_sys_recvfrom_args *uap, register_t *retval)
139 {
140 /* {
141 syscallarg(int) s;
142 syscallarg(netbsd32_voidp) buf;
143 syscallarg(netbsd32_size_t) len;
144 syscallarg(int) flags;
145 syscallarg(netbsd32_osockaddrp_t) from;
146 syscallarg(netbsd32_intp) fromlenaddr;
147 } */
148 struct linux_sys_recvfrom_args ua;
149
150 NETBSD32TO64_UAP(s);
151 NETBSD32TOP_UAP(buf, void);
152 NETBSD32TO64_UAP(len);
153 NETBSD32TO64_UAP(flags);
154 NETBSD32TOP_UAP(from, struct osockaddr);
155 NETBSD32TOP_UAP(fromlenaddr, unsigned int);
156
157 return linux_sys_recvfrom(l, &ua, retval);
158 }
159
160 int
161 linux32_sys_setsockopt(struct lwp *l, const struct linux32_sys_setsockopt_args *uap, register_t *retval)
162 {
163 /* {
164 syscallarg(int) s;
165 syscallarg(int) level;
166 syscallarg(int) optname;
167 syscallarg(netbsd32_voidp) optval;
168 syscallarg(int) optlen;
169 } */
170 struct linux_sys_setsockopt_args ua;
171
172 NETBSD32TO64_UAP(s);
173 NETBSD32TO64_UAP(level);
174 NETBSD32TO64_UAP(optname);
175 NETBSD32TOP_UAP(optval, void);
176 NETBSD32TO64_UAP(optlen);
177
178 return linux_sys_setsockopt(l, &ua, retval);
179 }
180
181
182 int
183 linux32_sys_getsockopt(struct lwp *l, const struct linux32_sys_getsockopt_args *uap, register_t *retval)
184 {
185 /* {
186 syscallarg(int) s;
187 syscallarg(int) level;
188 syscallarg(int) optname;
189 syscallarg(netbsd32_voidp) optval;
190 syscallarg(netbsd32_intp) optlen;
191 } */
192 struct linux_sys_getsockopt_args ua;
193
194 NETBSD32TO64_UAP(s);
195 NETBSD32TO64_UAP(level);
196 NETBSD32TO64_UAP(optname);
197 NETBSD32TOP_UAP(optval, void);
198 NETBSD32TOP_UAP(optlen, int);
199
200 return linux_sys_getsockopt(l, &ua, retval);
201 }
202
203 int
204 linux32_sys_socket(struct lwp *l, const struct linux32_sys_socket_args *uap, register_t *retval)
205 {
206 /* {
207 syscallarg(int) domain;
208 syscallarg(int) type;
209 syscallarg(int) protocol;
210 } */
211 struct linux_sys_socket_args ua;
212
213 NETBSD32TO64_UAP(domain);
214 NETBSD32TO64_UAP(type);
215 NETBSD32TO64_UAP(protocol);
216
217 return linux_sys_socket(l, &ua, retval);
218 }
219
220 int
221 linux32_sys_bind(struct lwp *l, const struct linux32_sys_bind_args *uap, register_t *retval)
222 {
223 /* {
224 syscallarg(int) s;
225 syscallarg(netbsd32_osockaddrp_t) name;
226 syscallarg(int) namelen;
227 } */
228 struct linux_sys_bind_args ua;
229
230 NETBSD32TO64_UAP(s);
231 NETBSD32TOP_UAP(name, struct osockaddr)
232 NETBSD32TO64_UAP(namelen);
233
234 return linux_sys_bind(l, &ua, retval);
235 }
236
237 int
238 linux32_sys_connect(struct lwp *l, const struct linux32_sys_connect_args *uap, register_t *retval)
239 {
240 /* {
241 syscallarg(int) s;
242 syscallarg(netbsd32_osockaddrp_t) name;
243 syscallarg(int) namelen;
244 } */
245 struct linux_sys_connect_args ua;
246
247 NETBSD32TO64_UAP(s);
248 NETBSD32TOP_UAP(name, struct osockaddr)
249 NETBSD32TO64_UAP(namelen);
250
251 #ifdef DEBUG_LINUX
252 printf("linux32_sys_connect: s = %d, name = %p, namelen = %d\n",
253 SCARG(&ua, s), SCARG(&ua, name), SCARG(&ua, namelen));
254 #endif
255
256 return linux_sys_connect(l, &ua, retval);
257 }
258
259 int
260 linux32_sys_accept(struct lwp *l, const struct linux32_sys_accept_args *uap, register_t *retval)
261 {
262 /* {
263 syscallarg(int) s;
264 syscallarg(netbsd32_osockaddrp_t) name;
265 syscallarg(netbsd32_intp) anamelen;
266 } */
267 struct linux_sys_accept_args ua;
268
269 NETBSD32TO64_UAP(s);
270 NETBSD32TOP_UAP(name, struct osockaddr)
271 NETBSD32TOP_UAP(anamelen, int);
272
273 return linux_sys_accept(l, &ua, retval);
274 }
275
276 int
277 linux32_sys_getpeername(struct lwp *l, const struct linux32_sys_getpeername_args *uap, register_t *retval)
278 {
279 /* {
280 syscallarg(int) fdes;
281 syscallarg(netbsd32_sockaddrp_t) asa;
282 syscallarg(netbsd32_intp) alen;
283 } */
284 struct linux_sys_getpeername_args ua;
285
286 NETBSD32TO64_UAP(fdes);
287 NETBSD32TOP_UAP(asa, struct sockaddr)
288 NETBSD32TOP_UAP(alen, int);
289
290 return linux_sys_getpeername(l, &ua, retval);
291 }
292
293 int
294 linux32_sys_getsockname(struct lwp *l, const struct linux32_sys_getsockname_args *uap, register_t *retval)
295 {
296 /* {
297 syscallarg(int) fdec;
298 syscallarg(netbsd32_charp) asa;
299 syscallarg(netbsd32_intp) alen;
300 } */
301 struct linux_sys_getsockname_args ua;
302
303 NETBSD32TO64_UAP(fdec);
304 NETBSD32TOP_UAP(asa, char)
305 NETBSD32TOP_UAP(alen, int);
306
307 return linux_sys_getsockname(l, &ua, retval);
308 }
309
310 int
311 linux32_sys_sendmsg(struct lwp *l, const struct linux32_sys_sendmsg_args *uap, register_t *retval)
312 {
313 /* {
314 syscallarg(int) s;
315 syscallarg(netbsd32_msghdrp_t) msg;
316 syscallarg(int) flags;
317 } */
318 struct linux_sys_sendmsg_args ua;
319
320 NETBSD32TO64_UAP(s);
321 NETBSD32TOP_UAP(msg, struct msghdr);
322 NETBSD32TO64_UAP(flags);
323
324 return linux_sys_sendmsg(l, &ua, retval);
325 }
326
327 int
328 linux32_sys_recvmsg(struct lwp *l, const struct linux32_sys_recvmsg_args *uap, register_t *retval)
329 {
330 /* {
331 syscallarg(int) s;
332 syscallarg(netbsd32_msghdrp_t) msg;
333 syscallarg(int) flags;
334 } */
335 struct linux_sys_recvmsg_args ua;
336
337 NETBSD32TO64_UAP(s);
338 NETBSD32TOP_UAP(msg, struct msghdr);
339 NETBSD32TO64_UAP(flags);
340
341 return linux_sys_recvmsg(l, &ua, retval);
342 }
343
344 int
345 linux32_sys_send(struct lwp *l, const struct linux32_sys_send_args *uap, register_t *retval)
346 {
347 /* {
348 syscallarg(int) s;
349 syscallarg(netbsd32_voidp) buf;
350 syscallarg(int) len;
351 syscallarg(int) flags;
352 } */
353 struct sys_sendto_args ua;
354
355 NETBSD32TO64_UAP(s);
356 NETBSD32TOP_UAP(buf, void);
357 NETBSD32TO64_UAP(len);
358 NETBSD32TO64_UAP(flags);
359 SCARG(&ua, to) = NULL;
360 SCARG(&ua, tolen) = 0;
361
362 return sys_sendto(l, &ua, retval);
363 }
364
365 int
366 linux32_sys_recv(struct lwp *l, const struct linux32_sys_recv_args *uap, register_t *retval)
367 {
368 /* {
369 syscallarg(int) s;
370 syscallarg(netbsd32_voidp) buf;
371 syscallarg(int) len;
372 syscallarg(int) flags;
373 } */
374 struct sys_recvfrom_args ua;
375
376 NETBSD32TO64_UAP(s);
377 NETBSD32TOP_UAP(buf, void);
378 NETBSD32TO64_UAP(len);
379 NETBSD32TO64_UAP(flags);
380 SCARG(&ua, from) = NULL;
381 SCARG(&ua, fromlenaddr) = NULL;
382
383 return sys_recvfrom(l, &ua, retval);
384 }
385
386 int
387 linux32_getifhwaddr(struct lwp *l, register_t *retval, u_int fd,
388 void *data)
389 {
390 struct linux32_ifreq lreq;
391 file_t *fp;
392 struct ifaddr *ifa;
393 struct ifnet *ifp;
394 struct sockaddr_dl *sadl;
395 int error, found;
396 int index, ifnum;
397
398 /*
399 * We can't emulate this ioctl by calling sys_ioctl() to run
400 * SIOCGIFCONF, because the user buffer is not of the right
401 * type to take those results. We can't use kernel buffers to
402 * receive the results, as the implementation of sys_ioctl()
403 * and ifconf() [which implements SIOCGIFCONF] use
404 * copyin()/copyout() which will fail on kernel addresses.
405 *
406 * So, we must duplicate code from sys_ioctl() and ifconf(). Ugh.
407 */
408
409 if ((fp = fd_getfile(fd)) == NULL)
410 return (EBADF);
411
412 KERNEL_LOCK(1, NULL);
413
414 if ((fp->f_flag & (FREAD | FWRITE)) == 0) {
415 error = EBADF;
416 goto out;
417 }
418
419 error = copyin(data, &lreq, sizeof(lreq));
420 if (error)
421 goto out;
422 lreq.ifr_name[LINUX32_IFNAMSIZ-1] = '\0'; /* just in case */
423
424 /*
425 * Try real interface name first, then fake "ethX"
426 */
427 found = 0;
428 IFNET_FOREACH(ifp) {
429 if (found)
430 break;
431 if (strcmp(lreq.ifr_name, ifp->if_xname))
432 /* not this interface */
433 continue;
434 found=1;
435 if (IFADDR_EMPTY(ifp)) {
436 error = ENODEV;
437 goto out;
438 }
439 IFADDR_FOREACH(ifa, ifp) {
440 sadl = satosdl(ifa->ifa_addr);
441 /* only return ethernet addresses */
442 /* XXX what about FDDI, etc. ? */
443 if (sadl->sdl_family != AF_LINK ||
444 sadl->sdl_type != IFT_ETHER)
445 continue;
446 memcpy(&lreq.ifr_hwaddr.sa_data, CLLADDR(sadl),
447 MIN(sadl->sdl_alen,
448 sizeof(lreq.ifr_hwaddr.sa_data)));
449 lreq.ifr_hwaddr.sa_family =
450 sadl->sdl_family;
451 error = copyout(&lreq, data, sizeof(lreq));
452 goto out;
453 }
454 }
455
456 if (strncmp(lreq.ifr_name, "eth", 3) == 0) {
457 for (ifnum = 0, index = 3;
458 lreq.ifr_name[index] != '\0' && index < LINUX32_IFNAMSIZ;
459 index++) {
460 ifnum *= 10;
461 ifnum += lreq.ifr_name[index] - '0';
462 }
463
464 error = EINVAL; /* in case we don't find one */
465 found = 0;
466 IFNET_FOREACH(ifp) {
467 if (found)
468 break;
469 memcpy(lreq.ifr_name, ifp->if_xname,
470 MIN(LINUX32_IFNAMSIZ, IFNAMSIZ));
471 IFADDR_FOREACH(ifa, ifp) {
472 sadl = satosdl(ifa->ifa_addr);
473 /* only return ethernet addresses */
474 /* XXX what about FDDI, etc. ? */
475 if (sadl->sdl_family != AF_LINK ||
476 sadl->sdl_type != IFT_ETHER)
477 continue;
478 if (ifnum--)
479 /* not the reqested iface */
480 continue;
481 memcpy(&lreq.ifr_hwaddr.sa_data,
482 CLLADDR(sadl),
483 MIN(sadl->sdl_alen,
484 sizeof(lreq.ifr_hwaddr.sa_data)));
485 lreq.ifr_hwaddr.sa_family =
486 sadl->sdl_family;
487 error = copyout(&lreq, data, sizeof(lreq));
488 found = 1;
489 break;
490 }
491 }
492 } else {
493 /* unknown interface, not even an "eth*" name */
494 error = ENODEV;
495 }
496
497 out:
498 KERNEL_UNLOCK_ONE(NULL);
499 fd_putfile(fd);
500 return error;
501 }
502
503 int
504 linux32_ioctl_socket(struct lwp *l, const struct linux32_sys_ioctl_args *uap, register_t *retval)
505 {
506 /* {
507 syscallarg(int) fd;
508 syscallarg(u_long) com;
509 syscallarg(void *) data;
510 } */
511 u_long com;
512 int error = 0, isdev = 0, dosys = 1;
513 struct netbsd32_ioctl_args ia;
514 file_t *fp;
515 struct vnode *vp;
516 int (*ioctlf)(file_t *, u_long, void *);
517 struct ioctl_pt pt;
518
519 if ((fp = fd_getfile(SCARG(uap, fd))) == NULL)
520 return (EBADF);
521
522 if (fp->f_type == DTYPE_VNODE) {
523 vp = (struct vnode *)fp->f_data;
524 isdev = vp->v_type == VCHR;
525 }
526
527 /*
528 * Don't try to interpret socket ioctl calls that are done
529 * on a device filedescriptor, just pass them through, to
530 * emulate Linux behaviour. Use PTIOCLINUX so that the
531 * device will only handle these if it's prepared to do
532 * so, to avoid unexpected things from happening.
533 */
534 if (isdev) {
535 dosys = 0;
536 ioctlf = fp->f_ops->fo_ioctl;
537 pt.com = SCARG(uap, com);
538 pt.data = (void *)NETBSD32PTR64(SCARG(uap, data));
539 error = ioctlf(fp, PTIOCLINUX, &pt);
540 /*
541 * XXX hack: if the function returns EJUSTRETURN,
542 * it has stuffed a sysctl return value in pt.data.
543 */
544 if (error == EJUSTRETURN) {
545 retval[0] = (register_t)pt.data;
546 error = 0;
547 }
548 goto out;
549 }
550
551 com = SCARG(uap, com);
552 retval[0] = 0;
553
554 switch (com) {
555 case LINUX_SIOCGIFCONF:
556 SCARG(&ia, com) = OOSIOCGIFCONF32;
557 break;
558 case LINUX_SIOCGIFFLAGS:
559 SCARG(&ia, com) = OSIOCGIFFLAGS;
560 break;
561 case LINUX_SIOCSIFFLAGS:
562 SCARG(&ia, com) = OSIOCSIFFLAGS;
563 break;
564 case LINUX_SIOCGIFADDR:
565 SCARG(&ia, com) = OOSIOCGIFADDR;
566 break;
567 case LINUX_SIOCGIFDSTADDR:
568 SCARG(&ia, com) = OOSIOCGIFDSTADDR;
569 break;
570 case LINUX_SIOCGIFBRDADDR:
571 SCARG(&ia, com) = OOSIOCGIFBRDADDR;
572 break;
573 case LINUX_SIOCGIFNETMASK:
574 SCARG(&ia, com) = OOSIOCGIFNETMASK;
575 break;
576 case LINUX_SIOCADDMULTI:
577 SCARG(&ia, com) = OSIOCADDMULTI;
578 break;
579 case LINUX_SIOCDELMULTI:
580 SCARG(&ia, com) = OSIOCDELMULTI;
581 break;
582 case LINUX_SIOCGIFHWADDR:
583 error = linux32_getifhwaddr(l, retval, SCARG(uap, fd),
584 SCARG_P32(uap, data));
585 dosys = 0;
586 break;
587 default:
588 error = EINVAL;
589 }
590
591 out:
592 fd_putfile(SCARG(uap, fd));
593
594 if (error == 0 && dosys) {
595 SCARG(&ia, fd) = SCARG(uap, fd);
596 SCARG(&ia, data) = SCARG(uap, data);
597 error = netbsd32_ioctl(curlwp, &ia, retval);
598 }
599
600 return error;
601 }
602