X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flibsystemd%2Fsd-rtnl%2Frtnl-message.c;h=7ea68f18ae4fed56a8420abf8d0ac3acd11b6926;hp=15e3247aca90dff62178320b78a8c3d7f5647664;hb=6a8402d956a6f89910530e6b364c79be821d2d9d;hpb=818dc5e72af8a3eb772997188e2bd8ea616de844 diff --git a/src/libsystemd/sd-rtnl/rtnl-message.c b/src/libsystemd/sd-rtnl/rtnl-message.c index 15e3247ac..7ea68f18a 100644 --- a/src/libsystemd/sd-rtnl/rtnl-message.c +++ b/src/libsystemd/sd-rtnl/rtnl-message.c @@ -27,6 +27,7 @@ #include "util.h" #include "refcnt.h" +#include "missing.h" #include "sd-rtnl.h" #include "rtnl-util.h" @@ -37,7 +38,7 @@ #define UPDATE_RTA(m, new) (m)->next_rta_offset = (uint8_t*)(new) - (uint8_t*)(m)->hdr; #define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers ++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr; -int message_new(sd_rtnl_message **ret, size_t initial_size) { +int message_new(sd_rtnl *rtnl, sd_rtnl_message **ret, size_t initial_size) { sd_rtnl_message *m; assert_return(ret, -EINVAL); @@ -58,6 +59,9 @@ int message_new(sd_rtnl_message **ret, size_t initial_size) { m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; m->sealed = false; + if (rtnl) + m->rtnl = sd_rtnl_ref(rtnl); + *ret = m; return 0; @@ -81,8 +85,22 @@ int sd_rtnl_message_route_set_dst_prefixlen(sd_rtnl_message *m, unsigned char pr return 0; } -int sd_rtnl_message_new_route(uint16_t nlmsg_type, unsigned char rtm_family, - sd_rtnl_message **ret) { +int sd_rtnl_message_route_set_scope(sd_rtnl_message *m, unsigned char scope) { + struct rtmsg *rtm; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL); + + rtm = NLMSG_DATA(m->hdr); + + rtm->rtm_scope = scope; + + return 0; +} + +int sd_rtnl_message_new_route(sd_rtnl *rtnl, sd_rtnl_message **ret, + uint16_t nlmsg_type, unsigned char rtm_family) { struct rtmsg *rtm; int r; @@ -90,7 +108,7 @@ int sd_rtnl_message_new_route(uint16_t nlmsg_type, unsigned char rtm_family, assert_return(rtm_family == AF_INET || rtm_family == AF_INET6, -EINVAL); assert_return(ret, -EINVAL); - r = message_new(ret, NLMSG_SPACE(sizeof(struct rtmsg))); + r = message_new(rtnl, ret, NLMSG_SPACE(sizeof(struct rtmsg))); if (r < 0) return r; @@ -142,22 +160,23 @@ int sd_rtnl_message_link_set_type(sd_rtnl_message *m, unsigned type) { return 0; } -int sd_rtnl_message_new_link(uint16_t nlmsg_type, int index, sd_rtnl_message **ret) { +int sd_rtnl_message_new_link(sd_rtnl *rtnl, sd_rtnl_message **ret, + uint16_t nlmsg_type, int index) { struct ifinfomsg *ifi; int r; assert_return(rtnl_message_type_is_link(nlmsg_type), -EINVAL); - assert_return(nlmsg_type == RTM_NEWLINK || index > 0, -EINVAL); + assert_return(nlmsg_type != RTM_DELLINK || index > 0, -EINVAL); assert_return(ret, -EINVAL); - r = message_new(ret, NLMSG_SPACE(sizeof(struct ifinfomsg))); + r = message_new(rtnl, ret, NLMSG_SPACE(sizeof(struct ifinfomsg))); if (r < 0) return r; (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); (*ret)->hdr->nlmsg_type = nlmsg_type; if (nlmsg_type == RTM_NEWLINK) - (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE; + (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL; ifi = NLMSG_DATA((*ret)->hdr); @@ -215,8 +234,9 @@ int sd_rtnl_message_addr_set_scope(sd_rtnl_message *m, unsigned char scope) { return 0; } -int sd_rtnl_message_new_addr(uint16_t nlmsg_type, int index, unsigned char family, - sd_rtnl_message **ret) { +int sd_rtnl_message_new_addr(sd_rtnl *rtnl, sd_rtnl_message **ret, + uint16_t nlmsg_type, int index, + unsigned char family) { struct ifaddrmsg *ifa; int r; @@ -225,7 +245,7 @@ int sd_rtnl_message_new_addr(uint16_t nlmsg_type, int index, unsigned char famil assert_return(family == AF_INET || family == AF_INET6, -EINVAL); assert_return(ret, -EINVAL); - r = message_new(ret, NLMSG_SPACE(sizeof(struct ifaddrmsg))); + r = message_new(rtnl, ret, NLMSG_SPACE(sizeof(struct ifaddrmsg))); if (r < 0) return r; @@ -257,7 +277,9 @@ sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) { sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) { if (m && REFCNT_DEC(m->n_ref) <= 0) { + sd_rtnl_unref(m->rtnl); free(m->hdr); + free(m->rta_offset_tb); free(m); } @@ -472,7 +494,7 @@ int sd_rtnl_message_append_u16(sd_rtnl_message *m, unsigned short type, uint16_t break; else return -ENOTSUP; - break; + default: return -ENOTSUP; } @@ -513,6 +535,7 @@ int sd_rtnl_message_append_u32(sd_rtnl_message *m, unsigned short type, uint32_t case IFLA_PROMISCUITY: case IFLA_NUM_TX_QUEUES: case IFLA_NUM_RX_QUEUES: + case IFLA_MACVLAN_MODE: break; default: return -ENOTSUP; @@ -755,7 +778,7 @@ int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data) if (!RTA_OK(NEXT_RTA(m), remaining_size)) return 0; - /* if we read a container, enter it and return its type */ + /* if we read a container, return its type, but do not enter it*/ r = sd_rtnl_message_get_type(m, &rtm_type); if (r < 0) return r; @@ -767,18 +790,136 @@ int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data) NEXT_RTA(m)->rta_type == IFLA_LINKINFO) || (m->n_containers == 1 && GET_CONTAINER(m, 0)->rta_type == IFLA_LINKINFO && - NEXT_RTA(m)->rta_type == IFLA_INFO_DATA))) { + NEXT_RTA(m)->rta_type == IFLA_INFO_DATA))) *data = NULL; - PUSH_CONTAINER(m, NEXT_RTA(m)); - UPDATE_RTA(m, RTA_DATA(NEXT_RTA(m))); - } else { + else *data = RTA_DATA(NEXT_RTA(m)); - UPDATE_RTA(m, RTA_NEXT(NEXT_RTA(m), remaining_size)); - } + + UPDATE_RTA(m, RTA_NEXT(NEXT_RTA(m), remaining_size)); return 1; } +int rtnl_message_read_internal(sd_rtnl_message *m, unsigned short type, void **data) { + assert_return(m, -EINVAL); + assert_return(m->sealed, -EPERM); + assert_return(data, -EINVAL); + assert_return(m->rta_offset_tb, -EINVAL); + assert_return(type < m->rta_tb_size, -EINVAL); + + if(!m->rta_offset_tb[type]) + return -ENODATA; + + *data = RTA_DATA((struct rtattr *)((uint8_t *) m->hdr + m->rta_offset_tb[type])); + + return 0; +} + +int sd_rtnl_message_read_string(sd_rtnl_message *m, unsigned short type, char **data) { + int r; + void *attr_data; + + assert_return(data, -EINVAL); + + r = rtnl_message_read_internal(m, type, &attr_data); + if(r < 0) + return r; + + *data = (char *) attr_data; + + return 0; +} + +int sd_rtnl_message_read_u8(sd_rtnl_message *m, unsigned short type, uint8_t *data) { + int r; + void *attr_data; + + assert_return(data, -EINVAL); + + r = rtnl_message_read_internal(m, type, &attr_data); + if(r < 0) + return r; + + *data = *(uint8_t *) attr_data; + + return 0; +} + +int sd_rtnl_message_read_u16(sd_rtnl_message *m, unsigned short type, uint16_t *data) { + int r; + void *attr_data; + + assert_return(data, -EINVAL); + + r = rtnl_message_read_internal(m, type, &attr_data); + if(r < 0) + return r; + + *data = *(uint16_t *) attr_data; + + return 0; +} + +int sd_rtnl_message_read_u32(sd_rtnl_message *m, unsigned short type, uint32_t *data) { + int r; + void *attr_data; + + assert_return(data, -EINVAL); + + r = rtnl_message_read_internal(m, type, &attr_data); + if(r < 0) + return r; + + *data = *(uint32_t *) attr_data; + + return 0; +} + +int sd_rtnl_message_read_ether_addr(sd_rtnl_message *m, unsigned short type, struct ether_addr *data) { + int r; + void *attr_data; + + assert_return(data, -EINVAL); + + r = rtnl_message_read_internal(m, type, &attr_data); + if(r < 0) + return r; + + memcpy(data, attr_data, sizeof(struct ether_addr)); + + return 0; +} + +int sd_rtnl_message_read_in_addr(sd_rtnl_message *m, unsigned short type, struct in_addr *data) { + int r; + void *attr_data; + + assert_return(data, -EINVAL); + + r = rtnl_message_read_internal(m, type, &attr_data); + if(r < 0) + return r; + + memcpy(data, attr_data, sizeof(struct in_addr)); + + return 0; +} + +int sd_rtnl_message_read_in6_addr(sd_rtnl_message *m, unsigned short type, struct in6_addr *data) { + int r; + void *attr_data; + + assert_return(data, -EINVAL); + + r = rtnl_message_read_internal(m, type, &attr_data); + if(r < 0) + return r; + + memcpy(data, attr_data, sizeof(struct in6_addr)); + + return 0; +} + int sd_rtnl_message_exit_container(sd_rtnl_message *m) { assert_return(m, -EINVAL); assert_return(m->sealed, -EINVAL); @@ -851,6 +992,33 @@ static int message_receive_need(sd_rtnl *rtnl, size_t *need) { return 0; } +int rtnl_message_parse(sd_rtnl_message *m, + size_t **rta_offset_tb, + unsigned short *rta_tb_size, + int max, + struct rtattr *rta, + unsigned int rt_len) { + int type; + size_t *tb; + + tb = (size_t *) new0(size_t *, max); + if(!tb) + return -ENOMEM; + + *rta_tb_size = max; + + for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) { + type = rta->rta_type; + + if (type < max && !tb[type]) + tb[type] = (uint8_t *) rta - (uint8_t *) m->hdr; + } + + *rta_offset_tb = tb; + + return 0; +} + /* returns the number of bytes sent, or a negative error code */ int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) { union { @@ -896,7 +1064,7 @@ int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) { if (r < 0) return r; - r = message_new(&m, need); + r = message_new(nl, &m, need); if (r < 0) return r; @@ -924,10 +1092,6 @@ int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) { if (k > 0) switch (m->hdr->nlmsg_type) { - struct ifinfomsg *ifi; - struct ifaddrmsg *ifa; - struct rtmsg *rtm; - /* check that the size matches the message type */ case NLMSG_ERROR: if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) @@ -940,8 +1104,18 @@ int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) { if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg))) k = -EIO; else { + struct ifinfomsg *ifi; + ifi = NLMSG_DATA(m->hdr); UPDATE_RTA(m, IFLA_RTA(ifi)); + + r = rtnl_message_parse(m, + &m->rta_offset_tb, + &m->rta_tb_size, + IFLA_MAX, + IFLA_RTA(ifi), + IFLA_PAYLOAD(m->hdr)); + } break; case RTM_NEWADDR: @@ -950,8 +1124,17 @@ int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) { if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifaddrmsg))) k = -EIO; else { + struct ifaddrmsg *ifa; + ifa = NLMSG_DATA(m->hdr); UPDATE_RTA(m, IFA_RTA(ifa)); + + r = rtnl_message_parse(m, + &m->rta_offset_tb, + &m->rta_tb_size, + IFA_MAX, + IFA_RTA(ifa), + IFA_PAYLOAD(m->hdr)); } break; case RTM_NEWROUTE: @@ -960,8 +1143,17 @@ int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) { if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg))) k = -EIO; else { + struct rtmsg *rtm; + rtm = NLMSG_DATA(m->hdr); UPDATE_RTA(m, RTM_RTA(rtm)); + + r = rtnl_message_parse(m, + &m->rta_offset_tb, + &m->rta_tb_size, + RTA_MAX, + RTM_RTA(rtm), + RTM_PAYLOAD(m->hdr)); } break; case NLMSG_NOOP: