X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flibsystemd%2Fsd-netlink%2Fnetlink-message.c;h=b0ed2f28825bf9dfd7408b6f9e423edfa5af9a79;hp=3f8bf018268d29c9c58538a855544fd9afc7ab27;hb=d29820f2a37d7fe1bccebfd83abbfd13e904af34;hpb=2f80599e296658b1322d9dca08adee57fde8a8e3;ds=sidebyside diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c index 3f8bf0182..b0ed2f288 100644 --- a/src/libsystemd/sd-netlink/netlink-message.c +++ b/src/libsystemd/sd-netlink/netlink-message.c @@ -34,10 +34,11 @@ #include "netlink-internal.h" #include "netlink-types.h" -#define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->container_offsets[i]) : NULL) +#define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->containers[i].offset) : NULL) #define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers ++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr; #define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK) +#define RTA_FLAGS(rta) ((rta)->rta_type & ~NLA_TYPE_MASK) int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret) { sd_netlink_message *m; @@ -72,6 +73,9 @@ int message_new(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t type) { if (r < 0) return r; + if (type_get_type(nl_type) != NETLINK_TYPE_NESTED) + return -EINVAL; + r = message_new_empty(rtnl, &m); if (r < 0) return r; @@ -85,8 +89,7 @@ int message_new(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t type) { m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; - if (type_get_type(nl_type) == NETLINK_TYPE_NESTED) - type_get_type_system(nl_type, &m->container_type_system[0]); + type_get_type_system(nl_type, &m->containers[0].type_system); m->hdr->nlmsg_len = size; m->hdr->nlmsg_type = type; @@ -127,7 +130,7 @@ sd_netlink_message *sd_netlink_message_unref(sd_netlink_message *m) { free(m->hdr); for (i = 0; i <= m->n_containers; i++) - free(m->rta_offset_tb[i]); + free(m->containers[i].attributes); sd_netlink_message_unref(m->next); @@ -221,7 +224,7 @@ static int message_attribute_has_type(sd_netlink_message *m, size_t *out_size, u assert(m); - r = type_system_get_type(m->container_type_system[m->n_containers], &type, attribute_type); + r = type_system_get_type(m->containers[m->n_containers].type_system, &type, attribute_type); if (r < 0) return r; @@ -404,18 +407,18 @@ int sd_netlink_message_open_container(sd_netlink_message *m, unsigned short type if (r < 0) return r; - r = type_system_get_type_system_union(m->container_type_system[m->n_containers], &type_system_union, type); + r = type_system_get_type_system_union(m->containers[m->n_containers].type_system, &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], + &m->containers[m->n_containers + 1].type_system, family); if (r < 0) return r; } else { - r = type_system_get_type_system(m->container_type_system[m->n_containers], - &m->container_type_system[m->n_containers + 1], + r = type_system_get_type_system(m->containers[m->n_containers].type_system, + &m->containers[m->n_containers + 1].type_system, type); if (r < 0) return r; @@ -425,7 +428,7 @@ int sd_netlink_message_open_container(sd_netlink_message *m, unsigned short type if (r < 0) return r; - m->container_offsets[m->n_containers ++] = r; + m->containers[m->n_containers ++].offset = r; return 0; } @@ -437,12 +440,12 @@ int sd_netlink_message_open_container_union(sd_netlink_message *m, unsigned shor assert_return(m, -EINVAL); assert_return(!m->sealed, -EPERM); - r = type_system_get_type_system_union(m->container_type_system[m->n_containers], &type_system_union, type); + r = type_system_get_type_system_union(m->containers[m->n_containers].type_system, &type_system_union, type); if (r < 0) return r; r = type_system_union_get_type_system(type_system_union, - &m->container_type_system[m->n_containers + 1], + &m->containers[m->n_containers + 1].type_system, key); if (r < 0) return r; @@ -452,11 +455,11 @@ int sd_netlink_message_open_container_union(sd_netlink_message *m, unsigned shor return r; /* do we evere need non-null size */ - r = add_rtattr(m, type, NULL, 0); + r = add_rtattr(m, type | NLA_F_NESTED, NULL, 0); if (r < 0) return r; - m->container_offsets[m->n_containers ++] = r; + m->containers[m->n_containers ++].offset = r; return 0; } @@ -467,29 +470,35 @@ int sd_netlink_message_close_container(sd_netlink_message *m) { assert_return(!m->sealed, -EPERM); assert_return(m->n_containers > 0, -EINVAL); - m->container_type_system[m->n_containers] = NULL; + m->containers[m->n_containers].type_system = NULL; m->n_containers --; return 0; } -int rtnl_message_read_internal(sd_netlink_message *m, unsigned short type, void **data) { +static int netlink_message_read_internal(sd_netlink_message *m, unsigned short type, void **data, bool *net_byteorder) { + struct netlink_attribute *attribute; struct rtattr *rta; assert_return(m, -EINVAL); assert_return(m->sealed, -EPERM); assert_return(data, -EINVAL); assert(m->n_containers <= RTNL_CONTAINER_DEPTH); - assert(m->rta_offset_tb[m->n_containers]); - assert(type < m->rta_tb_size[m->n_containers]); + assert(m->containers[m->n_containers].attributes); + assert(type < m->containers[m->n_containers].n_attributes); - if(!m->rta_offset_tb[m->n_containers][type]) + attribute = &m->containers[m->n_containers].attributes[type]; + + if(!attribute->offset) return -ENODATA; - rta = (struct rtattr*)((uint8_t *) m->hdr + m->rta_offset_tb[m->n_containers][type]); + rta = (struct rtattr*)((uint8_t *) m->hdr + attribute->offset); *data = RTA_DATA(rta); + if (net_byteorder) + *net_byteorder = attribute->net_byteorder; + return RTA_PAYLOAD(rta); } @@ -503,7 +512,7 @@ int sd_netlink_message_read_string(sd_netlink_message *m, unsigned short type, c if (r < 0) return r; - r = rtnl_message_read_internal(m, type, &attr_data); + r = netlink_message_read_internal(m, type, &attr_data, NULL); if (r < 0) return r; else if (strnlen(attr_data, r) >= (size_t) r) @@ -525,7 +534,7 @@ int sd_netlink_message_read_u8(sd_netlink_message *m, unsigned short type, uint8 if (r < 0) return r; - r = rtnl_message_read_internal(m, type, &attr_data); + r = netlink_message_read_internal(m, type, &attr_data, NULL); if (r < 0) return r; else if ((size_t) r < sizeof(uint8_t)) @@ -538,8 +547,9 @@ int sd_netlink_message_read_u8(sd_netlink_message *m, unsigned short type, uint8 } int sd_netlink_message_read_u16(sd_netlink_message *m, unsigned short type, uint16_t *data) { - int r; void *attr_data; + bool net_byteorder; + int r; assert_return(m, -EINVAL); @@ -547,21 +557,26 @@ int sd_netlink_message_read_u16(sd_netlink_message *m, unsigned short type, uint if (r < 0) return r; - r = rtnl_message_read_internal(m, type, &attr_data); + r = netlink_message_read_internal(m, type, &attr_data, &net_byteorder); if (r < 0) return r; else if ((size_t) r < sizeof(uint16_t)) return -EIO; - if (data) - *data = *(uint16_t *) attr_data; + if (data) { + if (net_byteorder) + *data = be16toh(*(uint16_t *) attr_data); + else + *data = *(uint16_t *) attr_data; + } return 0; } int sd_netlink_message_read_u32(sd_netlink_message *m, unsigned short type, uint32_t *data) { - int r; void *attr_data; + bool net_byteorder; + int r; assert_return(m, -EINVAL); @@ -569,14 +584,18 @@ int sd_netlink_message_read_u32(sd_netlink_message *m, unsigned short type, uint if (r < 0) return r; - r = rtnl_message_read_internal(m, type, &attr_data); + r = netlink_message_read_internal(m, type, &attr_data, &net_byteorder); if (r < 0) return r; else if ((size_t)r < sizeof(uint32_t)) return -EIO; - if (data) - *data = *(uint32_t *) attr_data; + if (data) { + if (net_byteorder) + *data = be32toh(*(uint32_t *) attr_data); + else + *data = *(uint32_t *) attr_data; + } return 0; } @@ -591,7 +610,7 @@ int sd_netlink_message_read_ether_addr(sd_netlink_message *m, unsigned short typ if (r < 0) return r; - r = rtnl_message_read_internal(m, type, &attr_data); + r = netlink_message_read_internal(m, type, &attr_data, NULL); if (r < 0) return r; else if ((size_t)r < sizeof(struct ether_addr)) @@ -613,7 +632,7 @@ int sd_netlink_message_read_cache_info(sd_netlink_message *m, unsigned short typ if (r < 0) return r; - r = rtnl_message_read_internal(m, type, &attr_data); + r = netlink_message_read_internal(m, type, &attr_data, NULL); if (r < 0) return r; else if ((size_t)r < sizeof(struct ifa_cacheinfo)) @@ -635,7 +654,7 @@ int sd_netlink_message_read_in_addr(sd_netlink_message *m, unsigned short type, if (r < 0) return r; - r = rtnl_message_read_internal(m, type, &attr_data); + r = netlink_message_read_internal(m, type, &attr_data, NULL); if (r < 0) return r; else if ((size_t)r < sizeof(struct in_addr)) @@ -657,7 +676,7 @@ int sd_netlink_message_read_in6_addr(sd_netlink_message *m, unsigned short type, if (r < 0) return r; - r = rtnl_message_read_internal(m, type, &attr_data); + r = netlink_message_read_internal(m, type, &attr_data, NULL); if (r < 0) return r; else if ((size_t)r < sizeof(struct in6_addr)) @@ -669,6 +688,42 @@ int sd_netlink_message_read_in6_addr(sd_netlink_message *m, unsigned short type, return 0; } +static int netlink_container_parse(sd_netlink_message *m, + struct netlink_container *container, + int count, + struct rtattr *rta, + unsigned int rt_len) { + _cleanup_free_ struct netlink_attribute *attributes = NULL; + + attributes = new0(struct netlink_attribute, count); + if(!attributes) + return -ENOMEM; + + for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) { + unsigned short type; + + type = RTA_TYPE(rta); + + /* if the kernel is newer than the headers we used + when building, we ignore out-of-range attributes */ + if (type >= count) + continue; + + if (attributes[type].offset) + log_debug("rtnl: message parse - overwriting repeated attribute"); + + attributes[type].offset = (uint8_t *) rta - (uint8_t *) m->hdr; + attributes[type].nested = RTA_FLAGS(rta) & NLA_F_NESTED; + attributes[type].net_byteorder = RTA_FLAGS(rta) & NLA_F_NET_BYTEORDER; + } + + container->attributes = attributes; + attributes = NULL; + container->n_attributes = count; + + return 0; +} + int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short type_id) { const NLType *nl_type; const NLTypeSystem *type_system; @@ -680,7 +735,7 @@ int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short typ assert_return(m, -EINVAL); assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL); - r = type_system_get_type(m->container_type_system[m->n_containers], + r = type_system_get_type(m->containers[m->n_containers].type_system, &nl_type, type_id); if (r < 0) @@ -689,7 +744,7 @@ int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short typ type = type_get_type(nl_type); if (type == NETLINK_TYPE_NESTED) { - r = type_system_get_type_system(m->container_type_system[m->n_containers], + r = type_system_get_type_system(m->containers[m->n_containers].type_system, &type_system, type_id); if (r < 0) @@ -697,7 +752,7 @@ int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short typ } else if (type == NETLINK_TYPE_UNION) { const NLTypeSystemUnion *type_system_union; - r = type_system_get_type_system_union(m->container_type_system[m->n_containers], + r = type_system_get_type_system_union(m->containers[m->n_containers].type_system, &type_system_union, type_id); if (r < 0) @@ -742,7 +797,7 @@ int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short typ } else return -EINVAL; - r = rtnl_message_read_internal(m, type_id, &container); + r = netlink_message_read_internal(m, type_id, &container, NULL); if (r < 0) return r; else @@ -750,18 +805,17 @@ int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short typ m->n_containers ++; - r = rtnl_message_parse(m, - &m->rta_offset_tb[m->n_containers], - &m->rta_tb_size[m->n_containers], - type_system_get_count(type_system), - container, - size); + r = netlink_container_parse(m, + &m->containers[m->n_containers], + type_system_get_count(type_system), + container, + size); if (r < 0) { m->n_containers --; return r; } - m->container_type_system[m->n_containers] = type_system; + m->containers[m->n_containers].type_system = type_system; return 0; } @@ -771,9 +825,9 @@ int sd_netlink_message_exit_container(sd_netlink_message *m) { assert_return(m->sealed, -EINVAL); assert_return(m->n_containers > 0, -EINVAL); - free(m->rta_offset_tb[m->n_containers]); - m->rta_offset_tb[m->n_containers] = NULL; - m->container_type_system[m->n_containers] = NULL; + free(m->containers[m->n_containers].attributes); + m->containers[m->n_containers].attributes = NULL; + m->containers[m->n_containers].type_system = NULL; m->n_containers --; @@ -808,41 +862,6 @@ int sd_netlink_message_get_errno(sd_netlink_message *m) { return err->error; } -int rtnl_message_parse(sd_netlink_message *m, - size_t **rta_offset_tb, - unsigned short *rta_tb_size, - int count, - struct rtattr *rta, - unsigned int rt_len) { - unsigned short type; - size_t *tb; - - tb = new0(size_t, count); - if(!tb) - return -ENOMEM; - - *rta_tb_size = count; - - for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) { - type = RTA_TYPE(rta); - - /* if the kernel is newer than the headers we used - when building, we ignore out-of-range attributes - */ - if (type >= count) - continue; - - if (tb[type]) - log_debug("rtnl: message parse - overwriting repeated attribute"); - - tb[type] = (uint8_t *) rta - (uint8_t *) m->hdr; - } - - *rta_offset_tb = tb; - - return 0; -} - int sd_netlink_message_rewind(sd_netlink_message *m) { const NLType *nl_type; uint16_t type; @@ -857,15 +876,13 @@ int sd_netlink_message_rewind(sd_netlink_message *m) { rtnl_message_seal(m); for (i = 1; i <= m->n_containers; i++) { - free(m->rta_offset_tb[i]); - m->rta_offset_tb[i] = NULL; - m->rta_tb_size[i] = 0; - m->container_type_system[i] = NULL; + free(m->containers[i].attributes); + m->containers[i].attributes = NULL; } m->n_containers = 0; - if (m->rta_offset_tb[0]) { + if (m->containers[0].attributes) { /* top-level attributes have already been parsed */ return 0; } @@ -884,14 +901,13 @@ int sd_netlink_message_rewind(sd_netlink_message *m) { type_get_type_system(nl_type, &type_system); - m->container_type_system[0] = type_system; + m->containers[0].type_system = type_system; - r = rtnl_message_parse(m, - &m->rta_offset_tb[m->n_containers], - &m->rta_tb_size[m->n_containers], - type_system_get_count(type_system), - (struct rtattr*)((uint8_t*)NLMSG_DATA(m->hdr) + NLMSG_ALIGN(size)), - NLMSG_PAYLOAD(m->hdr, size)); + r = netlink_container_parse(m, + &m->containers[m->n_containers], + type_system_get_count(type_system), + (struct rtattr*)((uint8_t*)NLMSG_DATA(m->hdr) + NLMSG_ALIGN(size)), + NLMSG_PAYLOAD(m->hdr, size)); if (r < 0) return r; }