@@ -25,12 +25,16 @@
#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_IFLA_BR_UNSPEC,
QEMU_IFLA_BR_FORWARD_DELAY,
@@ -1210,6 +1214,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)
{
@@ -1231,12 +1264,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) {
@@ -1263,6 +1304,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:
@@ -1410,6 +1462,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;
@@ -1448,6 +1529,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)
{
@@ -1460,6 +1548,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:
@@ -1486,6 +1575,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: