xref: /freebsd/sys/compat/linux/linux_socket.c (revision e627b39baccd1ec9129690167cf5e6d860509655)
1 /*-
2  * Copyright (c) 1995 S�ren Schmidt
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer
10  *    in this position and unchanged.
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. The name of the author may not be used to endorse or promote products
15  *    derived from this software withough specific prior written permission
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  *  $Id: linux_socket.c,v 1.3 1995/12/15 03:06:57 peter Exp $
29  */
30 
31 /* XXX we use functions that might not exist. */
32 #define	COMPAT_43	1
33 
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/sysproto.h>
37 #include <sys/proc.h>
38 #include <sys/socket.h>
39 #include <sys/socketvar.h>
40 
41 #include <netinet/in.h>
42 
43 #include <i386/linux/linux.h>
44 #include <i386/linux/linux_proto.h>
45 
46 static int
47 linux_to_bsd_domain(int domain)
48 {
49     switch (domain) {
50     case LINUX_AF_UNSPEC:
51 	return AF_UNSPEC;
52     case LINUX_AF_UNIX:
53 	return AF_LOCAL;
54     case LINUX_AF_INET:
55 	return AF_INET;
56     case LINUX_AF_AX25:
57 	return AF_CCITT;
58     case LINUX_AF_IPX:
59 	return AF_IPX;
60     case LINUX_AF_APPLETALK:
61 	return AF_APPLETALK;
62     default:
63 	return -1;
64     }
65 }
66 
67 static int
68 linux_to_bsd_sockopt_level(int level)
69 {
70     switch (level) {
71     case LINUX_SOL_SOCKET:
72 	return SOL_SOCKET;
73     default:
74 	return level;
75     }
76 }
77 
78 static int linux_to_bsd_ip_sockopt(int opt)
79 {
80     switch (opt) {
81     case LINUX_IP_TOS:
82 	return IP_TOS;
83     case LINUX_IP_TTL:
84 	return IP_TTL;
85     default:
86 	return -1;
87     }
88 }
89 
90 static int
91 linux_to_bsd_so_sockopt(int opt)
92 {
93     switch (opt) {
94     case LINUX_SO_DEBUG:
95 	return SO_DEBUG;
96     case LINUX_SO_REUSEADDR:
97 	return SO_REUSEADDR;
98     case LINUX_SO_TYPE:
99 	return SO_TYPE;
100     case LINUX_SO_ERROR:
101 	return SO_ERROR;
102     case LINUX_SO_DONTROUTE:
103 	return SO_DONTROUTE;
104     case LINUX_SO_BROADCAST:
105 	return SO_BROADCAST;
106     case LINUX_SO_SNDBUF:
107 	return SO_SNDBUF;
108     case LINUX_SO_RCVBUF:
109 	return SO_RCVBUF;
110     case LINUX_SO_KEEPALIVE:
111 	return SO_KEEPALIVE;
112     case LINUX_SO_OOBINLINE:
113 	return SO_OOBINLINE;
114     case LINUX_SO_LINGER:
115 	return SO_LINGER;
116     case LINUX_SO_PRIORITY:
117     case LINUX_SO_NO_CHECK:
118     default:
119 	return -1;
120     }
121 }
122 
123 struct linux_socket_args {
124     int domain;
125     int type;
126     int protocol;
127 };
128 
129 static int
130 linux_socket(struct proc *p, struct linux_socket_args *args, int *retval)
131 {
132     struct linux_socket_args linux_args;
133     struct socket_args /* {
134 	int domain;
135 	int type;
136 	int protocol;
137     } */ bsd_args;
138     int error;
139 
140     if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
141 	return error;
142     bsd_args.protocol = linux_args.protocol;
143     bsd_args.type = linux_args.type;
144     bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
145     if (bsd_args.domain == -1)
146 	return EINVAL;
147     return socket(p, &bsd_args, retval);
148 }
149 
150 struct linux_bind_args {
151     int s;
152     struct sockaddr *name;
153     int namelen;
154 };
155 
156 static int
157 linux_bind(struct proc *p, struct linux_bind_args *args, int *retval)
158 {
159     struct linux_bind_args linux_args;
160     struct bind_args /* {
161 	int s;
162 	caddr_t name;
163 	int namelen;
164     } */ bsd_args;
165     int error;
166 
167     if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
168 	return error;
169     bsd_args.s = linux_args.s;
170     bsd_args.name = (caddr_t)linux_args.name;
171     bsd_args.namelen = linux_args.namelen;
172     return bind(p, &bsd_args, retval);
173 }
174 
175 struct linux_connect_args {
176     int s;
177     struct sockaddr * name;
178     int namelen;
179 };
180 
181 static int
182 linux_connect(struct proc *p, struct linux_connect_args *args, int *retval)
183 {
184     struct linux_connect_args linux_args;
185     struct connect_args /* {
186 	int s;
187 	caddr_t name;
188 	int namelen;
189     } */ bsd_args;
190     int error;
191 
192     if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
193 	return error;
194     bsd_args.s = linux_args.s;
195     bsd_args.name = (caddr_t)linux_args.name;
196     bsd_args.namelen = linux_args.namelen;
197     return connect(p, &bsd_args, retval);
198 }
199 
200 struct linux_listen_args {
201     int s;
202     int backlog;
203 };
204 
205 static int
206 linux_listen(struct proc *p, struct linux_listen_args *args, int *retval)
207 {
208     struct linux_listen_args linux_args;
209     struct listen_args /* {
210 	int s;
211 	int backlog;
212     } */ bsd_args;
213     int error;
214 
215     if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
216 	return error;
217     bsd_args.s = linux_args.s;
218     bsd_args.backlog = linux_args.backlog;
219     return listen(p, &bsd_args, retval);
220 }
221 
222 struct linux_accept_args {
223     int s;
224     struct sockaddr *addr;
225     int *namelen;
226 };
227 
228 static int
229 linux_accept(struct proc *p, struct linux_accept_args *args, int *retval)
230 {
231     struct linux_accept_args linux_args;
232     struct accept_args /* {
233 	int s;
234 	caddr_t name;
235 	int *anamelen;
236     } */ bsd_args;
237     int error;
238 
239     if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
240 	return error;
241     bsd_args.s = linux_args.s;
242     bsd_args.name = (caddr_t)linux_args.addr;
243     bsd_args.anamelen = linux_args.namelen;
244     return oaccept(p, &bsd_args, retval);
245 }
246 
247 struct linux_getsockname_args {
248     int s;
249     struct sockaddr *addr;
250     int *namelen;
251 };
252 
253 static int
254 linux_getsockname(struct proc *p, struct linux_getsockname_args *args, int *retval)
255 {
256     struct linux_getsockname_args linux_args;
257     struct getsockname_args /* {
258 	int fdes;
259 	caddr_t asa;
260 	int *alen;
261     } */ bsd_args;
262     int error;
263 
264     if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
265 	return error;
266     bsd_args.fdes = linux_args.s;
267     bsd_args.asa = (caddr_t) linux_args.addr;
268     bsd_args.alen = linux_args.namelen;
269     return ogetsockname(p, &bsd_args, retval);
270 }
271 
272 struct linux_getpeername_args {
273     int s;
274     struct sockaddr *addr;
275     int *namelen;
276 };
277 
278 static int
279 linux_getpeername(struct proc *p, struct linux_getpeername_args *args, int *retval)
280 {
281     struct linux_getpeername_args linux_args;
282     struct ogetpeername_args /* {
283 	int fdes;
284 	caddr_t asa;
285 	int *alen;
286     } */ bsd_args;
287     int error;
288 
289     if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
290 	return error;
291     bsd_args.fdes = linux_args.s;
292     bsd_args.asa = (caddr_t) linux_args.addr;
293     bsd_args.alen = linux_args.namelen;
294     return ogetpeername(p, &bsd_args, retval);
295 }
296 
297 struct linux_socketpair_args {
298     int domain;
299     int type;
300     int protocol;
301     int *rsv;
302 };
303 
304 static int
305 linux_socketpair(struct proc *p, struct linux_socketpair_args *args, int *retval)
306 {
307     struct linux_socketpair_args linux_args;
308     struct socketpair_args /* {
309 	int domain;
310 	int type;
311 	int protocol;
312 	int *rsv;
313     } */ bsd_args;
314     int error;
315 
316     if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
317 	return error;
318     bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
319     if (bsd_args.domain == -1)
320 	return EINVAL;
321     bsd_args.type = linux_args.type;
322     bsd_args.protocol = linux_args.protocol;
323     bsd_args.rsv = linux_args.rsv;
324     return socketpair(p, &bsd_args, retval);
325 }
326 
327 struct linux_send_args {
328     int s;
329     void *msg;
330     int len;
331     int flags;
332 };
333 
334 static int
335 linux_send(struct proc *p, struct linux_send_args *args, int *retval)
336 {
337     struct linux_send_args linux_args;
338     struct osend_args /* {
339 	int s;
340 	caddr_t buf;
341 	int len;
342 	int flags;
343     } */ bsd_args;
344     int error;
345 
346     if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
347 	return error;
348     bsd_args.s = linux_args.s;
349     bsd_args.buf = linux_args.msg;
350     bsd_args.len = linux_args.len;
351     bsd_args.flags = linux_args.flags;
352     return osend(p, &bsd_args, retval);
353 }
354 
355 struct linux_recv_args {
356     int s;
357     void *msg;
358     int len;
359     int flags;
360 };
361 
362 static int
363 linux_recv(struct proc *p, struct linux_recv_args *args, int *retval)
364 {
365     struct linux_recv_args linux_args;
366     struct orecv_args /* {
367 	int s;
368 	caddr_t buf;
369 	int len;
370 	int flags;
371     } */ bsd_args;
372     int error;
373 
374     if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
375 	return error;
376     bsd_args.s = linux_args.s;
377     bsd_args.buf = linux_args.msg;
378     bsd_args.len = linux_args.len;
379     bsd_args.flags = linux_args.flags;
380     return orecv(p, &bsd_args, retval);
381 }
382 
383 struct linux_sendto_args {
384     int s;
385     void *msg;
386     int len;
387     int flags;
388     caddr_t to;
389     int tolen;
390 };
391 
392 static int
393 linux_sendto(struct proc *p, struct linux_sendto_args *args, int *retval)
394 {
395     struct linux_sendto_args linux_args;
396     struct sendto_args /* {
397 	int s;
398 	caddr_t buf;
399 	size_t len;
400 	int flags;
401 	caddr_t to;
402 	int tolen;
403     } */ bsd_args;
404     int error;
405 
406     if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
407 	return error;
408     bsd_args.s = linux_args.s;
409     bsd_args.buf = linux_args.msg;
410     bsd_args.len = linux_args.len;
411     bsd_args.flags = linux_args.flags;
412     bsd_args.to = linux_args.to;
413     bsd_args.tolen = linux_args.tolen;
414     return sendto(p, &bsd_args, retval);
415 }
416 
417 struct linux_recvfrom_args {
418     int s;
419     void *buf;
420     int len;
421     int flags;
422     caddr_t from;
423     int *fromlen;
424 };
425 
426 static int
427 linux_recvfrom(struct proc *p, struct linux_recvfrom_args *args, int *retval)
428 {
429     struct linux_recvfrom_args linux_args;
430     struct recvfrom_args /* {
431 	int s;
432 	caddr_t buf;
433 	size_t len;
434 	int flags;
435 	caddr_t from;
436 	int *fromlenaddr;
437     } */ bsd_args;
438     int error;
439 
440     if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
441 	return error;
442     bsd_args.s = linux_args.s;
443     bsd_args.buf = linux_args.buf;
444     bsd_args.len = linux_args.len;
445     bsd_args.flags = linux_args.flags;
446     bsd_args.from = linux_args.from;
447     bsd_args.fromlenaddr = linux_args.fromlen;
448     return orecvfrom(p, &bsd_args, retval);
449 }
450 
451 struct linux_shutdown_args {
452     int s;
453     int how;
454 };
455 
456 static int
457 linux_shutdown(struct proc *p, struct linux_shutdown_args *args, int *retval)
458 {
459     struct linux_shutdown_args linux_args;
460     struct shutdown_args /* {
461 	int s;
462 	int how;
463     } */ bsd_args;
464     int error;
465 
466     if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
467 	return error;
468     bsd_args.s = linux_args.s;
469     bsd_args.how = linux_args.how;
470     return shutdown(p, &bsd_args, retval);
471 }
472 
473 struct linux_setsockopt_args {
474     int s;
475     int level;
476     int optname;
477     void *optval;
478     int optlen;
479 };
480 
481 static int
482 linux_setsockopt(struct proc *p, struct linux_setsockopt_args *args, int *retval)
483 {
484     struct linux_setsockopt_args linux_args;
485     struct setsockopt_args /* {
486 	int s;
487 	int level;
488 	int name;
489 	caddr_t val;
490 	int valsize;
491     } */ bsd_args;
492     int error, name;
493 
494     if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
495 	return error;
496     bsd_args.s = linux_args.s;
497     bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
498     switch (bsd_args.level) {
499     case SOL_SOCKET:
500 	name = linux_to_bsd_so_sockopt(linux_args.optname);
501 	break;
502     case IPPROTO_IP:
503 	name = linux_to_bsd_ip_sockopt(linux_args.optname);
504 	break;
505     default:
506 	return EINVAL;
507     }
508     if (name == -1)
509 	return EINVAL;
510     bsd_args.name = name;
511     bsd_args.val = linux_args.optval;
512     bsd_args.valsize = linux_args.optlen;
513     return setsockopt(p, &bsd_args, retval);
514 }
515 
516 struct linux_getsockopt_args {
517     int s;
518     int level;
519     int optname;
520     void *optval;
521     int *optlen;
522 };
523 
524 static int
525 linux_getsockopt(struct proc *p, struct linux_getsockopt_args *args, int *retval)
526 {
527     struct linux_getsockopt_args linux_args;
528     struct getsockopt_args /* {
529 	int s;
530 	int level;
531 	int name;
532 	caddr_t val;
533 	int *avalsize;
534     } */ bsd_args;
535     int error, name;
536 
537     if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
538 	return error;
539     bsd_args.s = linux_args.s;
540     bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
541     switch (bsd_args.level) {
542     case SOL_SOCKET:
543 	name = linux_to_bsd_so_sockopt(linux_args.optname);
544 	break;
545     case IPPROTO_IP:
546 	name = linux_to_bsd_ip_sockopt(linux_args.optname);
547 	break;
548     default:
549 	return EINVAL;
550     }
551     if (name == -1)
552 	return EINVAL;
553     bsd_args.val = linux_args.optval;
554     bsd_args.avalsize = linux_args.optlen;
555     return getsockopt(p, &bsd_args, retval);
556 }
557 
558 int
559 linux_socketcall(struct proc *p, struct linux_socketcall_args *args,int *retval)
560 {
561     switch (args->what) {
562     case LINUX_SOCKET:
563 	return linux_socket(p, args->args, retval);
564     case LINUX_BIND:
565 	return linux_bind(p, args->args, retval);
566     case LINUX_CONNECT:
567 	return linux_connect(p, args->args, retval);
568     case LINUX_LISTEN:
569 	return linux_listen(p, args->args, retval);
570     case LINUX_ACCEPT:
571 	return linux_accept(p, args->args, retval);
572     case LINUX_GETSOCKNAME:
573 	return linux_getsockname(p, args->args, retval);
574     case LINUX_GETPEERNAME:
575 	return linux_getpeername(p, args->args, retval);
576     case LINUX_SOCKETPAIR:
577 	return linux_socketpair(p, args->args, retval);
578     case LINUX_SEND:
579 	return linux_send(p, args->args, retval);
580     case LINUX_RECV:
581 	return linux_recv(p, args->args, retval);
582     case LINUX_SENDTO:
583 	return linux_sendto(p, args->args, retval);
584     case LINUX_RECVFROM:
585 	return linux_recvfrom(p, args->args, retval);
586     case LINUX_SHUTDOWN:
587 	return linux_shutdown(p, args->args, retval);
588     case LINUX_SETSOCKOPT:
589 	return linux_setsockopt(p, args->args, retval);
590     case LINUX_GETSOCKOPT:
591 	return linux_getsockopt(p, args->args, retval);
592     default:
593 	uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what);
594 	return ENOSYS;
595     }
596 }
597