mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-03 15:53:54 -06:00
linux-user: Add support for various missing netlink sockopt entries
Add missing sockopt calls and thus fix building the debian gupnp package in a chroot. This fixes debian bug report: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1044651 Signed-off-by: Helge Deller <deller@gmx.de> -----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQS86RI+GtKfB8BJu973ErUQojoPXwUCZ5OPdwAKCRD3ErUQojoP X9EWAP0ZvoDehmNzgWMlUpWT+d4O06kMsrDsi+tRddUUSJgp4wEAuuycr4go4b9b 6xLDLr81C7MFEGsztGcRVhPwVdDJxAU= =Lw8U -----END PGP SIGNATURE----- Merge tag 'linux-user-fix-gupnp-pull-request' of https://github.com/hdeller/qemu-hppa into staging linux-user: Add support for various missing netlink sockopt entries Add missing sockopt calls and thus fix building the debian gupnp package in a chroot. This fixes debian bug report: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1044651 Signed-off-by: Helge Deller <deller@gmx.de> # -----BEGIN PGP SIGNATURE----- # # iHUEABYKAB0WIQS86RI+GtKfB8BJu973ErUQojoPXwUCZ5OPdwAKCRD3ErUQojoP # X9EWAP0ZvoDehmNzgWMlUpWT+d4O06kMsrDsi+tRddUUSJgp4wEAuuycr4go4b9b # 6xLDLr81C7MFEGsztGcRVhPwVdDJxAU= # =Lw8U # -----END PGP SIGNATURE----- # gpg: Signature made Fri 24 Jan 2025 08:02:47 EST # gpg: using EDDSA key BCE9123E1AD29F07C049BBDEF712B510A23A0F5F # gpg: Good signature from "Helge Deller <deller@gmx.de>" [unknown] # gpg: aka "Helge Deller <deller@kernel.org>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 4544 8228 2CD9 10DB EF3D 25F8 3E5F 3D04 A7A2 4603 # Subkey fingerprint: BCE9 123E 1AD2 9F07 C049 BBDE F712 B510 A23A 0F5F * tag 'linux-user-fix-gupnp-pull-request' of https://github.com/hdeller/qemu-hppa: linux-user: netlink: Add missing QEMU_IFLA entries linux-user: netlink: add netlink neighbour emulation linux-user: netlink: Add emulation of IP_MULTICAST_IF linux-user: netlink: Add IP_PKTINFO cmsg parsing linux-user: Use unique error messages for cmsg parsing linux-user: netlink: Add missing IFA_PROTO to host_to_target_data_addr_rtattr() Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
commit
ed734377ab
3 changed files with 192 additions and 17 deletions
|
@ -25,12 +25,32 @@
|
|||
#ifdef CONFIG_RTNETLINK
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/if_bridge.h>
|
||||
#include <linux/neighbour.h>
|
||||
#endif
|
||||
#include "qemu.h"
|
||||
#include "user-internals.h"
|
||||
#include "fd-trans.h"
|
||||
#include "signal-common.h"
|
||||
|
||||
#define NDM_RTA(r) ((struct rtattr*)(((char*)(r)) + \
|
||||
NLMSG_ALIGN(sizeof(struct ndmsg))))
|
||||
|
||||
enum {
|
||||
QEMU_IFA_UNSPEC,
|
||||
QEMU_IFA_ADDRESS,
|
||||
QEMU_IFA_LOCAL,
|
||||
QEMU_IFA_LABEL,
|
||||
QEMU_IFA_BROADCAST,
|
||||
QEMU_IFA_ANYCAST,
|
||||
QEMU_IFA_CACHEINFO,
|
||||
QEMU_IFA_MULTICAST,
|
||||
QEMU_IFA_FLAGS,
|
||||
QEMU_IFA_RT_PRIORITY,
|
||||
QEMU_IFA_TARGET_NETNSID,
|
||||
QEMU_IFA_PROTO,
|
||||
QEMU__IFA__MAX,
|
||||
};
|
||||
|
||||
enum {
|
||||
QEMU_IFLA_BR_UNSPEC,
|
||||
QEMU_IFLA_BR_FORWARD_DELAY,
|
||||
|
@ -141,6 +161,14 @@ enum {
|
|||
QEMU_IFLA_PROTO_DOWN_REASON,
|
||||
QEMU_IFLA_PARENT_DEV_NAME,
|
||||
QEMU_IFLA_PARENT_DEV_BUS_NAME,
|
||||
QEMU_IFLA_GRO_MAX_SIZE,
|
||||
QEMU_IFLA_TSO_MAX_SIZE,
|
||||
QEMU_IFLA_TSO_MAX_SEGS,
|
||||
QEMU_IFLA_ALLMULTI,
|
||||
QEMU_IFLA_DEVLINK_PORT,
|
||||
QEMU_IFLA_GSO_IPV4_MAX_SIZE,
|
||||
QEMU_IFLA_GRO_IPV4_MAX_SIZE,
|
||||
QEMU_IFLA_DPLL_PIN,
|
||||
QEMU___IFLA_MAX
|
||||
};
|
||||
|
||||
|
@ -982,6 +1010,22 @@ static abi_long host_to_target_data_vfinfo_nlattr(struct nlattr *nlattr,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static abi_long host_to_target_data_prop_nlattr(struct nlattr *nlattr,
|
||||
void *context)
|
||||
{
|
||||
switch (nlattr->nla_type) {
|
||||
/* string */
|
||||
case QEMU_IFLA_ALT_IFNAME:
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP, "Unknown host PROP type: %d\n",
|
||||
nlattr->nla_type);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static abi_long host_to_target_data_link_rtattr(struct rtattr *rtattr)
|
||||
{
|
||||
uint32_t *u32;
|
||||
|
@ -990,7 +1034,7 @@ static abi_long host_to_target_data_link_rtattr(struct rtattr *rtattr)
|
|||
struct rtnl_link_ifmap *map;
|
||||
struct linkinfo_context li_context;
|
||||
|
||||
switch (rtattr->rta_type) {
|
||||
switch (rtattr->rta_type & NLA_TYPE_MASK) {
|
||||
/* binary stream */
|
||||
case QEMU_IFLA_ADDRESS:
|
||||
case QEMU_IFLA_BROADCAST:
|
||||
|
@ -1028,6 +1072,12 @@ static abi_long host_to_target_data_link_rtattr(struct rtattr *rtattr)
|
|||
case QEMU_IFLA_CARRIER_DOWN_COUNT:
|
||||
case QEMU_IFLA_MIN_MTU:
|
||||
case QEMU_IFLA_MAX_MTU:
|
||||
case QEMU_IFLA_GRO_MAX_SIZE:
|
||||
case QEMU_IFLA_TSO_MAX_SIZE:
|
||||
case QEMU_IFLA_TSO_MAX_SEGS:
|
||||
case QEMU_IFLA_ALLMULTI:
|
||||
case QEMU_IFLA_GSO_IPV4_MAX_SIZE:
|
||||
case QEMU_IFLA_GRO_IPV4_MAX_SIZE:
|
||||
u32 = RTA_DATA(rtattr);
|
||||
*u32 = tswap32(*u32);
|
||||
break;
|
||||
|
@ -1123,6 +1173,10 @@ static abi_long host_to_target_data_link_rtattr(struct rtattr *rtattr)
|
|||
return host_to_target_for_each_nlattr(RTA_DATA(rtattr), rtattr->rta_len,
|
||||
NULL,
|
||||
host_to_target_data_vfinfo_nlattr);
|
||||
case QEMU_IFLA_PROP_LIST:
|
||||
return host_to_target_for_each_nlattr(RTA_DATA(rtattr), rtattr->rta_len,
|
||||
NULL,
|
||||
host_to_target_data_prop_nlattr);
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP, "Unknown host QEMU_IFLA type: %d\n",
|
||||
rtattr->rta_type);
|
||||
|
@ -1138,20 +1192,21 @@ static abi_long host_to_target_data_addr_rtattr(struct rtattr *rtattr)
|
|||
|
||||
switch (rtattr->rta_type) {
|
||||
/* binary: depends on family type */
|
||||
case IFA_ADDRESS:
|
||||
case IFA_LOCAL:
|
||||
case QEMU_IFA_ADDRESS:
|
||||
case QEMU_IFA_LOCAL:
|
||||
case QEMU_IFA_PROTO:
|
||||
break;
|
||||
/* string */
|
||||
case IFA_LABEL:
|
||||
case QEMU_IFA_LABEL:
|
||||
break;
|
||||
/* u32 */
|
||||
case IFA_FLAGS:
|
||||
case IFA_BROADCAST:
|
||||
case QEMU_IFA_FLAGS:
|
||||
case QEMU_IFA_BROADCAST:
|
||||
u32 = RTA_DATA(rtattr);
|
||||
*u32 = tswap32(*u32);
|
||||
break;
|
||||
/* struct ifa_cacheinfo */
|
||||
case IFA_CACHEINFO:
|
||||
case QEMU_IFA_CACHEINFO:
|
||||
ci = RTA_DATA(rtattr);
|
||||
ci->ifa_prefered = tswap32(ci->ifa_prefered);
|
||||
ci->ifa_valid = tswap32(ci->ifa_valid);
|
||||
|
@ -1209,6 +1264,35 @@ static abi_long host_to_target_data_route_rtattr(struct rtattr *rtattr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static abi_long host_to_target_data_neigh_rtattr(struct rtattr *rtattr)
|
||||
{
|
||||
struct nda_cacheinfo *ndac;
|
||||
uint32_t *u32;
|
||||
|
||||
switch (rtattr->rta_type) {
|
||||
case NDA_UNSPEC:
|
||||
case NDA_DST:
|
||||
case NDA_LLADDR:
|
||||
break;
|
||||
case NDA_PROBES:
|
||||
u32 = RTA_DATA(rtattr);
|
||||
*u32 = tswap32(*u32);
|
||||
break;
|
||||
case NDA_CACHEINFO:
|
||||
ndac = RTA_DATA(rtattr);
|
||||
ndac->ndm_confirmed = tswap32(ndac->ndm_confirmed);
|
||||
ndac->ndm_used = tswap32(ndac->ndm_used);
|
||||
ndac->ndm_updated = tswap32(ndac->ndm_updated);
|
||||
ndac->ndm_refcnt = tswap32(ndac->ndm_refcnt);
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP, "Unknown host to target NEIGH type: %d\n",
|
||||
rtattr->rta_type);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static abi_long host_to_target_link_rtattr(struct rtattr *rtattr,
|
||||
uint32_t rtattr_len)
|
||||
{
|
||||
|
@ -1230,12 +1314,20 @@ static abi_long host_to_target_route_rtattr(struct rtattr *rtattr,
|
|||
host_to_target_data_route_rtattr);
|
||||
}
|
||||
|
||||
static abi_long host_to_target_neigh_rtattr(struct rtattr *rtattr,
|
||||
uint32_t rtattr_len)
|
||||
{
|
||||
return host_to_target_for_each_rtattr(rtattr, rtattr_len,
|
||||
host_to_target_data_neigh_rtattr);
|
||||
}
|
||||
|
||||
static abi_long host_to_target_data_route(struct nlmsghdr *nlh)
|
||||
{
|
||||
uint32_t nlmsg_len;
|
||||
struct ifinfomsg *ifi;
|
||||
struct ifaddrmsg *ifa;
|
||||
struct rtmsg *rtm;
|
||||
struct ndmsg *ndm;
|
||||
|
||||
nlmsg_len = nlh->nlmsg_len;
|
||||
switch (nlh->nlmsg_type) {
|
||||
|
@ -1262,6 +1354,17 @@ static abi_long host_to_target_data_route(struct nlmsghdr *nlh)
|
|||
nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
|
||||
}
|
||||
break;
|
||||
case RTM_NEWNEIGH:
|
||||
case RTM_DELNEIGH:
|
||||
case RTM_GETNEIGH:
|
||||
if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ndm))) {
|
||||
ndm = NLMSG_DATA(nlh);
|
||||
ndm->ndm_ifindex = tswap32(ndm->ndm_ifindex);
|
||||
ndm->ndm_state = tswap16(ndm->ndm_state);
|
||||
host_to_target_neigh_rtattr(NDM_RTA(ndm),
|
||||
nlmsg_len - NLMSG_LENGTH(sizeof(*ndm)));
|
||||
}
|
||||
break;
|
||||
case RTM_NEWROUTE:
|
||||
case RTM_DELROUTE:
|
||||
case RTM_GETROUTE:
|
||||
|
@ -1398,8 +1501,8 @@ static abi_long target_to_host_data_addr_rtattr(struct rtattr *rtattr)
|
|||
{
|
||||
switch (rtattr->rta_type) {
|
||||
/* binary: depends on family type */
|
||||
case IFA_LOCAL:
|
||||
case IFA_ADDRESS:
|
||||
case QEMU_IFA_LOCAL:
|
||||
case QEMU_IFA_ADDRESS:
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP, "Unknown target IFA type: %d\n",
|
||||
|
@ -1409,6 +1512,35 @@ static abi_long target_to_host_data_addr_rtattr(struct rtattr *rtattr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static abi_long target_to_host_data_neigh_rtattr(struct rtattr *rtattr)
|
||||
{
|
||||
struct nda_cacheinfo *ndac;
|
||||
uint32_t *u32;
|
||||
|
||||
switch (rtattr->rta_type) {
|
||||
case NDA_UNSPEC:
|
||||
case NDA_DST:
|
||||
case NDA_LLADDR:
|
||||
break;
|
||||
case NDA_PROBES:
|
||||
u32 = RTA_DATA(rtattr);
|
||||
*u32 = tswap32(*u32);
|
||||
break;
|
||||
case NDA_CACHEINFO:
|
||||
ndac = RTA_DATA(rtattr);
|
||||
ndac->ndm_confirmed = tswap32(ndac->ndm_confirmed);
|
||||
ndac->ndm_used = tswap32(ndac->ndm_used);
|
||||
ndac->ndm_updated = tswap32(ndac->ndm_updated);
|
||||
ndac->ndm_refcnt = tswap32(ndac->ndm_refcnt);
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP, "Unknown target NEIGH type: %d\n",
|
||||
rtattr->rta_type);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static abi_long target_to_host_data_route_rtattr(struct rtattr *rtattr)
|
||||
{
|
||||
uint32_t *u32;
|
||||
|
@ -1447,6 +1579,13 @@ static void target_to_host_addr_rtattr(struct rtattr *rtattr,
|
|||
target_to_host_data_addr_rtattr);
|
||||
}
|
||||
|
||||
static void target_to_host_neigh_rtattr(struct rtattr *rtattr,
|
||||
uint32_t rtattr_len)
|
||||
{
|
||||
target_to_host_for_each_rtattr(rtattr, rtattr_len,
|
||||
target_to_host_data_neigh_rtattr);
|
||||
}
|
||||
|
||||
static void target_to_host_route_rtattr(struct rtattr *rtattr,
|
||||
uint32_t rtattr_len)
|
||||
{
|
||||
|
@ -1459,6 +1598,7 @@ static abi_long target_to_host_data_route(struct nlmsghdr *nlh)
|
|||
struct ifinfomsg *ifi;
|
||||
struct ifaddrmsg *ifa;
|
||||
struct rtmsg *rtm;
|
||||
struct ndmsg *ndm;
|
||||
|
||||
switch (nlh->nlmsg_type) {
|
||||
case RTM_NEWLINK:
|
||||
|
@ -1485,6 +1625,17 @@ static abi_long target_to_host_data_route(struct nlmsghdr *nlh)
|
|||
NLMSG_LENGTH(sizeof(*ifa)));
|
||||
}
|
||||
break;
|
||||
case RTM_NEWNEIGH:
|
||||
case RTM_DELNEIGH:
|
||||
case RTM_GETNEIGH:
|
||||
if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ndm))) {
|
||||
ndm = NLMSG_DATA(nlh);
|
||||
ndm->ndm_ifindex = tswap32(ndm->ndm_ifindex);
|
||||
ndm->ndm_state = tswap16(ndm->ndm_state);
|
||||
target_to_host_neigh_rtattr(NDM_RTA(ndm), nlh->nlmsg_len -
|
||||
NLMSG_LENGTH(sizeof(*ndm)));
|
||||
}
|
||||
break;
|
||||
case RTM_NEWROUTE:
|
||||
case RTM_DELROUTE:
|
||||
case RTM_GETROUTE:
|
||||
|
|
|
@ -1827,7 +1827,7 @@ static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
|
|||
*dst = tswap32(*dst);
|
||||
}
|
||||
} else {
|
||||
qemu_log_mask(LOG_UNIMP, "Unsupported ancillary data: %d/%d\n",
|
||||
qemu_log_mask(LOG_UNIMP, "Unsupported target ancillary data: %d/%d\n",
|
||||
cmsg->cmsg_level, cmsg->cmsg_type);
|
||||
memcpy(data, target_data, len);
|
||||
}
|
||||
|
@ -1998,6 +1998,16 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
|
|||
(void *) &errh->offender, sizeof(errh->offender));
|
||||
break;
|
||||
}
|
||||
case IP_PKTINFO:
|
||||
{
|
||||
struct in_pktinfo *pkti = data;
|
||||
struct target_in_pktinfo *target_pi = target_data;
|
||||
|
||||
__put_user(pkti->ipi_ifindex, &target_pi->ipi_ifindex);
|
||||
target_pi->ipi_spec_dst.s_addr = pkti->ipi_spec_dst.s_addr;
|
||||
target_pi->ipi_addr.s_addr = pkti->ipi_addr.s_addr;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
goto unimplemented;
|
||||
}
|
||||
|
@ -2049,7 +2059,7 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
|
|||
|
||||
default:
|
||||
unimplemented:
|
||||
qemu_log_mask(LOG_UNIMP, "Unsupported ancillary data: %d/%d\n",
|
||||
qemu_log_mask(LOG_UNIMP, "Unsupported host ancillary data: %d/%d\n",
|
||||
cmsg->cmsg_level, cmsg->cmsg_type);
|
||||
memcpy(target_data, data, MIN(len, tgt_len));
|
||||
if (tgt_len > len) {
|
||||
|
@ -2120,16 +2130,23 @@ static abi_long do_setsockopt(int sockfd, int level, int optname,
|
|||
}
|
||||
ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
|
||||
break;
|
||||
case IP_MULTICAST_IF:
|
||||
case IP_ADD_MEMBERSHIP:
|
||||
case IP_DROP_MEMBERSHIP:
|
||||
{
|
||||
struct ip_mreqn ip_mreq;
|
||||
struct target_ip_mreqn *target_smreqn;
|
||||
int min_size;
|
||||
|
||||
QEMU_BUILD_BUG_ON(sizeof(struct ip_mreq) !=
|
||||
sizeof(struct target_ip_mreq));
|
||||
|
||||
if (optlen < sizeof (struct target_ip_mreq) ||
|
||||
if (optname == IP_MULTICAST_IF) {
|
||||
min_size = sizeof(struct in_addr);
|
||||
} else {
|
||||
min_size = sizeof(struct target_ip_mreq);
|
||||
}
|
||||
if (optlen < min_size ||
|
||||
optlen > sizeof (struct target_ip_mreqn)) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
|
@ -2139,13 +2156,14 @@ static abi_long do_setsockopt(int sockfd, int level, int optname,
|
|||
return -TARGET_EFAULT;
|
||||
}
|
||||
ip_mreq.imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
|
||||
ip_mreq.imr_address.s_addr = target_smreqn->imr_address.s_addr;
|
||||
if (optlen == sizeof(struct target_ip_mreqn)) {
|
||||
ip_mreq.imr_ifindex = tswapal(target_smreqn->imr_ifindex);
|
||||
optlen = sizeof(struct ip_mreqn);
|
||||
if (optlen >= sizeof(struct target_ip_mreq)) {
|
||||
ip_mreq.imr_address.s_addr = target_smreqn->imr_address.s_addr;
|
||||
if (optlen >= sizeof(struct target_ip_mreqn)) {
|
||||
__put_user(target_smreqn->imr_ifindex, &ip_mreq.imr_ifindex);
|
||||
optlen = sizeof(struct ip_mreqn);
|
||||
}
|
||||
}
|
||||
unlock_user(target_smreqn, optval_addr, 0);
|
||||
|
||||
ret = get_errno(setsockopt(sockfd, level, optname, &ip_mreq, optlen));
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -2622,6 +2622,12 @@ struct target_ucred {
|
|||
abi_uint gid;
|
||||
};
|
||||
|
||||
struct target_in_pktinfo {
|
||||
abi_int ipi_ifindex;
|
||||
struct target_in_addr ipi_spec_dst;
|
||||
struct target_in_addr ipi_addr;
|
||||
};
|
||||
|
||||
typedef abi_int target_timer_t;
|
||||
|
||||
#define TARGET_SIGEV_MAX_SIZE 64
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue