linux-user: netlink: add netlink neighbour emulation

Fixes various warnings in the testsuite while building gupnp:
 gssdp-net-DEBUG: Failed to send netlink message: Operation not supported
 gupnp-context-DEBUG: Mismatch between host header and host IP (example.com, expected: 127.0.0.1)
 gupnp-context-DEBUG: Mismatch between host header and host port (80, expected 4711)
 gupnp-context-DEBUG: Mismatch between host header and host IP (192.168.1.2, expected: 127.0.0.1)
 gupnp-context-DEBUG: Mismatch between host header and host IP (fe80::01, expected: 127.0.0.1)
 gupnp-context-DEBUG: Mismatch between host header and host port (80, expected 4711)
 gupnp-context-DEBUG: Failed to parse HOST header from request: Invalid IPv6 address ?[fe80::01%1]? in URI
 gupnp-context-DEBUG: Failed to parse HOST header from request: Invalid IPv6 address ?[fe80::01%eth0]? in URI
 gupnp-context-DEBUG: Failed to parse HOST header from request: Could not parse port ?:1? in URI
 gupnp-context-DEBUG: Mismatch between host header and host IP (example.com, expected: ::1)
 gupnp-context-DEBUG: Mismatch between host header and host port (80, expected 4711)
 gupnp-context-DEBUG: Mismatch between host header and host IP (example.com, expected: ::1)
 gupnp-context-DEBUG: Mismatch between host header and host port (80, expected 4711)
 gupnp-context-DEBUG: Mismatch between host header and host IP (example.com, expected: ::1)

Signed-off-by: Helge Deller <deller@gmx.de>
Reviewed-by: Laurent Vivier <laurent@vivier.eu>
This commit is contained in:
Helge Deller 2025-01-20 22:22:31 +01:00
parent f65464ce6d
commit cc9a83155d

View File

@ -25,12 +25,16 @@
#ifdef CONFIG_RTNETLINK #ifdef CONFIG_RTNETLINK
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <linux/if_bridge.h> #include <linux/if_bridge.h>
#include <linux/neighbour.h>
#endif #endif
#include "qemu.h" #include "qemu.h"
#include "user-internals.h" #include "user-internals.h"
#include "fd-trans.h" #include "fd-trans.h"
#include "signal-common.h" #include "signal-common.h"
#define NDM_RTA(r) ((struct rtattr*)(((char*)(r)) + \
NLMSG_ALIGN(sizeof(struct ndmsg))))
enum { enum {
QEMU_IFA_UNSPEC, QEMU_IFA_UNSPEC,
QEMU_IFA_ADDRESS, QEMU_IFA_ADDRESS,
@ -1226,6 +1230,35 @@ static abi_long host_to_target_data_route_rtattr(struct rtattr *rtattr)
return 0; 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, static abi_long host_to_target_link_rtattr(struct rtattr *rtattr,
uint32_t rtattr_len) uint32_t rtattr_len)
{ {
@ -1247,12 +1280,20 @@ static abi_long host_to_target_route_rtattr(struct rtattr *rtattr,
host_to_target_data_route_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) static abi_long host_to_target_data_route(struct nlmsghdr *nlh)
{ {
uint32_t nlmsg_len; uint32_t nlmsg_len;
struct ifinfomsg *ifi; struct ifinfomsg *ifi;
struct ifaddrmsg *ifa; struct ifaddrmsg *ifa;
struct rtmsg *rtm; struct rtmsg *rtm;
struct ndmsg *ndm;
nlmsg_len = nlh->nlmsg_len; nlmsg_len = nlh->nlmsg_len;
switch (nlh->nlmsg_type) { switch (nlh->nlmsg_type) {
@ -1279,6 +1320,17 @@ static abi_long host_to_target_data_route(struct nlmsghdr *nlh)
nlmsg_len - NLMSG_LENGTH(sizeof(*ifa))); nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
} }
break; 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_NEWROUTE:
case RTM_DELROUTE: case RTM_DELROUTE:
case RTM_GETROUTE: case RTM_GETROUTE:
@ -1426,6 +1478,35 @@ static abi_long target_to_host_data_addr_rtattr(struct rtattr *rtattr)
return 0; 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) static abi_long target_to_host_data_route_rtattr(struct rtattr *rtattr)
{ {
uint32_t *u32; uint32_t *u32;
@ -1464,6 +1545,13 @@ static void target_to_host_addr_rtattr(struct rtattr *rtattr,
target_to_host_data_addr_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, static void target_to_host_route_rtattr(struct rtattr *rtattr,
uint32_t rtattr_len) uint32_t rtattr_len)
{ {
@ -1476,6 +1564,7 @@ static abi_long target_to_host_data_route(struct nlmsghdr *nlh)
struct ifinfomsg *ifi; struct ifinfomsg *ifi;
struct ifaddrmsg *ifa; struct ifaddrmsg *ifa;
struct rtmsg *rtm; struct rtmsg *rtm;
struct ndmsg *ndm;
switch (nlh->nlmsg_type) { switch (nlh->nlmsg_type) {
case RTM_NEWLINK: case RTM_NEWLINK:
@ -1502,6 +1591,17 @@ static abi_long target_to_host_data_route(struct nlmsghdr *nlh)
NLMSG_LENGTH(sizeof(*ifa))); NLMSG_LENGTH(sizeof(*ifa)));
} }
break; 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_NEWROUTE:
case RTM_DELROUTE: case RTM_DELROUTE:
case RTM_GETROUTE: case RTM_GETROUTE: