+static inline void target_to_host_sockaddr(struct sockaddr *addr,
+ struct target_sockaddr *target_addr,
+ socklen_t len)
+{
+ memcpy(addr, target_addr, len);
+ addr->sa_family = tswap16(target_addr->sa_family);
+}
+
+static inline void host_to_target_sockaddr(struct target_sockaddr *target_addr,
+ struct sockaddr *addr,
+ socklen_t len)
+{
+ memcpy(target_addr, addr, len);
+ target_addr->sa_family = tswap16(addr->sa_family);
+}
+
+static inline void target_to_host_cmsg(struct msghdr *msgh,
+ struct target_msghdr *target_msgh)
+{
+ struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
+ struct target_cmsghdr *target_cmsg = TARGET_CMSG_FIRSTHDR(target_msgh);
+ socklen_t space = 0;
+
+ while (cmsg && target_cmsg) {
+ void *data = CMSG_DATA(cmsg);
+ void *target_data = TARGET_CMSG_DATA(target_cmsg);
+
+ int len = tswapl(target_cmsg->cmsg_len)
+ - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
+
+ space += CMSG_SPACE(len);
+ if (space > msgh->msg_controllen) {
+ space -= CMSG_SPACE(len);
+ gemu_log("Host cmsg overflow");
+ break;
+ }
+
+ cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
+ cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
+ cmsg->cmsg_len = CMSG_LEN(len);
+
+ if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
+ gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
+ memcpy(data, target_data, len);
+ } else {
+ int *fd = (int *)data;
+ int *target_fd = (int *)target_data;
+ int i, numfds = len / sizeof(int);
+
+ for (i = 0; i < numfds; i++)
+ fd[i] = tswap32(target_fd[i]);
+ }
+
+ cmsg = CMSG_NXTHDR(msgh, cmsg);
+ target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
+ }
+
+ msgh->msg_controllen = space;
+}
+
+static inline void host_to_target_cmsg(struct target_msghdr *target_msgh,
+ struct msghdr *msgh)
+{
+ struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
+ struct target_cmsghdr *target_cmsg = TARGET_CMSG_FIRSTHDR(target_msgh);
+ socklen_t space = 0;
+
+ while (cmsg && target_cmsg) {
+ void *data = CMSG_DATA(cmsg);
+ void *target_data = TARGET_CMSG_DATA(target_cmsg);
+
+ int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
+
+ space += TARGET_CMSG_SPACE(len);
+ if (space > tswapl(target_msgh->msg_controllen)) {
+ space -= TARGET_CMSG_SPACE(len);
+ gemu_log("Target cmsg overflow");
+ break;
+ }
+
+ target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
+ target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
+ target_cmsg->cmsg_len = tswapl(TARGET_CMSG_LEN(len));
+
+ if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
+ gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
+ memcpy(target_data, data, len);
+ } else {
+ int *fd = (int *)data;
+ int *target_fd = (int *)target_data;
+ int i, numfds = len / sizeof(int);
+
+ for (i = 0; i < numfds; i++)
+ target_fd[i] = tswap32(fd[i]);
+ }
+
+ cmsg = CMSG_NXTHDR(msgh, cmsg);
+ target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
+ }
+
+ msgh->msg_controllen = tswapl(space);
+}
+
+static long do_setsockopt(int sockfd, int level, int optname,
+ void *optval, socklen_t optlen)
+{
+ if (level == SOL_TCP) {
+ /* TCP options all take an 'int' value. */
+ int val;
+
+ if (optlen < sizeof(uint32_t))
+ return -EINVAL;
+
+ val = tswap32(*(uint32_t *)optval);
+ return get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
+ }
+
+ else if (level != SOL_SOCKET) {
+ gemu_log("Unsupported setsockopt level: %d\n", level);
+ return -ENOSYS;
+ }
+
+ switch (optname) {
+ /* Options with 'int' argument. */
+ case SO_DEBUG:
+ case SO_REUSEADDR:
+ case SO_TYPE:
+ case SO_ERROR:
+ case SO_DONTROUTE:
+ case SO_BROADCAST:
+ case SO_SNDBUF:
+ case SO_RCVBUF:
+ case SO_KEEPALIVE:
+ case SO_OOBINLINE:
+ case SO_NO_CHECK:
+ case SO_PRIORITY:
+ case SO_BSDCOMPAT:
+ case SO_PASSCRED:
+ case SO_TIMESTAMP:
+ case SO_RCVLOWAT:
+ case SO_RCVTIMEO:
+ case SO_SNDTIMEO:
+ {
+ int val;
+ if (optlen < sizeof(uint32_t))
+ return -EINVAL;
+ val = tswap32(*(uint32_t *)optval);
+ return get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
+ }
+
+ default:
+ gemu_log("Unsupported setsockopt SOL_SOCKET option: %d\n", optname);
+ return -ENOSYS;
+ }
+}
+
+static long do_getsockopt(int sockfd, int level, int optname,
+ void *optval, socklen_t *optlen)
+{
+ gemu_log("getsockopt not yet supported\n");
+ return -ENOSYS;
+}
+
+static long do_socketcall(int num, int32_t *vptr)