1 /* $Id: socket.c,v 1.6 2002/02/08 03:57:14 davem Exp $
2 * socket.c: Socket syscall emulation for Solaris 2.6+
4 * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
6 * 1999-08-19 Fixed socketpair code
7 * Jason Rappleye (rappleye@ccr.buffalo.edu)
10 #include <linux/types.h>
11 #include <linux/smp_lock.h>
13 #include <linux/slab.h>
14 #include <linux/socket.h>
15 #include <linux/file.h>
16 #include <linux/net.h>
17 #include <linux/compat.h>
18 #include <net/compat.h>
21 #include <asm/uaccess.h>
22 #include <asm/string.h>
23 #include <asm/oplib.h>
24 #include <asm/idprom.h>
28 #define SOCK_SOL_STREAM 2
29 #define SOCK_SOL_DGRAM 1
30 #define SOCK_SOL_RAW 4
31 #define SOCK_SOL_RDM 5
32 #define SOCK_SOL_SEQPACKET 6
34 #define SOL_SO_SNDLOWAT 0x1003
35 #define SOL_SO_RCVLOWAT 0x1004
36 #define SOL_SO_SNDTIMEO 0x1005
37 #define SOL_SO_RCVTIMEO 0x1006
38 #define SOL_SO_STATE 0x2000
40 #define SOL_SS_NDELAY 0x040
41 #define SOL_SS_NONBLOCK 0x080
42 #define SOL_SS_ASYNC 0x100
44 #define SO_STATE 0x000e
46 static int socket_check(int family
, int type
)
48 if (family
!= PF_UNIX
&& family
!= PF_INET
)
49 return -ESOCKTNOSUPPORT
;
51 case SOCK_SOL_STREAM
: type
= SOCK_STREAM
; break;
52 case SOCK_SOL_DGRAM
: type
= SOCK_DGRAM
; break;
53 case SOCK_SOL_RAW
: type
= SOCK_RAW
; break;
54 case SOCK_SOL_RDM
: type
= SOCK_RDM
; break;
55 case SOCK_SOL_SEQPACKET
: type
= SOCK_SEQPACKET
; break;
56 default: return -EINVAL
;
61 static int solaris_to_linux_sockopt(int optname
)
64 case SOL_SO_SNDLOWAT
: optname
= SO_SNDLOWAT
; break;
65 case SOL_SO_RCVLOWAT
: optname
= SO_RCVLOWAT
; break;
66 case SOL_SO_SNDTIMEO
: optname
= SO_SNDTIMEO
; break;
67 case SOL_SO_RCVTIMEO
: optname
= SO_RCVTIMEO
; break;
68 case SOL_SO_STATE
: optname
= SO_STATE
; break;
74 asmlinkage
int solaris_socket(int family
, int type
, int protocol
)
76 int (*sys_socket
)(int, int, int) =
77 (int (*)(int, int, int))SYS(socket
);
79 type
= socket_check (family
, type
);
80 if (type
< 0) return type
;
81 return sys_socket(family
, type
, protocol
);
84 asmlinkage
int solaris_socketpair(int *usockvec
)
86 int (*sys_socketpair
)(int, int, int, int *) =
87 (int (*)(int, int, int, int *))SYS(socketpair
);
89 /* solaris socketpair really only takes one arg at the syscall
90 * level, int * usockvec. The libs apparently take care of
91 * making sure that family==AF_UNIX and type==SOCK_STREAM. The
92 * pointer we really want ends up residing in the first (and
93 * supposedly only) argument.
96 return sys_socketpair(AF_UNIX
, SOCK_STREAM
, 0, (int *)usockvec
);
99 asmlinkage
int solaris_bind(int fd
, struct sockaddr
*addr
, int addrlen
)
101 int (*sys_bind
)(int, struct sockaddr
*, int) =
102 (int (*)(int, struct sockaddr
*, int))SUNOS(104);
104 return sys_bind(fd
, addr
, addrlen
);
107 asmlinkage
int solaris_setsockopt(int fd
, int level
, int optname
, u32 optval
, int optlen
)
109 int (*sunos_setsockopt
)(int, int, int, u32
, int) =
110 (int (*)(int, int, int, u32
, int))SUNOS(105);
112 optname
= solaris_to_linux_sockopt(optname
);
115 if (optname
== SO_STATE
)
118 return sunos_setsockopt(fd
, level
, optname
, optval
, optlen
);
121 asmlinkage
int solaris_getsockopt(int fd
, int level
, int optname
, u32 optval
, u32 optlen
)
123 int (*sunos_getsockopt
)(int, int, int, u32
, u32
) =
124 (int (*)(int, int, int, u32
, u32
))SUNOS(118);
126 optname
= solaris_to_linux_sockopt(optname
);
130 if (optname
== SO_STATE
)
131 optname
= SOL_SO_STATE
;
133 return sunos_getsockopt(fd
, level
, optname
, optval
, optlen
);
136 asmlinkage
int solaris_connect(int fd
, struct sockaddr __user
*addr
, int addrlen
)
138 int (*sys_connect
)(int, struct sockaddr __user
*, int) =
139 (int (*)(int, struct sockaddr __user
*, int))SYS(connect
);
141 return sys_connect(fd
, addr
, addrlen
);
144 asmlinkage
int solaris_accept(int fd
, struct sockaddr __user
*addr
, int __user
*addrlen
)
146 int (*sys_accept
)(int, struct sockaddr __user
*, int __user
*) =
147 (int (*)(int, struct sockaddr __user
*, int __user
*))SYS(accept
);
149 return sys_accept(fd
, addr
, addrlen
);
152 asmlinkage
int solaris_listen(int fd
, int backlog
)
154 int (*sys_listen
)(int, int) =
155 (int (*)(int, int))SUNOS(106);
157 return sys_listen(fd
, backlog
);
160 asmlinkage
int solaris_shutdown(int fd
, int how
)
162 int (*sys_shutdown
)(int, int) =
163 (int (*)(int, int))SYS(shutdown
);
165 return sys_shutdown(fd
, how
);
168 #define MSG_SOL_OOB 0x1
169 #define MSG_SOL_PEEK 0x2
170 #define MSG_SOL_DONTROUTE 0x4
171 #define MSG_SOL_EOR 0x8
172 #define MSG_SOL_CTRUNC 0x10
173 #define MSG_SOL_TRUNC 0x20
174 #define MSG_SOL_WAITALL 0x40
175 #define MSG_SOL_DONTWAIT 0x80
177 static int solaris_to_linux_msgflags(int flags
)
179 int fl
= flags
& (MSG_OOB
|MSG_PEEK
|MSG_DONTROUTE
);
181 if (flags
& MSG_SOL_EOR
) fl
|= MSG_EOR
;
182 if (flags
& MSG_SOL_CTRUNC
) fl
|= MSG_CTRUNC
;
183 if (flags
& MSG_SOL_TRUNC
) fl
|= MSG_TRUNC
;
184 if (flags
& MSG_SOL_WAITALL
) fl
|= MSG_WAITALL
;
185 if (flags
& MSG_SOL_DONTWAIT
) fl
|= MSG_DONTWAIT
;
189 static int linux_to_solaris_msgflags(int flags
)
191 int fl
= flags
& (MSG_OOB
|MSG_PEEK
|MSG_DONTROUTE
);
193 if (flags
& MSG_EOR
) fl
|= MSG_SOL_EOR
;
194 if (flags
& MSG_CTRUNC
) fl
|= MSG_SOL_CTRUNC
;
195 if (flags
& MSG_TRUNC
) fl
|= MSG_SOL_TRUNC
;
196 if (flags
& MSG_WAITALL
) fl
|= MSG_SOL_WAITALL
;
197 if (flags
& MSG_DONTWAIT
) fl
|= MSG_SOL_DONTWAIT
;
201 asmlinkage
int solaris_recvfrom(int s
, char __user
*buf
, int len
, int flags
, u32 from
, u32 fromlen
)
203 int (*sys_recvfrom
)(int, void __user
*, size_t, unsigned, struct sockaddr __user
*, int __user
*) =
204 (int (*)(int, void __user
*, size_t, unsigned, struct sockaddr __user
*, int __user
*))SYS(recvfrom
);
206 return sys_recvfrom(s
, buf
, len
, solaris_to_linux_msgflags(flags
), A(from
), A(fromlen
));
209 asmlinkage
int solaris_recv(int s
, char __user
*buf
, int len
, int flags
)
211 int (*sys_recvfrom
)(int, void __user
*, size_t, unsigned, struct sockaddr __user
*, int __user
*) =
212 (int (*)(int, void __user
*, size_t, unsigned, struct sockaddr __user
*, int __user
*))SYS(recvfrom
);
214 return sys_recvfrom(s
, buf
, len
, solaris_to_linux_msgflags(flags
), NULL
, NULL
);
217 asmlinkage
int solaris_sendto(int s
, char __user
*buf
, int len
, int flags
, u32 to
, u32 tolen
)
219 int (*sys_sendto
)(int, void __user
*, size_t, unsigned, struct sockaddr __user
*, int __user
*) =
220 (int (*)(int, void __user
*, size_t, unsigned, struct sockaddr __user
*, int __user
*))SYS(sendto
);
222 return sys_sendto(s
, buf
, len
, solaris_to_linux_msgflags(flags
), A(to
), A(tolen
));
225 asmlinkage
int solaris_send(int s
, char *buf
, int len
, int flags
)
227 int (*sys_sendto
)(int, void *, size_t, unsigned, struct sockaddr
*, int *) =
228 (int (*)(int, void *, size_t, unsigned, struct sockaddr
*, int *))SYS(sendto
);
230 return sys_sendto(s
, buf
, len
, solaris_to_linux_msgflags(flags
), NULL
, NULL
);
233 asmlinkage
int solaris_getpeername(int fd
, struct sockaddr
*addr
, int *addrlen
)
235 int (*sys_getpeername
)(int, struct sockaddr
*, int *) =
236 (int (*)(int, struct sockaddr
*, int *))SYS(getpeername
);
238 return sys_getpeername(fd
, addr
, addrlen
);
241 asmlinkage
int solaris_getsockname(int fd
, struct sockaddr
*addr
, int *addrlen
)
243 int (*sys_getsockname
)(int, struct sockaddr
*, int *) =
244 (int (*)(int, struct sockaddr
*, int *))SYS(getsockname
);
246 return sys_getsockname(fd
, addr
, addrlen
);
249 /* XXX This really belongs in some header file... -DaveM */
250 #define MAX_SOCK_ADDR 128 /* 108 for Unix domain -
251 16 for IP, 16 for IPX,
253 about 80 for AX.25 */
269 unsigned char cmsg_data
[0];
272 static inline int msghdr_from_user32_to_kern(struct msghdr
*kmsg
,
273 struct sol_nmsghdr __user
*umsg
)
275 u32 tmp1
, tmp2
, tmp3
;
278 err
= get_user(tmp1
, &umsg
->msg_name
);
279 err
|= __get_user(tmp2
, &umsg
->msg_iov
);
280 err
|= __get_user(tmp3
, &umsg
->msg_control
);
284 kmsg
->msg_name
= A(tmp1
);
285 kmsg
->msg_iov
= A(tmp2
);
286 kmsg
->msg_control
= A(tmp3
);
288 err
= get_user(kmsg
->msg_namelen
, &umsg
->msg_namelen
);
289 err
|= get_user(kmsg
->msg_controllen
, &umsg
->msg_controllen
);
290 err
|= get_user(kmsg
->msg_flags
, &umsg
->msg_flags
);
292 kmsg
->msg_flags
= solaris_to_linux_msgflags(kmsg
->msg_flags
);
297 asmlinkage
int solaris_sendmsg(int fd
, struct sol_nmsghdr __user
*user_msg
, unsigned user_flags
)
300 char address
[MAX_SOCK_ADDR
];
301 struct iovec iovstack
[UIO_FASTIOV
], *iov
= iovstack
;
302 unsigned char ctl
[sizeof(struct cmsghdr
) + 20];
303 unsigned char *ctl_buf
= ctl
;
304 struct msghdr msg_sys
;
305 int err
, ctl_len
, iov_size
, total_len
;
308 if (msghdr_from_user32_to_kern(&msg_sys
, user_msg
))
311 sock
= sockfd_lookup(fd
, &err
);
315 /* do not move before msg_sys is valid */
317 if (msg_sys
.msg_iovlen
> UIO_MAXIOV
)
320 /* Check whether to allocate the iovec area*/
322 iov_size
= msg_sys
.msg_iovlen
* sizeof(struct iovec
);
323 if (msg_sys
.msg_iovlen
> UIO_FASTIOV
) {
324 iov
= sock_kmalloc(sock
->sk
, iov_size
, GFP_KERNEL
);
329 err
= verify_compat_iovec(&msg_sys
, iov
, address
, VERIFY_READ
);
335 if (msg_sys
.msg_controllen
> INT_MAX
)
338 ctl_len
= msg_sys
.msg_controllen
;
340 struct sol_cmsghdr __user
*ucmsg
= msg_sys
.msg_control
;
341 unsigned long *kcmsg
;
345 if (ctl_len
<= sizeof(compat_size_t
))
348 if (ctl_len
> sizeof(ctl
)) {
350 ctl_buf
= kmalloc(ctl_len
, GFP_KERNEL
);
354 __get_user(cmlen
, &ucmsg
->cmsg_len
);
355 kcmsg
= (unsigned long *) ctl_buf
;
356 *kcmsg
++ = (unsigned long)cmlen
;
358 if (copy_from_user(kcmsg
, &ucmsg
->cmsg_level
,
359 ctl_len
- sizeof(compat_size_t
)))
361 msg_sys
.msg_control
= ctl_buf
;
363 msg_sys
.msg_flags
= solaris_to_linux_msgflags(user_flags
);
365 if (sock
->file
->f_flags
& O_NONBLOCK
)
366 msg_sys
.msg_flags
|= MSG_DONTWAIT
;
367 err
= sock_sendmsg(sock
, &msg_sys
, total_len
);
371 sock_kfree_s(sock
->sk
, ctl_buf
, ctl_len
);
374 sock_kfree_s(sock
->sk
, iov
, iov_size
);
381 asmlinkage
int solaris_recvmsg(int fd
, struct sol_nmsghdr __user
*user_msg
, unsigned int user_flags
)
384 struct iovec iovstack
[UIO_FASTIOV
];
385 struct iovec
*iov
= iovstack
;
386 struct msghdr msg_sys
;
387 unsigned long cmsg_ptr
;
388 int err
, iov_size
, total_len
, len
;
390 /* kernel mode address */
391 char addr
[MAX_SOCK_ADDR
];
393 /* user mode address pointers */
394 struct sockaddr __user
*uaddr
;
395 int __user
*uaddr_len
;
397 if (msghdr_from_user32_to_kern(&msg_sys
, user_msg
))
400 sock
= sockfd_lookup(fd
, &err
);
405 if (msg_sys
.msg_iovlen
> UIO_MAXIOV
)
408 /* Check whether to allocate the iovec area*/
410 iov_size
= msg_sys
.msg_iovlen
* sizeof(struct iovec
);
411 if (msg_sys
.msg_iovlen
> UIO_FASTIOV
) {
412 iov
= sock_kmalloc(sock
->sk
, iov_size
, GFP_KERNEL
);
418 * Save the user-mode address (verify_iovec will change the
419 * kernel msghdr to use the kernel address space)
422 uaddr
= (void __user
*) msg_sys
.msg_name
;
423 uaddr_len
= &user_msg
->msg_namelen
;
424 err
= verify_compat_iovec(&msg_sys
, iov
, addr
, VERIFY_WRITE
);
429 cmsg_ptr
= (unsigned long) msg_sys
.msg_control
;
430 msg_sys
.msg_flags
= MSG_CMSG_COMPAT
;
432 if (sock
->file
->f_flags
& O_NONBLOCK
)
433 user_flags
|= MSG_DONTWAIT
;
435 err
= sock_recvmsg(sock
, &msg_sys
, total_len
, user_flags
);
442 err
= move_addr_to_user(addr
, msg_sys
.msg_namelen
, uaddr
, uaddr_len
);
446 err
= __put_user(linux_to_solaris_msgflags(msg_sys
.msg_flags
), &user_msg
->msg_flags
);
449 err
= __put_user((unsigned long)msg_sys
.msg_control
- cmsg_ptr
,
450 &user_msg
->msg_controllen
);
457 sock_kfree_s(sock
->sk
, iov
, iov_size
);