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