sd-netlink: allow configuration of flags parameter when creating message object
We soon want to add for sock_diag(7) netlink sockets. Those reuse the same message type codes for request and response but with different message formats. Hence we need to look at NLM_F_REQUEST to determine which message policy to apply. Hence it is essential to know the flags parameters right away when creating a message, since we cannot do early validation otherwise. This only adds support for setting the flags value right at the moment of creation of the message object, it does not otherwise add sock_diag(7) support, that is added in a later message. This also corrects the flag for synthetic NLMSG_ERROR messages which should not have the NLM_F_REQUEST flag set (since they are responses, not requests).
This commit is contained in:
@@ -244,7 +244,7 @@ static int genl_message_new(
|
||||
if (!policy_set)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
r = message_new_full(nl, family->id, policy_set,
|
||||
r = message_new_full(nl, family->id, NLM_F_REQUEST | NLM_F_ACK, policy_set,
|
||||
sizeof(struct genlmsghdr) + family->additional_header_size, &m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -131,10 +131,11 @@ int message_new_empty(sd_netlink *nl, sd_netlink_message **ret);
|
||||
int message_new_full(
|
||||
sd_netlink *nl,
|
||||
uint16_t nlmsg_type,
|
||||
uint16_t nlmsg_flags,
|
||||
const NLAPolicySet *policy_set,
|
||||
size_t header_size,
|
||||
sd_netlink_message **ret);
|
||||
int message_new(sd_netlink *nl, sd_netlink_message **ret, uint16_t type);
|
||||
int message_new(sd_netlink *nl, sd_netlink_message **ret, uint16_t type, uint16_t flags);
|
||||
int message_new_synthetic_error(sd_netlink *nl, int error, uint32_t serial, sd_netlink_message **ret);
|
||||
|
||||
static inline uint32_t message_get_serial(sd_netlink_message *m) {
|
||||
|
||||
@@ -34,7 +34,7 @@ int sd_nfnl_message_new(sd_netlink *nfnl, sd_netlink_message **ret, int nfproto,
|
||||
assert_return(nfproto_is_valid(nfproto), -EINVAL);
|
||||
assert_return(NFNL_MSG_TYPE(msg_type) == msg_type, -EINVAL);
|
||||
|
||||
r = message_new(nfnl, &m, subsys << 8 | msg_type);
|
||||
r = message_new(nfnl, &m, subsys << 8 | msg_type, NLM_F_REQUEST | NLM_F_ACK);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
@@ -244,13 +244,13 @@ int sd_rtnl_message_new_route(
|
||||
IN_SET(family, AF_INET, AF_INET6), -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
r = message_new(rtnl, ret, nlmsg_type);
|
||||
r = message_new(rtnl,
|
||||
ret,
|
||||
nlmsg_type,
|
||||
NLM_F_REQUEST|NLM_F_ACK|(nlmsg_type == RTM_NEWROUTE ? NLM_F_CREATE | NLM_F_APPEND : 0));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (nlmsg_type == RTM_NEWROUTE)
|
||||
(*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_APPEND;
|
||||
|
||||
rtm = NLMSG_DATA((*ret)->hdr);
|
||||
|
||||
rtm->rtm_family = family;
|
||||
@@ -281,13 +281,13 @@ int sd_rtnl_message_new_nexthop(sd_netlink *rtnl, sd_netlink_message **ret,
|
||||
}
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
r = message_new(rtnl, ret, nlmsg_type);
|
||||
r = message_new(rtnl,
|
||||
ret,
|
||||
nlmsg_type,
|
||||
NLM_F_REQUEST | NLM_F_ACK | (nlmsg_type == RTM_NEWNEXTHOP ? NLM_F_CREATE | NLM_F_REPLACE : 0));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (nlmsg_type == RTM_NEWNEXTHOP)
|
||||
(*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
|
||||
|
||||
nhm = NLMSG_DATA((*ret)->hdr);
|
||||
|
||||
nhm->nh_family = family;
|
||||
@@ -311,17 +311,18 @@ int sd_rtnl_message_new_neigh(
|
||||
assert_return(IN_SET(family, AF_UNSPEC, AF_INET, AF_INET6, AF_BRIDGE), -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
r = message_new(rtnl, ret, nlmsg_type);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||
if (nlmsg_type == RTM_NEWNEIGH) {
|
||||
if (family == AF_BRIDGE)
|
||||
(*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_APPEND;
|
||||
flags |= NLM_F_CREATE | NLM_F_APPEND;
|
||||
else
|
||||
(*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
|
||||
flags |= NLM_F_CREATE | NLM_F_REPLACE;
|
||||
}
|
||||
|
||||
r = message_new(rtnl, ret, nlmsg_type, flags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
ndm = NLMSG_DATA((*ret)->hdr);
|
||||
|
||||
ndm->ndm_family = family;
|
||||
@@ -337,15 +338,16 @@ int sd_rtnl_message_new_link(sd_netlink *rtnl, sd_netlink_message **ret, uint16_
|
||||
assert_return(rtnl_message_type_is_link(nlmsg_type), -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
r = message_new(rtnl, ret, nlmsg_type);
|
||||
uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||
if (nlmsg_type == RTM_NEWLINK && ifindex == 0)
|
||||
flags |= NLM_F_CREATE | NLM_F_EXCL;
|
||||
else if (nlmsg_type == RTM_NEWLINKPROP)
|
||||
flags |= NLM_F_CREATE | NLM_F_EXCL | NLM_F_APPEND;
|
||||
|
||||
r = message_new(rtnl, ret, nlmsg_type, flags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (nlmsg_type == RTM_NEWLINK && ifindex == 0)
|
||||
(*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
|
||||
else if (nlmsg_type == RTM_NEWLINKPROP)
|
||||
(*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL | NLM_F_APPEND;
|
||||
|
||||
ifi = NLMSG_DATA((*ret)->hdr);
|
||||
|
||||
ifi->ifi_family = AF_UNSPEC;
|
||||
@@ -371,7 +373,7 @@ int sd_rtnl_message_new_addr(
|
||||
IN_SET(family, AF_INET, AF_INET6), -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
r = message_new(rtnl, ret, nlmsg_type);
|
||||
r = message_new(rtnl, ret, nlmsg_type, NLM_F_REQUEST | NLM_F_ACK);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -439,13 +441,13 @@ int sd_rtnl_message_new_addrlabel(
|
||||
assert_return(rtnl_message_type_is_addrlabel(nlmsg_type), -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
r = message_new(rtnl, ret, nlmsg_type);
|
||||
r = message_new(rtnl,
|
||||
ret,
|
||||
nlmsg_type,
|
||||
NLM_F_REQUEST | NLM_F_ACK | (nlmsg_type == RTM_NEWADDRLABEL ? NLM_F_CREATE | NLM_F_REPLACE : 0));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (nlmsg_type == RTM_NEWADDRLABEL)
|
||||
(*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
|
||||
|
||||
addrlabel = NLMSG_DATA((*ret)->hdr);
|
||||
|
||||
addrlabel->ifal_family = family;
|
||||
@@ -466,13 +468,13 @@ int sd_rtnl_message_new_routing_policy_rule(
|
||||
assert_return(rtnl_message_type_is_routing_policy_rule(nlmsg_type), -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
r = message_new(rtnl, ret, nlmsg_type);
|
||||
r = message_new(rtnl,
|
||||
ret,
|
||||
nlmsg_type,
|
||||
NLM_F_REQUEST | NLM_F_ACK | (nlmsg_type == RTM_NEWRULE ? NLM_F_CREATE | NLM_F_EXCL : 0));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (nlmsg_type == RTM_NEWRULE)
|
||||
(*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
|
||||
|
||||
frh = NLMSG_DATA((*ret)->hdr);
|
||||
frh->family = family;
|
||||
|
||||
@@ -493,13 +495,13 @@ int sd_rtnl_message_new_traffic_control(
|
||||
assert_return(rtnl_message_type_is_traffic_control(nlmsg_type), -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
r = message_new(rtnl, ret, nlmsg_type);
|
||||
r = message_new(rtnl,
|
||||
ret,
|
||||
nlmsg_type,
|
||||
NLM_F_REQUEST | NLM_F_ACK | (IN_SET(nlmsg_type, RTM_NEWQDISC, RTM_NEWTCLASS) ? NLM_F_CREATE | NLM_F_REPLACE : 0));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (IN_SET(nlmsg_type, RTM_NEWQDISC, RTM_NEWTCLASS))
|
||||
(*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
|
||||
|
||||
tcm = NLMSG_DATA((*ret)->hdr);
|
||||
tcm->tcm_ifindex = ifindex;
|
||||
tcm->tcm_handle = handle;
|
||||
@@ -520,13 +522,13 @@ int sd_rtnl_message_new_mdb(
|
||||
assert_return(rtnl_message_type_is_mdb(nlmsg_type), -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
r = message_new(rtnl, ret, nlmsg_type);
|
||||
r = message_new(rtnl,
|
||||
ret,
|
||||
nlmsg_type,
|
||||
NLM_F_REQUEST | NLM_F_ACK | (nlmsg_type == RTM_NEWMDB ? NLM_F_CREATE | NLM_F_REPLACE : 0));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (nlmsg_type == RTM_NEWMDB)
|
||||
(*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
|
||||
|
||||
bpm = NLMSG_DATA((*ret)->hdr);
|
||||
bpm->family = AF_BRIDGE;
|
||||
bpm->ifindex = ifindex;
|
||||
@@ -545,7 +547,7 @@ int sd_rtnl_message_new_nsid(
|
||||
assert_return(rtnl_message_type_is_nsid(nlmsg_type), -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
r = message_new(rtnl, ret, nlmsg_type);
|
||||
r = message_new(rtnl, ret, nlmsg_type, NLM_F_REQUEST | NLM_F_ACK);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ int message_new_empty(sd_netlink *nl, sd_netlink_message **ret) {
|
||||
int message_new_full(
|
||||
sd_netlink *nl,
|
||||
uint16_t nlmsg_type,
|
||||
uint16_t nlmsg_flags,
|
||||
const NLAPolicySet *policy_set,
|
||||
size_t header_size,
|
||||
sd_netlink_message **ret) {
|
||||
@@ -69,7 +70,7 @@ int message_new_full(
|
||||
if (!m->hdr)
|
||||
return -ENOMEM;
|
||||
|
||||
m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||
m->hdr->nlmsg_flags = nlmsg_flags;
|
||||
m->hdr->nlmsg_len = size;
|
||||
m->hdr->nlmsg_type = nlmsg_type;
|
||||
|
||||
@@ -77,7 +78,7 @@ int message_new_full(
|
||||
return 0;
|
||||
}
|
||||
|
||||
int message_new(sd_netlink *nl, sd_netlink_message **ret, uint16_t nlmsg_type) {
|
||||
int message_new(sd_netlink *nl, sd_netlink_message **ret, uint16_t nlmsg_type, uint16_t nlmsg_flags) {
|
||||
const NLAPolicySet *policy_set;
|
||||
size_t size;
|
||||
int r;
|
||||
@@ -85,11 +86,11 @@ int message_new(sd_netlink *nl, sd_netlink_message **ret, uint16_t nlmsg_type) {
|
||||
assert_return(nl, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
r = netlink_get_policy_set_and_header_size(nl, nlmsg_type, &policy_set, &size);
|
||||
r = netlink_get_policy_set_and_header_size(nl, nlmsg_type, nlmsg_flags, &policy_set, &size);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return message_new_full(nl, nlmsg_type, policy_set, size, ret);
|
||||
return message_new_full(nl, nlmsg_type, nlmsg_flags, policy_set, size, ret);
|
||||
}
|
||||
|
||||
int message_new_synthetic_error(sd_netlink *nl, int error, uint32_t serial, sd_netlink_message **ret) {
|
||||
@@ -98,7 +99,7 @@ int message_new_synthetic_error(sd_netlink *nl, int error, uint32_t serial, sd_n
|
||||
|
||||
assert(error <= 0);
|
||||
|
||||
r = message_new(nl, ret, NLMSG_ERROR);
|
||||
r = message_new(nl, ret, NLMSG_ERROR, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -1328,8 +1329,12 @@ int sd_netlink_message_rewind(sd_netlink_message *m, sd_netlink *nl) {
|
||||
|
||||
assert(m->hdr);
|
||||
|
||||
r = netlink_get_policy_set_and_header_size(nl, m->hdr->nlmsg_type,
|
||||
&m->containers[0].policy_set, &size);
|
||||
r = netlink_get_policy_set_and_header_size(
|
||||
nl,
|
||||
m->hdr->nlmsg_type,
|
||||
m->hdr->nlmsg_flags,
|
||||
&m->containers[0].policy_set,
|
||||
&size);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
@@ -307,7 +307,7 @@ static int parse_message_one(sd_netlink *nl, uint32_t group, const struct nlmsgh
|
||||
goto finalize;
|
||||
|
||||
/* check that we support this message type */
|
||||
r = netlink_get_policy_set_and_header_size(nl, hdr->nlmsg_type, NULL, &size);
|
||||
r = netlink_get_policy_set_and_header_size(nl, hdr->nlmsg_type, hdr->nlmsg_flags, NULL, &size);
|
||||
if (r == -EOPNOTSUPP) {
|
||||
log_debug("sd-netlink: ignored message with unknown type: %i", hdr->nlmsg_type);
|
||||
goto finalize;
|
||||
|
||||
@@ -51,6 +51,7 @@ const NLAPolicySetUnion *policy_get_policy_set_union(const NLAPolicy *policy) {
|
||||
int netlink_get_policy_set_and_header_size(
|
||||
sd_netlink *nl,
|
||||
uint16_t type,
|
||||
uint16_t flags,
|
||||
const NLAPolicySet **ret_policy_set,
|
||||
size_t *ret_header_size) {
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@ const NLAPolicySetUnion *policy_get_policy_set_union(const NLAPolicy *policy);
|
||||
int netlink_get_policy_set_and_header_size(
|
||||
sd_netlink *nl,
|
||||
uint16_t type,
|
||||
uint16_t flags,
|
||||
const NLAPolicySet **ret_policy_set,
|
||||
size_t *ret_header_size);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user