sd-netlink: save dynamic general netlink message type
This commit is contained in:
parent
2cac03f71d
commit
4e8f0ef921
|
@ -71,6 +71,7 @@ libsystemd_sources = files('''
|
||||||
sd-hwdb/hwdb-util.h
|
sd-hwdb/hwdb-util.h
|
||||||
sd-hwdb/sd-hwdb.c
|
sd-hwdb/sd-hwdb.c
|
||||||
sd-netlink/generic-netlink.c
|
sd-netlink/generic-netlink.c
|
||||||
|
sd-netlink/generic-netlink.h
|
||||||
sd-netlink/netlink-internal.h
|
sd-netlink/netlink-internal.h
|
||||||
sd-netlink/netlink-message.c
|
sd-netlink/netlink-message.c
|
||||||
sd-netlink/netlink-slot.c
|
sd-netlink/netlink-slot.c
|
||||||
|
|
|
@ -3,8 +3,10 @@
|
||||||
#include <linux/genetlink.h>
|
#include <linux/genetlink.h>
|
||||||
|
|
||||||
#include "sd-netlink.h"
|
#include "sd-netlink.h"
|
||||||
#include "netlink-internal.h"
|
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
|
#include "generic-netlink.h"
|
||||||
|
#include "netlink-internal.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char* name;
|
const char* name;
|
||||||
|
@ -25,12 +27,12 @@ int sd_genl_socket_open(sd_netlink **ret) {
|
||||||
static int lookup_id(sd_netlink *nl, sd_genl_family family, uint16_t *id);
|
static int lookup_id(sd_netlink *nl, sd_genl_family family, uint16_t *id);
|
||||||
|
|
||||||
static int genl_message_new(sd_netlink *nl, sd_genl_family family, uint16_t nlmsg_type, uint8_t cmd, sd_netlink_message **ret) {
|
static int genl_message_new(sd_netlink *nl, sd_genl_family family, uint16_t nlmsg_type, uint8_t cmd, sd_netlink_message **ret) {
|
||||||
int r;
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
||||||
struct genlmsghdr *genl;
|
|
||||||
const NLType *genl_cmd_type, *nl_type;
|
const NLType *genl_cmd_type, *nl_type;
|
||||||
const NLTypeSystem *type_system;
|
const NLTypeSystem *type_system;
|
||||||
|
struct genlmsghdr *genl;
|
||||||
size_t size;
|
size_t size;
|
||||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
int r;
|
||||||
|
|
||||||
assert_return(nl->protocol == NETLINK_GENERIC, -EINVAL);
|
assert_return(nl->protocol == NETLINK_GENERIC, -EINVAL);
|
||||||
|
|
||||||
|
@ -69,21 +71,33 @@ static int genl_message_new(sd_netlink *nl, sd_genl_family family, uint16_t nlms
|
||||||
}
|
}
|
||||||
|
|
||||||
int sd_genl_message_new(sd_netlink *nl, sd_genl_family family, uint8_t cmd, sd_netlink_message **ret) {
|
int sd_genl_message_new(sd_netlink *nl, sd_genl_family family, uint8_t cmd, sd_netlink_message **ret) {
|
||||||
|
uint16_t id;
|
||||||
int r;
|
int r;
|
||||||
uint16_t id = GENL_ID_CTRL;
|
|
||||||
|
|
||||||
if (family != SD_GENL_ID_CTRL) {
|
r = lookup_id(nl, family, &id);
|
||||||
r = lookup_id(nl, family, &id);
|
if (r < 0)
|
||||||
if (r < 0)
|
return r;
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
return genl_message_new(nl, family, id, cmd, ret);
|
return genl_message_new(nl, family, id, cmd, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lookup_id(sd_netlink *nl, sd_genl_family family, uint16_t *id) {
|
static int lookup_id(sd_netlink *nl, sd_genl_family family, uint16_t *id) {
|
||||||
int r;
|
|
||||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
|
||||||
|
uint16_t u;
|
||||||
|
void *v;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (family == SD_GENL_ID_CTRL) {
|
||||||
|
*id = GENL_ID_CTRL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
v = hashmap_get(nl->genl_family_to_nlmsg_type, INT_TO_PTR(family));
|
||||||
|
if (v) {
|
||||||
|
*id = PTR_TO_UINT(v);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
r = sd_genl_message_new(nl, SD_GENL_ID_CTRL, CTRL_CMD_GETFAMILY, &req);
|
r = sd_genl_message_new(nl, SD_GENL_ID_CTRL, CTRL_CMD_GETFAMILY, &req);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -97,5 +111,48 @@ static int lookup_id(sd_netlink *nl, sd_genl_family family, uint16_t *id) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
return sd_netlink_message_read_u16(reply, CTRL_ATTR_FAMILY_ID, id);
|
r = sd_netlink_message_read_u16(reply, CTRL_ATTR_FAMILY_ID, &u);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = hashmap_ensure_allocated(&nl->genl_family_to_nlmsg_type, NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = hashmap_ensure_allocated(&nl->nlmsg_type_to_genl_family, NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = hashmap_put(nl->genl_family_to_nlmsg_type, INT_TO_PTR(family), UINT_TO_PTR(u));
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = hashmap_put(nl->nlmsg_type_to_genl_family, UINT_TO_PTR(u), INT_TO_PTR(family));
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
*id = u;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nlmsg_type_to_genl_family(sd_netlink *nl, uint16_t type, sd_genl_family *ret) {
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
assert_return(nl, -EINVAL);
|
||||||
|
assert_return(nl->protocol == NETLINK_GENERIC, -EINVAL);
|
||||||
|
assert(ret);
|
||||||
|
|
||||||
|
if (type == NLMSG_ERROR)
|
||||||
|
*ret = SD_GENL_ERROR;
|
||||||
|
else if (type == GENL_ID_CTRL)
|
||||||
|
*ret = SD_GENL_ID_CTRL;
|
||||||
|
else {
|
||||||
|
p = hashmap_get(nl->nlmsg_type_to_genl_family, UINT_TO_PTR(type));
|
||||||
|
if (!p)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
*ret = PTR_TO_INT(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
6
src/libsystemd/sd-netlink/generic-netlink.h
Normal file
6
src/libsystemd/sd-netlink/generic-netlink.h
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "sd-netlink.h"
|
||||||
|
|
||||||
|
int nlmsg_type_to_genl_family(sd_netlink *nl, uint16_t type, sd_genl_family *ret);
|
|
@ -98,6 +98,9 @@ struct sd_netlink {
|
||||||
sd_event_source *time_event_source;
|
sd_event_source *time_event_source;
|
||||||
sd_event_source *exit_event_source;
|
sd_event_source *exit_event_source;
|
||||||
sd_event *event;
|
sd_event *event;
|
||||||
|
|
||||||
|
Hashmap *genl_family_to_nlmsg_type;
|
||||||
|
Hashmap *nlmsg_type_to_genl_family;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct netlink_attribute {
|
struct netlink_attribute {
|
||||||
|
|
|
@ -49,15 +49,12 @@ int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret) {
|
||||||
int message_new(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t type) {
|
int message_new(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t type) {
|
||||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
||||||
const NLType *nl_type;
|
const NLType *nl_type;
|
||||||
const NLTypeSystem *type_system_root;
|
|
||||||
size_t size;
|
size_t size;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert_return(rtnl, -EINVAL);
|
assert_return(rtnl, -EINVAL);
|
||||||
|
|
||||||
type_system_root = type_system_get_root(rtnl->protocol);
|
r = type_system_root_get_type(rtnl, &nl_type, type);
|
||||||
|
|
||||||
r = type_system_get_type(type_system_root, &nl_type, type);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -1025,22 +1022,20 @@ int sd_netlink_message_get_errno(sd_netlink_message *m) {
|
||||||
return err->error;
|
return err->error;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sd_netlink_message_rewind(sd_netlink_message *m) {
|
int sd_netlink_message_rewind(sd_netlink_message *m, sd_netlink *genl) {
|
||||||
const NLType *nl_type;
|
const NLType *nl_type;
|
||||||
const NLTypeSystem *type_system_root;
|
|
||||||
uint16_t type;
|
uint16_t type;
|
||||||
size_t size;
|
size_t size;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert_return(m, -EINVAL);
|
assert_return(m, -EINVAL);
|
||||||
|
assert_return(genl || m->protocol != NETLINK_GENERIC, -EINVAL);
|
||||||
|
|
||||||
/* don't allow appending to message once parsed */
|
/* don't allow appending to message once parsed */
|
||||||
if (!m->sealed)
|
if (!m->sealed)
|
||||||
rtnl_message_seal(m);
|
rtnl_message_seal(m);
|
||||||
|
|
||||||
type_system_root = type_system_get_root(m->protocol);
|
|
||||||
|
|
||||||
for (i = 1; i <= m->n_containers; i++)
|
for (i = 1; i <= m->n_containers; i++)
|
||||||
m->containers[i].attributes = mfree(m->containers[i].attributes);
|
m->containers[i].attributes = mfree(m->containers[i].attributes);
|
||||||
|
|
||||||
|
@ -1052,7 +1047,7 @@ int sd_netlink_message_rewind(sd_netlink_message *m) {
|
||||||
|
|
||||||
assert(m->hdr);
|
assert(m->hdr);
|
||||||
|
|
||||||
r = type_system_get_type(type_system_root, &nl_type, m->hdr->nlmsg_type);
|
r = type_system_root_get_type(genl, &nl_type, m->hdr->nlmsg_type);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
|
|
@ -313,14 +313,11 @@ int socket_read_message(sd_netlink *rtnl) {
|
||||||
size_t len;
|
size_t len;
|
||||||
int r;
|
int r;
|
||||||
unsigned i = 0;
|
unsigned i = 0;
|
||||||
const NLTypeSystem *type_system_root;
|
|
||||||
|
|
||||||
assert(rtnl);
|
assert(rtnl);
|
||||||
assert(rtnl->rbuffer);
|
assert(rtnl->rbuffer);
|
||||||
assert(rtnl->rbuffer_allocated >= sizeof(struct nlmsghdr));
|
assert(rtnl->rbuffer_allocated >= sizeof(struct nlmsghdr));
|
||||||
|
|
||||||
type_system_root = type_system_get_root(rtnl->protocol);
|
|
||||||
|
|
||||||
/* read nothing, just get the pending message size */
|
/* read nothing, just get the pending message size */
|
||||||
r = socket_recv_message(rtnl->fd, &iov, NULL, true);
|
r = socket_recv_message(rtnl->fd, &iov, NULL, true);
|
||||||
if (r <= 0)
|
if (r <= 0)
|
||||||
|
@ -381,7 +378,7 @@ int socket_read_message(sd_netlink *rtnl) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check that we support this message type */
|
/* check that we support this message type */
|
||||||
r = type_system_get_type(type_system_root, &nl_type, new_msg->nlmsg_type);
|
r = type_system_root_get_type(rtnl, &nl_type, new_msg->nlmsg_type);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
if (r == -EOPNOTSUPP)
|
if (r == -EOPNOTSUPP)
|
||||||
log_debug("sd-netlink: ignored message with unknown type: %i",
|
log_debug("sd-netlink: ignored message with unknown type: %i",
|
||||||
|
@ -407,7 +404,7 @@ int socket_read_message(sd_netlink *rtnl) {
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
/* seal and parse the top-level message */
|
/* seal and parse the top-level message */
|
||||||
r = sd_netlink_message_rewind(m);
|
r = sd_netlink_message_rewind(m, rtnl);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
|
|
@ -23,10 +23,14 @@
|
||||||
#include <linux/veth.h>
|
#include <linux/veth.h>
|
||||||
#include <linux/wireguard.h>
|
#include <linux/wireguard.h>
|
||||||
|
|
||||||
|
#include "sd-netlink.h"
|
||||||
|
|
||||||
|
#include "generic-netlink.h"
|
||||||
|
#include "hashmap.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
#include "missing.h"
|
#include "missing.h"
|
||||||
|
#include "netlink-internal.h"
|
||||||
#include "netlink-types.h"
|
#include "netlink-types.h"
|
||||||
#include "sd-netlink.h"
|
|
||||||
#include "string-table.h"
|
#include "string-table.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
@ -992,16 +996,18 @@ static const NLType genl_families[] = {
|
||||||
[SD_GENL_MACSEC] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_macsec_device_type_system },
|
[SD_GENL_MACSEC] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_macsec_device_type_system },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Mainly used when sending message */
|
||||||
const NLTypeSystem genl_family_type_system_root = {
|
const NLTypeSystem genl_family_type_system_root = {
|
||||||
.count = ELEMENTSOF(genl_families),
|
.count = ELEMENTSOF(genl_families),
|
||||||
.types = genl_families,
|
.types = genl_families,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const NLType genl_types[] = {
|
static const NLType genl_types[] = {
|
||||||
[NLMSG_ERROR] = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system, .size = sizeof(struct nlmsgerr) },
|
[SD_GENL_ERROR] = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system, .size = sizeof(struct nlmsgerr) },
|
||||||
[GENL_ID_CTRL] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_get_family_type_system, .size = sizeof(struct genlmsghdr) },
|
[SD_GENL_ID_CTRL] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_get_family_type_system, .size = sizeof(struct genlmsghdr) },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Mainly used when message received */
|
||||||
const NLTypeSystem genl_type_system_root = {
|
const NLTypeSystem genl_type_system_root = {
|
||||||
.count = ELEMENTSOF(genl_types),
|
.count = ELEMENTSOF(genl_types),
|
||||||
.types = genl_types,
|
.types = genl_types,
|
||||||
|
@ -1049,6 +1055,31 @@ const NLTypeSystem *type_system_get_root(int protocol) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int type_system_root_get_type(sd_netlink *nl, const NLType **ret, uint16_t type) {
|
||||||
|
sd_genl_family family;
|
||||||
|
const NLType *nl_type;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (!nl || nl->protocol != NETLINK_GENERIC)
|
||||||
|
return type_system_get_type(&rtnl_type_system_root, ret, type);
|
||||||
|
|
||||||
|
r = nlmsg_type_to_genl_family(nl, type, &family);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (family >= genl_type_system_root.count)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
nl_type = &genl_type_system_root.types[family];
|
||||||
|
|
||||||
|
if (nl_type->type == NETLINK_TYPE_UNSPEC)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
*ret = nl_type;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int type_system_get_type(const NLTypeSystem *type_system, const NLType **ret, uint16_t type) {
|
int type_system_get_type(const NLTypeSystem *type_system, const NLType **ret, uint16_t type) {
|
||||||
const NLType *nl_type;
|
const NLType *nl_type;
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,7 @@ void type_get_type_system_union(const NLType *type, const NLTypeSystemUnion **re
|
||||||
|
|
||||||
const NLTypeSystem* type_system_get_root(int protocol);
|
const NLTypeSystem* type_system_get_root(int protocol);
|
||||||
uint16_t type_system_get_count(const NLTypeSystem *type_system);
|
uint16_t type_system_get_count(const NLTypeSystem *type_system);
|
||||||
|
int type_system_root_get_type(sd_netlink *nl, const NLType **ret, uint16_t type);
|
||||||
int type_system_get_type(const NLTypeSystem *type_system, const NLType **ret, uint16_t type);
|
int type_system_get_type(const NLTypeSystem *type_system, const NLType **ret, uint16_t type);
|
||||||
int type_system_get_type_system(const NLTypeSystem *type_system, const NLTypeSystem **ret, uint16_t type);
|
int type_system_get_type_system(const NLTypeSystem *type_system, const NLTypeSystem **ret, uint16_t type);
|
||||||
int type_system_get_type_system_union(const NLTypeSystem *type_system, const NLTypeSystemUnion **ret, uint16_t type);
|
int type_system_get_type_system_union(const NLTypeSystem *type_system, const NLTypeSystemUnion **ret, uint16_t type);
|
||||||
|
|
|
@ -178,6 +178,9 @@ static sd_netlink *netlink_free(sd_netlink *rtnl) {
|
||||||
|
|
||||||
hashmap_free(rtnl->broadcast_group_refs);
|
hashmap_free(rtnl->broadcast_group_refs);
|
||||||
|
|
||||||
|
hashmap_free(rtnl->genl_family_to_nlmsg_type);
|
||||||
|
hashmap_free(rtnl->nlmsg_type_to_genl_family);
|
||||||
|
|
||||||
safe_close(rtnl->fd);
|
safe_close(rtnl->fd);
|
||||||
return mfree(rtnl);
|
return mfree(rtnl);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ static void test_message_link_bridge(sd_netlink *rtnl) {
|
||||||
assert_se(sd_netlink_message_append_u32(message, IFLA_BRPORT_COST, 10) >= 0);
|
assert_se(sd_netlink_message_append_u32(message, IFLA_BRPORT_COST, 10) >= 0);
|
||||||
assert_se(sd_netlink_message_close_container(message) >= 0);
|
assert_se(sd_netlink_message_close_container(message) >= 0);
|
||||||
|
|
||||||
assert_se(sd_netlink_message_rewind(message) >= 0);
|
assert_se(sd_netlink_message_rewind(message, NULL) >= 0);
|
||||||
|
|
||||||
assert_se(sd_netlink_message_enter_container(message, IFLA_PROTINFO) >= 0);
|
assert_se(sd_netlink_message_enter_container(message, IFLA_PROTINFO) >= 0);
|
||||||
assert_se(sd_netlink_message_read_u32(message, IFLA_BRPORT_COST, &cost) >= 0);
|
assert_se(sd_netlink_message_read_u32(message, IFLA_BRPORT_COST, &cost) >= 0);
|
||||||
|
@ -49,7 +49,7 @@ static void test_link_configure(sd_netlink *rtnl, int ifindex) {
|
||||||
assert_se(sd_netlink_message_append_u32(message, IFLA_MTU, mtu) >= 0);
|
assert_se(sd_netlink_message_append_u32(message, IFLA_MTU, mtu) >= 0);
|
||||||
|
|
||||||
assert_se(sd_netlink_call(rtnl, message, 0, NULL) == 1);
|
assert_se(sd_netlink_call(rtnl, message, 0, NULL) == 1);
|
||||||
assert_se(sd_netlink_message_rewind(message) >= 0);
|
assert_se(sd_netlink_message_rewind(message, NULL) >= 0);
|
||||||
|
|
||||||
assert_se(sd_netlink_message_read_string(message, IFLA_IFNAME, &name_out) >= 0);
|
assert_se(sd_netlink_message_read_string(message, IFLA_IFNAME, &name_out) >= 0);
|
||||||
assert_se(streq(name, name_out));
|
assert_se(streq(name, name_out));
|
||||||
|
@ -153,7 +153,7 @@ static void test_route(sd_netlink *rtnl) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_se(sd_netlink_message_rewind(req) >= 0);
|
assert_se(sd_netlink_message_rewind(req, NULL) >= 0);
|
||||||
|
|
||||||
assert_se(sd_netlink_message_read_in_addr(req, RTA_GATEWAY, &addr_data) >= 0);
|
assert_se(sd_netlink_message_read_in_addr(req, RTA_GATEWAY, &addr_data) >= 0);
|
||||||
assert_se(addr_data.s_addr == addr.s_addr);
|
assert_se(addr_data.s_addr == addr.s_addr);
|
||||||
|
@ -439,7 +439,7 @@ static void test_container(sd_netlink *rtnl) {
|
||||||
assert_se(sd_netlink_message_close_container(m) >= 0);
|
assert_se(sd_netlink_message_close_container(m) >= 0);
|
||||||
assert_se(sd_netlink_message_close_container(m) == -EINVAL);
|
assert_se(sd_netlink_message_close_container(m) == -EINVAL);
|
||||||
|
|
||||||
assert_se(sd_netlink_message_rewind(m) >= 0);
|
assert_se(sd_netlink_message_rewind(m, NULL) >= 0);
|
||||||
|
|
||||||
assert_se(sd_netlink_message_enter_container(m, IFLA_LINKINFO) >= 0);
|
assert_se(sd_netlink_message_enter_container(m, IFLA_LINKINFO) >= 0);
|
||||||
assert_se(sd_netlink_message_read_string(m, IFLA_INFO_KIND, &string_data) >= 0);
|
assert_se(sd_netlink_message_read_string(m, IFLA_INFO_KIND, &string_data) >= 0);
|
||||||
|
@ -530,7 +530,7 @@ static void test_array(void) {
|
||||||
assert_se(sd_netlink_message_close_container(m) >= 0);
|
assert_se(sd_netlink_message_close_container(m) >= 0);
|
||||||
|
|
||||||
rtnl_message_seal(m);
|
rtnl_message_seal(m);
|
||||||
assert_se(sd_netlink_message_rewind(m) >= 0);
|
assert_se(sd_netlink_message_rewind(m, genl) >= 0);
|
||||||
|
|
||||||
assert_se(sd_netlink_message_enter_container(m, CTRL_ATTR_MCAST_GROUPS) >= 0);
|
assert_se(sd_netlink_message_enter_container(m, CTRL_ATTR_MCAST_GROUPS) >= 0);
|
||||||
for (unsigned i = 0; i < 10; i++) {
|
for (unsigned i = 0; i < 10; i++) {
|
||||||
|
|
|
@ -35,6 +35,7 @@ typedef struct sd_netlink_message sd_netlink_message;
|
||||||
typedef struct sd_netlink_slot sd_netlink_slot;
|
typedef struct sd_netlink_slot sd_netlink_slot;
|
||||||
|
|
||||||
typedef enum sd_gen_family {
|
typedef enum sd_gen_family {
|
||||||
|
SD_GENL_ERROR,
|
||||||
SD_GENL_ID_CTRL,
|
SD_GENL_ID_CTRL,
|
||||||
SD_GENL_WIREGUARD,
|
SD_GENL_WIREGUARD,
|
||||||
SD_GENL_FOU,
|
SD_GENL_FOU,
|
||||||
|
@ -111,7 +112,7 @@ int sd_netlink_message_exit_container(sd_netlink_message *m);
|
||||||
int sd_netlink_message_open_array(sd_netlink_message *m, uint16_t type);
|
int sd_netlink_message_open_array(sd_netlink_message *m, uint16_t type);
|
||||||
int sd_netlink_message_cancel_array(sd_netlink_message *m);
|
int sd_netlink_message_cancel_array(sd_netlink_message *m);
|
||||||
|
|
||||||
int sd_netlink_message_rewind(sd_netlink_message *m);
|
int sd_netlink_message_rewind(sd_netlink_message *m, sd_netlink *genl);
|
||||||
|
|
||||||
sd_netlink_message *sd_netlink_message_next(sd_netlink_message *m);
|
sd_netlink_message *sd_netlink_message_next(sd_netlink_message *m);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue