diff options
author | iwasaki <iwasaki@FreeBSD.org> | 2003-10-11 15:08:32 +0000 |
---|---|---|
committer | iwasaki <iwasaki@FreeBSD.org> | 2003-10-11 15:08:32 +0000 |
commit | 324480cbaf22f812dbbff8d773d2f51c15a59e1d (patch) | |
tree | 838ecf698f233895709cc02db410ed0624a7a772 /sys/compat/linux/linux_socket.c | |
parent | 8f0a204f9bab012d324a4ca5a65811b0360ec4f5 (diff) | |
download | FreeBSD-src-324480cbaf22f812dbbff8d773d2f51c15a59e1d.zip FreeBSD-src-324480cbaf22f812dbbff8d773d2f51c15a59e1d.tar.gz |
Fix some problems in linux_sendmsg() and linux_recvmsg().
- Allocate storage for uap->msg always because it is copyin()'ed in
native sendmsg().
- Convert sockopt level from Linux to FreeBSD after native recvmsg() calling.
- Some cleanups.
Tested with: Oracle 9i shared server connection mode.
MFC after: 1 week
Diffstat (limited to 'sys/compat/linux/linux_socket.c')
-rw-r--r-- | sys/compat/linux/linux_socket.c | 74 |
1 files changed, 38 insertions, 36 deletions
diff --git a/sys/compat/linux/linux_socket.c b/sys/compat/linux/linux_socket.c index a8d8128..bf9d217 100644 --- a/sys/compat/linux/linux_socket.c +++ b/sys/compat/linux/linux_socket.c @@ -225,6 +225,17 @@ linux_to_bsd_sockopt_level(int level) } static int +bsd_to_linux_sockopt_level(int level) +{ + + switch (level) { + case SOL_SOCKET: + return (LINUX_SOL_SOCKET); + } + return (level); +} + +static int linux_to_bsd_ip_sockopt(int opt) { @@ -995,9 +1006,9 @@ linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args) } */ bsd_args; struct msghdr msg; struct msghdr *nmsg = NULL; + struct cmsghdr *cmsg; int error; - int level; - caddr_t control; + caddr_t sg; if ((error = copyin(args, &linux_args, sizeof(linux_args)))) return (error); @@ -1006,54 +1017,39 @@ linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args) if (error) return (error); - if (msg.msg_name) { - struct sockaddr *sa; - caddr_t sg = stackgap_init(); + sg = stackgap_init(); + nmsg = (struct msghdr *)stackgap_alloc(&sg, sizeof(struct msghdr)); + if (nmsg == NULL) + return (ENOMEM); - nmsg = (struct msghdr *) stackgap_alloc(&sg, - sizeof(struct msghdr)); - if (!nmsg) - return (ENOMEM); + bcopy(&msg, nmsg, sizeof(struct msghdr)); + + if (msg.msg_name != NULL) { + struct sockaddr *sa; error = linux_sa_get(&sg, &sa, (struct osockaddr *) msg.msg_name, &msg.msg_namelen); if (error) return (error); - msg.msg_name = (struct sockaddr *) sa; - error = copyout(&msg, nmsg, sizeof(struct msghdr)); - if (error) - return (error); + nmsg->msg_name = sa; } - error = copyin(&linux_args.msg->msg_control, &control, - sizeof(caddr_t)); - if (error) - return (error); - - if (control == NULL) - goto done; + if (msg.msg_control != NULL) { + nmsg->msg_control = (struct cmsghdr *)stackgap_alloc(&sg, + msg.msg_controllen); + if (nmsg->msg_control == NULL) + return (ENOMEM); - error = copyin(&((struct cmsghdr*)control)->cmsg_level, &level, - sizeof(int)); - if (error) - return (error); + bcopy(msg.msg_control, nmsg->msg_control, msg.msg_controllen); + cmsg = (struct cmsghdr*)nmsg->msg_control; - if (level == 1) { - /* - * Linux thinks that SOL_SOCKET is 1; we know - * that it's really 0xffff, of course. - */ - level = SOL_SOCKET; - error = copyout(&level, - &((struct cmsghdr *)control)->cmsg_level, sizeof(int)); - if (error) - return (error); + cmsg->cmsg_level = linux_to_bsd_sockopt_level(cmsg->cmsg_level); } -done: + bsd_args.s = linux_args.s; bsd_args.msg = (caddr_t)nmsg; - bsd_args.flags = linux_args.flags; + bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags); return (sendmsg(td, &bsd_args)); } @@ -1073,6 +1069,7 @@ linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args) int flags; } */ bsd_args; struct msghdr msg; + struct cmsghdr *cmsg; int error; if ((error = copyin(args, &linux_args, sizeof(linux_args)))) @@ -1085,6 +1082,11 @@ linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args) if (error) return (error); + if (bsd_args.msg->msg_control != NULL) { + cmsg = (struct cmsghdr*)bsd_args.msg->msg_control; + cmsg->cmsg_level = bsd_to_linux_sockopt_level(cmsg->cmsg_level); + } + error = copyin(linux_args.msg, &msg, sizeof(msg)); if (error) return (error); |