linux32_socket.c revision 1.5.12.3 1 /* $NetBSD: linux32_socket.c,v 1.5.12.3 2008/06/23 04:30:54 wrstuden 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.12.3 2008/06/23 04:30:54 wrstuden 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
57 #include <sys/syscallargs.h>
58
59 #include <compat/netbsd32/netbsd32.h>
60 #include <compat/netbsd32/netbsd32_conv.h>
61 #include <compat/netbsd32/netbsd32_syscallargs.h>
62 #include <compat/sys/sockio.h>
63
64 #include <compat/linux/common/linux_types.h>
65 #include <compat/linux/common/linux_types.h>
66 #include <compat/linux/common/linux_signal.h>
67 #include <compat/linux/common/linux_machdep.h>
68 #include <compat/linux/common/linux_misc.h>
69 #include <compat/linux/common/linux_oldolduname.h>
70 #include <compat/linux/common/linux_ioctl.h>
71 #include <compat/linux/common/linux_sockio.h>
72 #include <compat/linux/linux_syscallargs.h>
73
74 #include <compat/linux32/common/linux32_types.h>
75 #include <compat/linux32/common/linux32_signal.h>
76 #include <compat/linux32/common/linux32_machdep.h>
77 #include <compat/linux32/common/linux32_sysctl.h>
78 #include <compat/linux32/common/linux32_socketcall.h>
79 #include <compat/linux32/common/linux32_ioctl.h>
80 #include <compat/linux32/linux32_syscallargs.h>
81
82 int
83 linux32_sys_socketpair(struct lwp *l, const struct linux32_sys_socketpair_args *uap, register_t *retval)
84 {
85 /* {
86 syscallarg(int) domain;
87 syscallarg(int) type;
88 syscallarg(int) protocol;
89 syscallarg(netbsd32_intp) rsv;
90 } */
91 struct linux_sys_socketpair_args ua;
92
93 NETBSD32TO64_UAP(domain);
94 NETBSD32TO64_UAP(type);
95 NETBSD32TO64_UAP(protocol);
96 NETBSD32TOP_UAP(rsv, int)
97
98 return linux_sys_socketpair(l, &ua, retval);
99 }
100
101 int
102 linux32_sys_sendto(struct lwp *l, const struct linux32_sys_sendto_args *uap, register_t *retval)
103 {
104 /* {
105 syscallarg(int) s;
106 syscallarg(netbsd32_voidp) msg;
107 syscallarg(int) len;
108 syscallarg(int) flags;
109 syscallarg(netbsd32_osockaddrp_t) to;
110 syscallarg(int) tolen;
111 } */
112 struct linux_sys_sendto_args ua;
113
114 NETBSD32TO64_UAP(s);
115 NETBSD32TOP_UAP(msg, void);
116 NETBSD32TO64_UAP(len);
117 NETBSD32TO64_UAP(flags);
118 NETBSD32TOP_UAP(to, struct osockaddr);
119 NETBSD32TO64_UAP(tolen);
120
121 return linux_sys_sendto(l, &ua, retval);
122 }
123
124
125 int
126 linux32_sys_recvfrom(struct lwp *l, const struct linux32_sys_recvfrom_args *uap, register_t *retval)
127 {
128 /* {
129 syscallarg(int) s;
130 syscallarg(netbsd32_voidp) buf;
131 syscallarg(netbsd32_size_t) len;
132 syscallarg(int) flags;
133 syscallarg(netbsd32_osockaddrp_t) from;
134 syscallarg(netbsd32_intp) fromlenaddr;
135 } */
136 struct linux_sys_recvfrom_args ua;
137
138 NETBSD32TO64_UAP(s);
139 NETBSD32TOP_UAP(buf, void);
140 NETBSD32TO64_UAP(len);
141 NETBSD32TO64_UAP(flags);
142 NETBSD32TOP_UAP(from, struct osockaddr);
143 NETBSD32TOP_UAP(fromlenaddr, unsigned int);
144
145 return linux_sys_recvfrom(l, &ua, retval);
146 }
147
148 int
149 linux32_sys_setsockopt(struct lwp *l, const struct linux32_sys_setsockopt_args *uap, register_t *retval)
150 {
151 /* {
152 syscallarg(int) s;
153 syscallarg(int) level;
154 syscallarg(int) optname;
155 syscallarg(netbsd32_voidp) optval;
156 syscallarg(int) optlen;
157 } */
158 struct linux_sys_setsockopt_args ua;
159
160 NETBSD32TO64_UAP(s);
161 NETBSD32TO64_UAP(level);
162 NETBSD32TO64_UAP(optname);
163 NETBSD32TOP_UAP(optval, void);
164 NETBSD32TO64_UAP(optlen);
165
166 return linux_sys_setsockopt(l, &ua, retval);
167 }
168
169
170 int
171 linux32_sys_getsockopt(struct lwp *l, const struct linux32_sys_getsockopt_args *uap, register_t *retval)
172 {
173 /* {
174 syscallarg(int) s;
175 syscallarg(int) level;
176 syscallarg(int) optname;
177 syscallarg(netbsd32_voidp) optval;
178 syscallarg(netbsd32_intp) optlen;
179 } */
180 struct linux_sys_getsockopt_args ua;
181
182 NETBSD32TO64_UAP(s);
183 NETBSD32TO64_UAP(level);
184 NETBSD32TO64_UAP(optname);
185 NETBSD32TOP_UAP(optval, void);
186 NETBSD32TOP_UAP(optlen, int);
187
188 return linux_sys_getsockopt(l, &ua, retval);
189 }
190
191 int
192 linux32_sys_socket(struct lwp *l, const struct linux32_sys_socket_args *uap, register_t *retval)
193 {
194 /* {
195 syscallarg(int) domain;
196 syscallarg(int) type;
197 syscallarg(int) protocol;
198 } */
199 struct linux_sys_socket_args ua;
200
201 NETBSD32TO64_UAP(domain);
202 NETBSD32TO64_UAP(type);
203 NETBSD32TO64_UAP(protocol);
204
205 return linux_sys_socket(l, &ua, retval);
206 }
207
208 int
209 linux32_sys_bind(struct lwp *l, const struct linux32_sys_bind_args *uap, register_t *retval)
210 {
211 /* {
212 syscallarg(int) s;
213 syscallarg(netbsd32_osockaddrp_t) name;
214 syscallarg(int) namelen;
215 } */
216 struct linux_sys_bind_args ua;
217
218 NETBSD32TO64_UAP(s);
219 NETBSD32TOP_UAP(name, struct osockaddr)
220 NETBSD32TO64_UAP(namelen);
221
222 return linux_sys_bind(l, &ua, retval);
223 }
224
225 int
226 linux32_sys_connect(struct lwp *l, const struct linux32_sys_connect_args *uap, register_t *retval)
227 {
228 /* {
229 syscallarg(int) s;
230 syscallarg(netbsd32_osockaddrp_t) name;
231 syscallarg(int) namelen;
232 } */
233 struct linux_sys_connect_args ua;
234
235 NETBSD32TO64_UAP(s);
236 NETBSD32TOP_UAP(name, struct osockaddr)
237 NETBSD32TO64_UAP(namelen);
238
239 #ifdef DEBUG_LINUX
240 printf("linux32_sys_connect: s = %d, name = %p, namelen = %d\n",
241 SCARG(&ua, s), SCARG(&ua, name), SCARG(&ua, namelen));
242 #endif
243
244 return linux_sys_connect(l, &ua, retval);
245 }
246
247 int
248 linux32_sys_accept(struct lwp *l, const struct linux32_sys_accept_args *uap, register_t *retval)
249 {
250 /* {
251 syscallarg(int) s;
252 syscallarg(netbsd32_osockaddrp_t) name;
253 syscallarg(netbsd32_intp) anamelen;
254 } */
255 struct linux_sys_accept_args ua;
256
257 NETBSD32TO64_UAP(s);
258 NETBSD32TOP_UAP(name, struct osockaddr)
259 NETBSD32TOP_UAP(anamelen, int);
260
261 return linux_sys_accept(l, &ua, retval);
262 }
263
264 int
265 linux32_sys_getpeername(struct lwp *l, const struct linux32_sys_getpeername_args *uap, register_t *retval)
266 {
267 /* {
268 syscallarg(int) fdes;
269 syscallarg(netbsd32_sockaddrp_t) asa;
270 syscallarg(netbsd32_intp) alen;
271 } */
272 struct linux_sys_getpeername_args ua;
273
274 NETBSD32TO64_UAP(fdes);
275 NETBSD32TOP_UAP(asa, struct sockaddr)
276 NETBSD32TOP_UAP(alen, int);
277
278 return linux_sys_getpeername(l, &ua, retval);
279 }
280
281 int
282 linux32_sys_getsockname(struct lwp *l, const struct linux32_sys_getsockname_args *uap, register_t *retval)
283 {
284 /* {
285 syscallarg(int) fdec;
286 syscallarg(netbsd32_charp) asa;
287 syscallarg(netbsd32_intp) alen;
288 } */
289 struct linux_sys_getsockname_args ua;
290
291 NETBSD32TO64_UAP(fdec);
292 NETBSD32TOP_UAP(asa, char)
293 NETBSD32TOP_UAP(alen, int);
294
295 return linux_sys_getsockname(l, &ua, retval);
296 }
297
298 int
299 linux32_sys_sendmsg(struct lwp *l, const struct linux32_sys_sendmsg_args *uap, register_t *retval)
300 {
301 /* {
302 syscallarg(int) s;
303 syscallarg(netbsd32_msghdrp_t) msg;
304 syscallarg(int) flags;
305 } */
306 struct linux_sys_sendmsg_args ua;
307
308 NETBSD32TO64_UAP(s);
309 NETBSD32TOP_UAP(msg, struct msghdr);
310 NETBSD32TO64_UAP(flags);
311
312 return linux_sys_sendmsg(l, &ua, retval);
313 }
314
315 int
316 linux32_sys_recvmsg(struct lwp *l, const struct linux32_sys_recvmsg_args *uap, register_t *retval)
317 {
318 /* {
319 syscallarg(int) s;
320 syscallarg(netbsd32_msghdrp_t) msg;
321 syscallarg(int) flags;
322 } */
323 struct linux_sys_recvmsg_args ua;
324
325 NETBSD32TO64_UAP(s);
326 NETBSD32TOP_UAP(msg, struct msghdr);
327 NETBSD32TO64_UAP(flags);
328
329 return linux_sys_recvmsg(l, &ua, retval);
330 }
331
332 int
333 linux32_sys_send(struct lwp *l, const struct linux32_sys_send_args *uap, register_t *retval)
334 {
335 /* {
336 syscallarg(int) s;
337 syscallarg(netbsd32_voidp) buf;
338 syscallarg(int) len;
339 syscallarg(int) flags;
340 } */
341 struct sys_sendto_args ua;
342
343 NETBSD32TO64_UAP(s);
344 NETBSD32TOP_UAP(buf, void);
345 NETBSD32TO64_UAP(len);
346 NETBSD32TO64_UAP(flags);
347 SCARG(&ua, to) = NULL;
348 SCARG(&ua, tolen) = 0;
349
350 return sys_sendto(l, &ua, retval);
351 }
352
353 int
354 linux32_sys_recv(struct lwp *l, const struct linux32_sys_recv_args *uap, register_t *retval)
355 {
356 /* {
357 syscallarg(int) s;
358 syscallarg(netbsd32_voidp) buf;
359 syscallarg(int) len;
360 syscallarg(int) flags;
361 } */
362 struct sys_recvfrom_args ua;
363
364 NETBSD32TO64_UAP(s);
365 NETBSD32TOP_UAP(buf, void);
366 NETBSD32TO64_UAP(len);
367 NETBSD32TO64_UAP(flags);
368 SCARG(&ua, from) = NULL;
369 SCARG(&ua, fromlenaddr) = NULL;
370
371 return sys_recvfrom(l, &ua, retval);
372 }
373
374 int
375 linux32_ioctl_socket(struct lwp *l, const struct linux32_sys_ioctl_args *uap, register_t *retval)
376 {
377 /* {
378 syscallarg(int) fd;
379 syscallarg(u_long) com;
380 syscallarg(void *) data;
381 } */
382 u_long com;
383 int error = 0, isdev = 0, dosys = 1;
384 struct netbsd32_ioctl_args ia;
385 file_t *fp;
386 struct vnode *vp;
387 int (*ioctlf)(file_t *, u_long, void *);
388 struct ioctl_pt pt;
389
390 if ((fp = fd_getfile(SCARG(uap, fd))) == NULL)
391 return (EBADF);
392
393 if (fp->f_type == DTYPE_VNODE) {
394 vp = (struct vnode *)fp->f_data;
395 isdev = vp->v_type == VCHR;
396 }
397
398 /*
399 * Don't try to interpret socket ioctl calls that are done
400 * on a device filedescriptor, just pass them through, to
401 * emulate Linux behaviour. Use PTIOCLINUX so that the
402 * device will only handle these if it's prepared to do
403 * so, to avoid unexpected things from happening.
404 */
405 if (isdev) {
406 dosys = 0;
407 ioctlf = fp->f_ops->fo_ioctl;
408 pt.com = SCARG(uap, com);
409 pt.data = (void *)NETBSD32PTR64(SCARG(uap, data));
410 error = ioctlf(fp, PTIOCLINUX, &pt);
411 /*
412 * XXX hack: if the function returns EJUSTRETURN,
413 * it has stuffed a sysctl return value in pt.data.
414 */
415 if (error == EJUSTRETURN) {
416 retval[0] = (register_t)pt.data;
417 error = 0;
418 }
419 goto out;
420 }
421
422 com = SCARG(uap, com);
423 retval[0] = 0;
424
425 switch (com) {
426 case LINUX_SIOCGIFCONF:
427 SCARG(&ia, com) = OOSIOCGIFCONF;
428 break;
429 case LINUX_SIOCGIFFLAGS:
430 SCARG(&ia, com) = OSIOCGIFFLAGS;
431 break;
432 case LINUX_SIOCSIFFLAGS:
433 SCARG(&ia, com) = OSIOCSIFFLAGS;
434 break;
435 case LINUX_SIOCGIFADDR:
436 SCARG(&ia, com) = OOSIOCGIFADDR;
437 break;
438 case LINUX_SIOCGIFDSTADDR:
439 SCARG(&ia, com) = OOSIOCGIFDSTADDR;
440 break;
441 case LINUX_SIOCGIFBRDADDR:
442 SCARG(&ia, com) = OOSIOCGIFBRDADDR;
443 break;
444 case LINUX_SIOCGIFNETMASK:
445 SCARG(&ia, com) = OOSIOCGIFNETMASK;
446 break;
447 case LINUX_SIOCADDMULTI:
448 SCARG(&ia, com) = OSIOCADDMULTI;
449 break;
450 case LINUX_SIOCDELMULTI:
451 SCARG(&ia, com) = OSIOCDELMULTI;
452 break;
453 #ifdef notyet
454 case LINUX_SIOCGIFHWADDR:
455 error = linux_getifhwaddr(l, retval, SCARG(uap, fd),
456 SCARG(uap, data));
457 dosys = 0;
458 break;
459 #endif
460 default:
461 error = EINVAL;
462 }
463
464 out:
465 fd_putfile(SCARG(uap, fd));
466
467 if (error == 0 && dosys) {
468 SCARG(&ia, fd) = SCARG(uap, fd);
469 SCARG(&ia, data) = SCARG(uap, data);
470 error = netbsd32_ioctl(curlwp, &ia, retval);
471 }
472
473 return error;
474 }
475