Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F136474935
D20157.id57059.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
22 KB
Referenced Files
None
Subscribers
None
D20157.id57059.diff
View Options
Index: sys/compat/linux/linux.h
===================================================================
--- sys/compat/linux/linux.h
+++ sys/compat/linux/linux.h
@@ -46,6 +46,17 @@
#define LINUX_ARPHRD_ETHER 1
#define LINUX_ARPHRD_LOOPBACK 772
+/*
+ * Supported address families
+ */
+#define LINUX_AF_UNSPEC 0
+#define LINUX_AF_UNIX 1
+#define LINUX_AF_INET 2
+#define LINUX_AF_AX25 3
+#define LINUX_AF_IPX 4
+#define LINUX_AF_APPLETALK 5
+#define LINUX_AF_INET6 10
+
/*
* net device flags
*/
Index: sys/compat/linux/linux.c
===================================================================
--- sys/compat/linux/linux.c
+++ sys/compat/linux/linux.c
@@ -32,14 +32,19 @@
#include <sys/ctype.h>
#include <sys/jail.h>
#include <sys/lock.h>
+#include <sys/malloc.h>
#include <sys/signalvar.h>
#include <sys/socket.h>
+#include <sys/socketvar.h>
#include <net/if.h>
#include <net/if_var.h>
#include <net/if_dl.h>
#include <net/if_types.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+
#include <compat/linux/linux.h>
#include <compat/linux/linux_common.h>
@@ -323,3 +328,193 @@
return (ENOENT);
}
+
+int
+linux_to_bsd_domain(int domain)
+{
+
+ switch (domain) {
+ case LINUX_AF_UNSPEC:
+ return (AF_UNSPEC);
+ case LINUX_AF_UNIX:
+ return (AF_LOCAL);
+ case LINUX_AF_INET:
+ return (AF_INET);
+ case LINUX_AF_INET6:
+ return (AF_INET6);
+ case LINUX_AF_AX25:
+ return (AF_CCITT);
+ case LINUX_AF_IPX:
+ return (AF_IPX);
+ case LINUX_AF_APPLETALK:
+ return (AF_APPLETALK);
+ }
+ return (-1);
+}
+
+int
+bsd_to_linux_domain(int domain)
+{
+
+ switch (domain) {
+ case AF_UNSPEC:
+ return (LINUX_AF_UNSPEC);
+ case AF_LOCAL:
+ return (LINUX_AF_UNIX);
+ case AF_INET:
+ return (LINUX_AF_INET);
+ case AF_INET6:
+ return (LINUX_AF_INET6);
+ case AF_CCITT:
+ return (LINUX_AF_AX25);
+ case AF_IPX:
+ return (LINUX_AF_IPX);
+ case AF_APPLETALK:
+ return (LINUX_AF_APPLETALK);
+ }
+ return (-1);
+}
+
+/*
+ * Based on the fact that:
+ * 1. Native and Linux storage of struct sockaddr
+ * and struct sockaddr_in6 are equal.
+ * 2. On Linux sa_family is the first member of all struct sockaddr.
+ */
+int
+bsd_to_linux_sockaddr(const struct sockaddr *sa, struct l_sockaddr **lsa,
+ socklen_t len)
+{
+ struct l_sockaddr *kosa;
+ int error, bdom;
+
+ *lsa = NULL;
+ if (len < 2 || len > UCHAR_MAX)
+ return (EINVAL);
+
+ kosa = malloc(len, M_SONAME, M_WAITOK);
+ bcopy(sa, kosa, len);
+
+ bdom = bsd_to_linux_domain(sa->sa_family);
+ if (bdom == -1) {
+ error = EAFNOSUPPORT;
+ goto out;
+ }
+
+ kosa->sa_family = bdom;
+ *lsa = kosa;
+ return (0);
+
+out:
+ free(kosa, M_SONAME);
+ return (error);
+}
+
+int
+linux_to_bsd_sockaddr(const struct l_sockaddr *osa, struct sockaddr **sap,
+ socklen_t *len)
+{
+ struct sockaddr *sa;
+ struct l_sockaddr *kosa;
+#ifdef INET6
+ struct sockaddr_in6 *sin6;
+ bool oldv6size;
+#endif
+ char *name;
+ int salen, bdom, error, hdrlen, namelen;
+
+ if (*len < 2 || *len > UCHAR_MAX)
+ return (EINVAL);
+
+ salen = *len;
+
+#ifdef INET6
+ oldv6size = false;
+ /*
+ * Check for old (pre-RFC2553) sockaddr_in6. We may accept it
+ * if it's a v4-mapped address, so reserve the proper space
+ * for it.
+ */
+ if (salen == sizeof(struct sockaddr_in6) - sizeof(uint32_t)) {
+ salen += sizeof(uint32_t);
+ oldv6size = true;
+ }
+#endif
+
+ kosa = malloc(salen, M_SONAME, M_WAITOK);
+
+ if ((error = copyin(osa, kosa, *len)))
+ goto out;
+
+ bdom = linux_to_bsd_domain(kosa->sa_family);
+ if (bdom == -1) {
+ error = EAFNOSUPPORT;
+ goto out;
+ }
+
+#ifdef INET6
+ /*
+ * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6,
+ * which lacks the scope id compared with RFC2553 one. If we detect
+ * the situation, reject the address and write a message to system log.
+ *
+ * Still accept addresses for which the scope id is not used.
+ */
+ if (oldv6size) {
+ if (bdom == AF_INET6) {
+ sin6 = (struct sockaddr_in6 *)kosa;
+ if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ||
+ (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
+ !IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) &&
+ !IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) &&
+ !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
+ !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) {
+ sin6->sin6_scope_id = 0;
+ } else {
+ log(LOG_DEBUG,
+ "obsolete pre-RFC2553 sockaddr_in6 rejected\n");
+ error = EINVAL;
+ goto out;
+ }
+ } else
+ salen -= sizeof(uint32_t);
+ }
+#endif
+ if (bdom == AF_INET) {
+ if (salen < sizeof(struct sockaddr_in)) {
+ error = EINVAL;
+ goto out;
+ }
+ salen = sizeof(struct sockaddr_in);
+ }
+
+ if (bdom == AF_LOCAL && salen > sizeof(struct sockaddr_un)) {
+ hdrlen = offsetof(struct sockaddr_un, sun_path);
+ name = ((struct sockaddr_un *)kosa)->sun_path;
+ if (*name == '\0') {
+ /*
+ * Linux abstract namespace starts with a NULL byte.
+ * XXX We do not support abstract namespace yet.
+ */
+ namelen = strnlen(name + 1, salen - hdrlen - 1) + 1;
+ } else
+ namelen = strnlen(name, salen - hdrlen);
+ salen = hdrlen + namelen;
+ if (salen > sizeof(struct sockaddr_un)) {
+ error = ENAMETOOLONG;
+ goto out;
+ }
+ }
+
+ sa = (struct sockaddr *)kosa;
+ sa->sa_family = bdom;
+ sa->sa_len = salen;
+
+ *sap = sa;
+ *len = salen;
+ return (0);
+
+out:
+ free(kosa, M_SONAME);
+ return (error);
+}
Index: sys/compat/linux/linux_common.h
===================================================================
--- sys/compat/linux/linux_common.h
+++ sys/compat/linux/linux_common.h
@@ -35,4 +35,11 @@
void linux_ifflags(struct ifnet *ifp, short *flags);
int linux_ifhwaddr(struct ifnet *ifp, struct l_sockaddr *lsa);
+int linux_to_bsd_domain(int domain);
+int bsd_to_linux_domain(int domain);
+int bsd_to_linux_sockaddr(const struct sockaddr *sa,
+ struct l_sockaddr **lsa, socklen_t len);
+int linux_to_bsd_sockaddr(const struct l_sockaddr *lsa,
+ struct sockaddr **sap, socklen_t *len);
+
#endif /* _LINUX_COMMON_H_ */
Index: sys/compat/linux/linux_socket.c
===================================================================
--- sys/compat/linux/linux_socket.c
+++ sys/compat/linux/linux_socket.c
@@ -70,174 +70,18 @@
#include <machine/../linux/linux.h>
#include <machine/../linux/linux_proto.h>
#endif
+#include <compat/linux/linux_common.h>
#include <compat/linux/linux_file.h>
#include <compat/linux/linux_socket.h>
#include <compat/linux/linux_timer.h>
#include <compat/linux/linux_util.h>
-static int linux_to_bsd_domain(int);
static int linux_sendmsg_common(struct thread *, l_int, struct l_msghdr *,
l_uint);
static int linux_recvmsg_common(struct thread *, l_int, struct l_msghdr *,
l_uint, struct msghdr *);
static int linux_set_socket_flags(int, int *);
-/*
- * Reads a Linux sockaddr and does any necessary translation.
- * Linux sockaddrs don't have a length field, only a family.
- * Copy the osockaddr structure pointed to by osa to kernel, adjust
- * family and convert to sockaddr.
- */
-static int
-linux_getsockaddr(struct sockaddr **sap, const struct osockaddr *osa, int salen)
-{
- struct sockaddr *sa;
- struct osockaddr *kosa;
-#ifdef INET6
- struct sockaddr_in6 *sin6;
- int oldv6size;
-#endif
- char *name;
- int bdom, error, hdrlen, namelen;
-
- if (salen < 2 || salen > UCHAR_MAX || !osa)
- return (EINVAL);
-
-#ifdef INET6
- oldv6size = 0;
- /*
- * Check for old (pre-RFC2553) sockaddr_in6. We may accept it
- * if it's a v4-mapped address, so reserve the proper space
- * for it.
- */
- if (salen == sizeof(struct sockaddr_in6) - sizeof(uint32_t)) {
- salen += sizeof(uint32_t);
- oldv6size = 1;
- }
-#endif
-
- kosa = malloc(salen, M_SONAME, M_WAITOK);
-
- if ((error = copyin(osa, kosa, salen)))
- goto out;
-
- bdom = linux_to_bsd_domain(kosa->sa_family);
- if (bdom == -1) {
- error = EAFNOSUPPORT;
- goto out;
- }
-
-#ifdef INET6
- /*
- * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6,
- * which lacks the scope id compared with RFC2553 one. If we detect
- * the situation, reject the address and write a message to system log.
- *
- * Still accept addresses for which the scope id is not used.
- */
- if (oldv6size) {
- if (bdom == AF_INET6) {
- sin6 = (struct sockaddr_in6 *)kosa;
- if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ||
- (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
- !IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) &&
- !IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) &&
- !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
- !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) {
- sin6->sin6_scope_id = 0;
- } else {
- log(LOG_DEBUG,
- "obsolete pre-RFC2553 sockaddr_in6 rejected\n");
- error = EINVAL;
- goto out;
- }
- } else
- salen -= sizeof(uint32_t);
- }
-#endif
- if (bdom == AF_INET) {
- if (salen < sizeof(struct sockaddr_in)) {
- error = EINVAL;
- goto out;
- }
- salen = sizeof(struct sockaddr_in);
- }
-
- if (bdom == AF_LOCAL && salen > sizeof(struct sockaddr_un)) {
- hdrlen = offsetof(struct sockaddr_un, sun_path);
- name = ((struct sockaddr_un *)kosa)->sun_path;
- if (*name == '\0') {
- /*
- * Linux abstract namespace starts with a NULL byte.
- * XXX We do not support abstract namespace yet.
- */
- namelen = strnlen(name + 1, salen - hdrlen - 1) + 1;
- } else
- namelen = strnlen(name, salen - hdrlen);
- salen = hdrlen + namelen;
- if (salen > sizeof(struct sockaddr_un)) {
- error = ENAMETOOLONG;
- goto out;
- }
- }
-
- sa = (struct sockaddr *)kosa;
- sa->sa_family = bdom;
- sa->sa_len = salen;
-
- *sap = sa;
- return (0);
-
-out:
- free(kosa, M_SONAME);
- return (error);
-}
-
-static int
-linux_to_bsd_domain(int domain)
-{
-
- switch (domain) {
- case LINUX_AF_UNSPEC:
- return (AF_UNSPEC);
- case LINUX_AF_UNIX:
- return (AF_LOCAL);
- case LINUX_AF_INET:
- return (AF_INET);
- case LINUX_AF_INET6:
- return (AF_INET6);
- case LINUX_AF_AX25:
- return (AF_CCITT);
- case LINUX_AF_IPX:
- return (AF_IPX);
- case LINUX_AF_APPLETALK:
- return (AF_APPLETALK);
- }
- return (-1);
-}
-
-static int
-bsd_to_linux_domain(int domain)
-{
-
- switch (domain) {
- case AF_UNSPEC:
- return (LINUX_AF_UNSPEC);
- case AF_LOCAL:
- return (LINUX_AF_UNIX);
- case AF_INET:
- return (LINUX_AF_INET);
- case AF_INET6:
- return (LINUX_AF_INET6);
- case AF_CCITT:
- return (LINUX_AF_AX25);
- case AF_IPX:
- return (LINUX_AF_IPX);
- case AF_APPLETALK:
- return (LINUX_AF_APPLETALK);
- }
- return (-1);
-}
static int
linux_to_bsd_sockopt_level(int level)
@@ -453,71 +297,6 @@
return (ret_flags);
}
-/*
-* If bsd_to_linux_sockaddr() or linux_to_bsd_sockaddr() faults, then the
-* native syscall will fault. Thus, we don't really need to check the
-* return values for these functions.
-*/
-
-static int
-bsd_to_linux_sockaddr(struct sockaddr *arg)
-{
- struct sockaddr sa;
- size_t sa_len = sizeof(struct sockaddr);
- int error, bdom;
-
- if ((error = copyin(arg, &sa, sa_len)))
- return (error);
-
- bdom = bsd_to_linux_domain(sa.sa_family);
- if (bdom == -1)
- return (EAFNOSUPPORT);
-
- *(u_short *)&sa = bdom;
- return (copyout(&sa, arg, sa_len));
-}
-
-static int
-linux_to_bsd_sockaddr(struct sockaddr *arg, int len)
-{
- struct sockaddr sa;
- size_t sa_len = sizeof(struct sockaddr);
- int error, bdom;
-
- if ((error = copyin(arg, &sa, sa_len)))
- return (error);
-
- bdom = linux_to_bsd_domain(*(sa_family_t *)&sa);
- if (bdom == -1)
- return (EAFNOSUPPORT);
-
- sa.sa_family = bdom;
- sa.sa_len = len;
- return (copyout(&sa, arg, sa_len));
-}
-
-static int
-linux_sa_put(struct osockaddr *osa)
-{
- struct osockaddr sa;
- int error, bdom;
-
- /*
- * Only read/write the osockaddr family part, the rest is
- * not changed.
- */
- error = copyin(osa, &sa, sizeof(sa.sa_family));
- if (error != 0)
- return (error);
-
- bdom = bsd_to_linux_domain(sa.sa_family);
- if (bdom == -1)
- return (EINVAL);
-
- sa.sa_family = bdom;
- return (copyout(&sa, osa, sizeof(sa.sa_family)));
-}
-
static int
linux_to_bsd_cmsg_type(int cmsg_type)
{
@@ -611,10 +390,11 @@
struct mbuf *control, enum uio_seg segflg)
{
struct sockaddr *to;
- int error;
+ int error, len;
if (mp->msg_name != NULL) {
- error = linux_getsockaddr(&to, mp->msg_name, mp->msg_namelen);
+ len = mp->msg_namelen;
+ error = linux_to_bsd_sockaddr(mp->msg_name, &to, &len);
if (error != 0)
return (error);
mp->msg_name = to;
@@ -753,13 +533,15 @@
struct sockaddr *sa;
int error;
- error = linux_getsockaddr(&sa, PTRIN(args->name),
- args->namelen);
+ error = linux_to_bsd_sockaddr(PTRIN(args->name), &sa,
+ &args->namelen);
if (error != 0)
return (error);
error = kern_bindat(td, AT_FDCWD, args->s, sa);
free(sa, M_SONAME);
+
+ /* XXX */
if (error == EADDRNOTAVAIL && args->namelen != sizeof(struct sockaddr_in))
return (EINVAL);
return (error);
@@ -774,8 +556,8 @@
u_int fflag;
int error;
- error = linux_getsockaddr(&sa, (struct osockaddr *)PTRIN(args->name),
- args->namelen);
+ error = linux_to_bsd_sockaddr(PTRIN(args->name), &sa,
+ &args->namelen);
if (error != 0)
return (error);
@@ -819,43 +601,67 @@
linux_accept_common(struct thread *td, int s, l_uintptr_t addr,
l_uintptr_t namelen, int flags)
{
- struct accept4_args /* {
- int s;
- struct sockaddr * __restrict name;
- socklen_t * __restrict anamelen;
- int flags;
- } */ bsd_args;
- struct socket *so;
+ struct l_sockaddr *lsa;
+ struct sockaddr *sa;
struct file *fp;
+ int bflags, len;
+ struct socket *so;
int error, error1;
- bsd_args.s = s;
- bsd_args.name = (struct sockaddr * __restrict)PTRIN(addr);
- bsd_args.anamelen = PTRIN(namelen);
- bsd_args.flags = 0;
- error = linux_set_socket_flags(flags, &bsd_args.flags);
+ bflags = 0;
+ error = linux_set_socket_flags(flags, &bflags);
if (error != 0)
return (error);
- error = sys_accept4(td, &bsd_args);
- bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.name);
+
+ sa = NULL;
+ if (PTRIN(addr) == NULL) {
+ len = 0;
+ error = kern_accept4(td, s, NULL, NULL, bflags, NULL);
+ } else {
+ error = copyin(PTRIN(namelen), &len, sizeof(len));
+ if (error != 0)
+ return (error);
+ if (len < 0)
+ return (EINVAL);
+ error = kern_accept4(td, s, &sa, &len, bflags, &fp);
+ if (error == 0)
+ fdrop(fp, td);
+ }
+
if (error != 0) {
+ /*
+ * XXX. This is wrong, different sockaddr structures
+ * have different sizes.
+ */
if (error == EFAULT && namelen != sizeof(struct sockaddr_in))
- return (EINVAL);
+ {
+ error = EINVAL;
+ goto out;
+ }
if (error == EINVAL) {
error1 = getsock_cap(td, s, &cap_accept_rights, &fp, NULL, NULL);
- if (error1 != 0)
- return (error1);
- so = fp->f_data;
- if (so->so_type == SOCK_DGRAM) {
- fdrop(fp, td);
- return (EOPNOTSUPP);
+ if (error1 != 0) {
+ error = error1;
+ goto out;
}
+ so = fp->f_data;
+ if (so->so_type == SOCK_DGRAM)
+ error = EOPNOTSUPP;
fdrop(fp, td);
}
- return (error);
+ goto out;
+ }
+
+ if (len != 0 && error == 0) {
+ error = bsd_to_linux_sockaddr(sa, &lsa, len);
+ if (error == 0)
+ error = copyout(lsa, PTRIN(addr), len);
+ free(lsa, M_SONAME);
}
- if (addr)
- error = linux_sa_put(PTRIN(addr));
+
+ free(sa, M_SONAME);
+
+out:
if (error != 0) {
(void)kern_close(td, td->td_retval[0]);
td->td_retval[0] = 0;
@@ -882,41 +688,59 @@
int
linux_getsockname(struct thread *td, struct linux_getsockname_args *args)
{
- struct getsockname_args /* {
- int fdes;
- struct sockaddr * __restrict asa;
- socklen_t * __restrict alen;
- } */ bsd_args;
- int error;
+ struct l_sockaddr *lsa;
+ struct sockaddr *sa;
+ int len, error;
+
+ error = copyin(PTRIN(args->namelen), &len, sizeof(len));
+ if (error != 0)
+ return (error);
- bsd_args.fdes = args->s;
- bsd_args.asa = (struct sockaddr * __restrict)PTRIN(args->addr);
- bsd_args.alen = PTRIN(args->namelen);
- error = sys_getsockname(td, &bsd_args);
- bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa);
+ error = kern_getsockname(td, args->s, &sa, &len);
if (error != 0)
return (error);
- return (linux_sa_put(PTRIN(args->addr)));
+
+ if (len != 0) {
+ error = bsd_to_linux_sockaddr(sa, &lsa, len);
+ if (error == 0)
+ error = copyout(lsa, PTRIN(args->addr),
+ len);
+ free(lsa, M_SONAME);
+ }
+
+ free(sa, M_SONAME);
+ if (error == 0)
+ error = copyout(&len, PTRIN(args->namelen), sizeof(len));
+ return (error);
}
int
linux_getpeername(struct thread *td, struct linux_getpeername_args *args)
{
- struct getpeername_args /* {
- int fdes;
- caddr_t asa;
- int *alen;
- } */ bsd_args;
- int error;
+ struct l_sockaddr *lsa;
+ struct sockaddr *sa;
+ int len, error;
+
+ error = copyin(PTRIN(args->namelen), &len, sizeof(len));
+ if (error != 0)
+ return (error);
- bsd_args.fdes = args->s;
- bsd_args.asa = (struct sockaddr *)PTRIN(args->addr);
- bsd_args.alen = (socklen_t *)PTRIN(args->namelen);
- error = sys_getpeername(td, &bsd_args);
- bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa);
+ error = kern_getpeername(td, args->s, &sa, &len);
if (error != 0)
return (error);
- return (linux_sa_put(PTRIN(args->addr)));
+
+ if (len != 0) {
+ error = bsd_to_linux_sockaddr(sa, &lsa, len);
+ if (error == 0)
+ error = copyout(lsa, PTRIN(args->addr),
+ len);
+ free(lsa, M_SONAME);
+ }
+
+ free(sa, M_SONAME);
+ if (error == 0)
+ error = copyout(&len, PTRIN(args->namelen), sizeof(len));
+ return (error);
}
int
@@ -1038,6 +862,8 @@
int
linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args)
{
+ struct l_sockaddr *lsa;
+ struct sockaddr *sa;
struct msghdr msg;
struct iovec aiov;
int error, fromlen;
@@ -1049,11 +875,14 @@
return (error);
if (fromlen < 0)
return (EINVAL);
- msg.msg_namelen = fromlen;
- } else
- msg.msg_namelen = 0;
+ sa = malloc(fromlen, M_SONAME, M_WAITOK);
+ } else {
+ fromlen = 0;
+ sa = NULL;
+ }
- msg.msg_name = (struct sockaddr * __restrict)PTRIN(args->from);
+ msg.msg_name = sa;
+ msg.msg_namelen = fromlen;
msg.msg_iov = &aiov;
msg.msg_iovlen = 1;
aiov.iov_base = PTRIN(args->buf);
@@ -1061,24 +890,23 @@
msg.msg_control = 0;
msg.msg_flags = linux_to_bsd_msg_flags(args->flags);
- error = kern_recvit(td, args->s, &msg, UIO_USERSPACE, NULL);
+ error = kern_recvit(td, args->s, &msg, UIO_SYSSPACE, NULL);
if (error != 0)
return (error);
if (PTRIN(args->from) != NULL) {
- error = bsd_to_linux_sockaddr((struct sockaddr *)
- PTRIN(args->from));
- if (error != 0)
- return (error);
-
- error = linux_sa_put((struct osockaddr *)
- PTRIN(args->from));
+ error = bsd_to_linux_sockaddr(sa, &lsa, msg.msg_namelen);
+ if (error == 0)
+ error = copyout(lsa, PTRIN(args->from),
+ msg.msg_namelen);
+ free(lsa, M_SONAME);
}
- if (PTRIN(args->fromlen) != NULL)
+ if (error == 0 && PTRIN(args->fromlen) != NULL)
error = copyout(&msg.msg_namelen, PTRIN(args->fromlen),
sizeof(msg.msg_namelen));
+ free(sa, M_SONAME);
return (error);
}
@@ -1284,6 +1112,8 @@
struct mbuf *control = NULL;
struct mbuf **controlp;
struct timeval *ftmvl;
+ struct l_sockaddr *lsa;
+ struct sockaddr *sa;
l_timeval ltmvl;
caddr_t outbuf;
void *data;
@@ -1307,36 +1137,34 @@
return (error);
if (msg->msg_name) {
- error = linux_to_bsd_sockaddr((struct sockaddr *)msg->msg_name,
- msg->msg_namelen);
- if (error != 0)
- goto bad;
+ sa = malloc(msg->msg_namelen, M_SONAME, M_WAITOK);
+ msg->msg_name = sa;
}
uiov = msg->msg_iov;
msg->msg_iov = iov;
controlp = (msg->msg_control != NULL) ? &control : NULL;
- error = kern_recvit(td, s, msg, UIO_USERSPACE, controlp);
+ error = kern_recvit(td, s, msg, UIO_SYSSPACE, controlp);
msg->msg_iov = uiov;
if (error != 0)
goto bad;
- error = bsd_to_linux_msghdr(msg, &linux_msg);
- if (error != 0)
- goto bad;
-
- if (linux_msg.msg_name) {
- error = bsd_to_linux_sockaddr((struct sockaddr *)
- PTRIN(linux_msg.msg_name));
- if (error != 0)
- goto bad;
- }
- if (linux_msg.msg_name && linux_msg.msg_namelen > 2) {
- error = linux_sa_put(PTRIN(linux_msg.msg_name));
+ if (sa) {
+ msg->msg_name = PTRIN(linux_msg.msg_name);
+ error = bsd_to_linux_sockaddr(sa, &lsa, msg->msg_namelen);
+ if (error == 0)
+ error = copyout(lsa, PTRIN(msg->msg_name),
+ msg->msg_namelen);
+ free(lsa, M_SONAME);
+ free(sa, M_SONAME);
if (error != 0)
goto bad;
}
+ error = bsd_to_linux_msghdr(msg, &linux_msg);
+ if (error != 0)
+ goto bad;
+
maxlen = linux_msg.msg_controllen;
linux_msg.msg_controllen = 0;
if (control) {
@@ -1539,7 +1367,9 @@
int valsize;
} */ bsd_args;
l_timeval linux_tv;
+ struct sockaddr *sa;
struct timeval tv;
+ socklen_t len;
int error, name, val;
bsd_args.s = args->s;
@@ -1588,18 +1418,23 @@
if (name == -1)
return (ENOPROTOOPT);
- bsd_args.name = name;
- bsd_args.val = PTRIN(args->optval);
- bsd_args.valsize = args->optlen;
if (name == IPV6_NEXTHOP) {
- linux_to_bsd_sockaddr(__DECONST(struct sockaddr *,
- bsd_args.val), bsd_args.valsize);
- error = sys_setsockopt(td, &bsd_args);
- bsd_to_linux_sockaddr(__DECONST(struct sockaddr *,
- bsd_args.val));
- } else
+
+ len = args->optlen;
+ error = linux_to_bsd_sockaddr(PTRIN(args->optval), &sa, &len);
+ if (error != 0)
+ return (error);
+
+ error = kern_setsockopt(td, args->s, bsd_args.level,
+ name, sa, UIO_SYSSPACE, len);
+ free(sa, M_SONAME);
+ } else {
+ bsd_args.name = name;
+ bsd_args.val = PTRIN(args->optval);
+ bsd_args.valsize = args->optlen;
error = sys_setsockopt(td, &bsd_args);
+ }
return (error);
}
@@ -1617,6 +1452,8 @@
l_timeval linux_tv;
struct timeval tv;
socklen_t tv_len, xulen, len;
+ struct l_sockaddr *lsa;
+ struct sockaddr *sa;
struct xucred xu;
struct l_ucred lxu;
int error, name, newval;
@@ -1696,14 +1533,32 @@
return (EINVAL);
bsd_args.name = name;
- bsd_args.val = PTRIN(args->optval);
bsd_args.avalsize = PTRIN(args->optlen);
if (name == IPV6_NEXTHOP) {
+ error = copyin(PTRIN(args->optlen), &len, sizeof(len));
+ if (error != 0)
+ return (error);
+ sa = malloc(len, M_SONAME, M_WAITOK);
+
+ error = kern_getsockopt(td, args->s, bsd_args.level,
+ name, sa, UIO_SYSSPACE, &len);
+ if (error != 0)
+ goto out;
+
+ error = bsd_to_linux_sockaddr(sa, &lsa, len);
+ if (error == 0)
+ error = copyout(lsa, PTRIN(args->optval), len);
+ free(lsa, M_SONAME);
+ if (error == 0)
+ error = copyout(&len, PTRIN(args->optlen),
+ sizeof(len));
+out:
+ free(sa, M_SONAME);
+ } else {
+ bsd_args.val = PTRIN(args->optval);
error = sys_getsockopt(td, &bsd_args);
- bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val);
- } else
- error = sys_getsockopt(td, &bsd_args);
+ }
return (error);
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Nov 18, 11:26 PM (30 m, 1 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
25561861
Default Alt Text
D20157.id57059.diff (22 KB)
Attached To
Mode
D20157: Rewrite Linuxulator struct sockaddr conversion funtions
Attached
Detach File
Event Timeline
Log In to Comment