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