blob: cc45400e4ce3bbf79cfc63806bea010814533134 [file]
/*
* BSD socket system call related helpers
*
* Copyright (c) 2013 Stacey D. Son
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include "qemu.h"
#include "qemu-bsd.h"
/*
* socket conversion
*/
abi_long target_to_host_sockaddr(struct sockaddr *addr, abi_ulong target_addr,
socklen_t len)
{
const socklen_t unix_maxlen = sizeof(struct sockaddr_un);
sa_family_t sa_family;
struct target_sockaddr *target_saddr;
target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
if (target_saddr == 0) {
return -TARGET_EFAULT;
}
sa_family = target_saddr->sa_family;
/*
* Oops. The caller might send a incomplete sun_path; sun_path
* must be terminated by \0 (see the manual page), but unfortunately
* it is quite common to specify sockaddr_un length as
* "strlen(x->sun_path)" while it should be "strlen(...) + 1". We will
* fix that here if needed.
*/
if (target_saddr->sa_family == AF_UNIX) {
if (len < unix_maxlen && len > 0) {
char *cp = (char *)target_saddr;
if (cp[len - 1] && !cp[len]) {
len++;
}
}
if (len > unix_maxlen) {
len = unix_maxlen;
}
}
memcpy(addr, target_saddr, len);
addr->sa_family = sa_family; /* type uint8_t */
addr->sa_len = target_saddr->sa_len; /* type uint8_t */
unlock_user(target_saddr, target_addr, 0);
return 0;
}
abi_long host_to_target_sockaddr(abi_ulong target_addr, struct sockaddr *addr,
socklen_t len)
{
struct target_sockaddr *target_saddr;
target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
if (target_saddr == 0) {
return -TARGET_EFAULT;
}
memcpy(target_saddr, addr, len);
target_saddr->sa_family = addr->sa_family; /* type uint8_t */
target_saddr->sa_len = addr->sa_len; /* type uint8_t */
unlock_user(target_saddr, target_addr, len);
return 0;
}
abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn, abi_ulong target_addr,
socklen_t len)
{
struct target_ip_mreqn *target_smreqn;
target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
if (target_smreqn == 0) {
return -TARGET_EFAULT;
}
mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
if (len == sizeof(struct target_ip_mreqn)) {
mreqn->imr_ifindex = tswap32(target_smreqn->imr_ifindex);
}
unlock_user(target_smreqn, target_addr, 0);
return 0;
}