***/
#include <netinet/in.h>
-#include <netinet/ether.h>
#include <stdbool.h>
#include <unistd.h>
assert_return(ret, -EINVAL);
- /* Note that 'rtnl' is curretly unused, if we start using it internally
+ /* Note that 'rtnl' is currently unused, if we start using it internally
we must take care to avoid problems due to mutual references between
busses and their queued messages. See sd-bus.
*/
if (r < 0)
return r;
- assert(nl_type->type == NLA_NESTED);
-
r = message_new_empty(rtnl, &m);
if (r < 0)
return r;
}
sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) {
- if (m && REFCNT_DEC(m->n_ref) <= 0) {
+ if (m && REFCNT_DEC(m->n_ref) == 0) {
unsigned i;
free(m->hdr);
return 0;
}
+int sd_rtnl_message_get_family(sd_rtnl_message *m, int *family) {
+ assert_return(m, -EINVAL);
+ assert_return(family, -EINVAL);
+
+ assert(m->hdr);
+
+ if (rtnl_message_type_is_link(m->hdr->nlmsg_type)) {
+ struct ifinfomsg *ifi;
+
+ ifi = NLMSG_DATA(m->hdr);
+
+ *family = ifi->ifi_family;
+
+ return 0;
+ } else if (rtnl_message_type_is_route(m->hdr->nlmsg_type)) {
+ struct rtmsg *rtm;
+
+ rtm = NLMSG_DATA(m->hdr);
+
+ *family = rtm->rtm_family;
+
+ return 0;
+ } else if (rtnl_message_type_is_neigh(m->hdr->nlmsg_type)) {
+ struct ndmsg *ndm;
+
+ ndm = NLMSG_DATA(m->hdr);
+
+ *family = ndm->ndm_family;
+
+ return 0;
+ } else if (rtnl_message_type_is_addr(m->hdr->nlmsg_type)) {
+ struct ifaddrmsg *ifa;
+
+ ifa = NLMSG_DATA(m->hdr);
+
+ *family = ifa->ifa_family;
+
+ return 0;
+ }
+
+ return -EOPNOTSUPP;
+}
+
int sd_rtnl_message_is_broadcast(sd_rtnl_message *m) {
assert_return(m, -EINVAL);
assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -ERANGE);
r = message_attribute_has_type(m, type, NLA_NESTED);
- if (r < 0)
- return r;
- else
+ if (r < 0) {
+ const NLTypeSystemUnion *type_system_union;
+ int family;
+
+ r = message_attribute_has_type(m, type, NLA_UNION);
+ if (r < 0)
+ return r;
+ size = (size_t) r;
+
+ r = sd_rtnl_message_get_family(m, &family);
+ if (r < 0)
+ return r;
+
+ r = type_system_get_type_system_union(m->container_type_system[m->n_containers], &type_system_union, type);
+ if (r < 0)
+ return r;
+
+ r = type_system_union_protocol_get_type_system(type_system_union,
+ &m->container_type_system[m->n_containers + 1],
+ family);
+ if (r < 0)
+ return r;
+ } else {
size = (size_t)r;
- r = type_system_get_type_system(m->container_type_system[m->n_containers],
- &m->container_type_system[m->n_containers + 1],
- type);
- if (r < 0)
- return r;
+ r = type_system_get_type_system(m->container_type_system[m->n_containers],
+ &m->container_type_system[m->n_containers + 1],
+ type);
+ if (r < 0)
+ return r;
+ }
r = add_rtattr(m, type | NLA_F_NESTED, NULL, size);
if (r < 0)
return r;
} else if (nl_type->type == NLA_UNION) {
const NLTypeSystemUnion *type_system_union;
- const char *key;
r = type_system_get_type_system_union(m->container_type_system[m->n_containers],
&type_system_union,
if (r < 0)
return r;
- r = sd_rtnl_message_read_string(m, type_system_union->match, &key);
- if (r < 0)
- return r;
+ switch (type_system_union->match_type) {
+ case NL_MATCH_SIBLING:
+ {
+ const char *key;
- r = type_system_union_get_type_system(type_system_union,
- &type_system,
- key);
- if (r < 0)
- return r;
+ r = sd_rtnl_message_read_string(m, type_system_union->match, &key);
+ if (r < 0)
+ return r;
+
+ r = type_system_union_get_type_system(type_system_union,
+ &type_system,
+ key);
+ if (r < 0)
+ return r;
+
+ break;
+ }
+ case NL_MATCH_PROTOCOL:
+ {
+ int family;
+
+ r = sd_rtnl_message_get_family(m, &family);
+ if (r < 0)
+ return r;
+
+ r = type_system_union_protocol_get_type_system(type_system_union,
+ &type_system,
+ family);
+ if (r < 0)
+ return r;
+
+ break;
+ }
+ default:
+ assert_not_reached("sd-rtnl: invalid type system union type");
+ }
} else
return -EINVAL;
log_debug("rtnl: no data in socket");
return (errno == EAGAIN || errno == EINTR) ? 0 : -errno;
- } else if (r == 0)
- /* connection was closed by the kernel */
- return -ECONNRESET;
+ }
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
if (cmsg->cmsg_level == SOL_SOCKET &&
struct ucred *ucred = (void *)CMSG_DATA(cmsg);
/* from the kernel */
- if (ucred->uid == 0 && ucred->pid == 0)
+ if (ucred->pid == 0)
auth = true;
else
- log_debug("rtnl: ignoring message from uid %u pid %u", ucred->uid, ucred->pid);
+ log_debug("rtnl: ignoring message from PID "PID_FMT, ucred->pid);
} else if (cmsg->cmsg_level == SOL_NETLINK &&
cmsg->cmsg_type == NETLINK_PKTINFO &&
cmsg->cmsg_len == CMSG_LEN(sizeof(struct nl_pktinfo))) {
}
}
- if (!auth)
+ if (!auth) {
/* not from the kernel, ignore */
+ if (peek) {
+ /* drop the message */
+ r = recvmsg(fd, &msg, 0);
+ if (r < 0)
+ return (errno == EAGAIN || errno == EINTR) ? 0 : -errno;
+ }
+
return 0;
+ }
if (group)
*_group = group;
/* check that we support this message type */
r = type_system_get_type(NULL, &nl_type, new_msg->nlmsg_type);
if (r < 0) {
- if (r == -ENOTSUP)
- log_debug("sd-rtnl: ignored message with unknown type: %u",
+ if (r == -EOPNOTSUPP)
+ log_debug("sd-rtnl: ignored message with unknown type: %i",
new_msg->nlmsg_type);
continue;