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