LCOV - code coverage report
Current view: top level - libsystemd/sd-netlink - netlink-message.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 415 569 72.9 %
Date: 2019-08-22 15:41:25 Functions: 39 50 78.0 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <netinet/in.h>
       4             : #include <stdbool.h>
       5             : #include <unistd.h>
       6             : 
       7             : #include "sd-netlink.h"
       8             : 
       9             : #include "alloc-util.h"
      10             : #include "format-util.h"
      11             : #include "missing.h"
      12             : #include "netlink-internal.h"
      13             : #include "netlink-types.h"
      14             : #include "netlink-util.h"
      15             : #include "socket-util.h"
      16             : #include "memory-util.h"
      17             : 
      18             : #define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->containers[i].offset) : NULL)
      19             : #define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
      20             : 
      21             : #define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK)
      22             : #define RTA_FLAGS(rta) ((rta)->rta_type & ~NLA_TYPE_MASK)
      23             : 
      24         102 : int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret) {
      25             :         sd_netlink_message *m;
      26             : 
      27         102 :         assert_return(ret, -EINVAL);
      28             : 
      29             :         /* Note that 'rtnl' is currently unused, if we start using it internally
      30             :            we must take care to avoid problems due to mutual references between
      31             :            buses and their queued messages. See sd-bus.
      32             :          */
      33             : 
      34         102 :         m = new0(sd_netlink_message, 1);
      35         102 :         if (!m)
      36           0 :                 return -ENOMEM;
      37             : 
      38         102 :         m->n_ref = 1;
      39         102 :         m->protocol = rtnl->protocol;
      40         102 :         m->sealed = false;
      41             : 
      42         102 :         *ret = m;
      43             : 
      44         102 :         return 0;
      45             : }
      46             : 
      47          30 : int message_new(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t type) {
      48          30 :         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
      49             :         const NLType *nl_type;
      50             :         const NLTypeSystem *type_system_root;
      51             :         size_t size;
      52             :         int r;
      53             : 
      54          30 :         assert_return(rtnl, -EINVAL);
      55             : 
      56          30 :         type_system_root = type_system_get_root(rtnl->protocol);
      57             : 
      58          30 :         r = type_system_get_type(type_system_root, &nl_type, type);
      59          30 :         if (r < 0)
      60           0 :                 return r;
      61             : 
      62          30 :         if (type_get_type(nl_type) != NETLINK_TYPE_NESTED)
      63           0 :                 return -EINVAL;
      64             : 
      65          30 :         r = message_new_empty(rtnl, &m);
      66          30 :         if (r < 0)
      67           0 :                 return r;
      68             : 
      69          30 :         size = NLMSG_SPACE(type_get_size(nl_type));
      70             : 
      71          30 :         assert(size >= sizeof(struct nlmsghdr));
      72          30 :         m->hdr = malloc0(size);
      73          30 :         if (!m->hdr)
      74           0 :                 return -ENOMEM;
      75             : 
      76          30 :         m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
      77             : 
      78          30 :         type_get_type_system(nl_type, &m->containers[0].type_system);
      79          30 :         m->hdr->nlmsg_len = size;
      80          30 :         m->hdr->nlmsg_type = type;
      81             : 
      82          30 :         *ret = TAKE_PTR(m);
      83             : 
      84          30 :         return 0;
      85             : }
      86             : 
      87           2 : int sd_netlink_message_request_dump(sd_netlink_message *m, int dump) {
      88           2 :         assert_return(m, -EINVAL);
      89           2 :         assert_return(m->hdr, -EINVAL);
      90             : 
      91           2 :         assert_return(IN_SET(m->hdr->nlmsg_type, RTM_GETLINK, RTM_GETADDR, RTM_GETROUTE, RTM_GETNEIGH, RTM_GETRULE, RTM_GETADDRLABEL), -EINVAL);
      92             : 
      93           2 :         SET_FLAG(m->hdr->nlmsg_flags, NLM_F_DUMP, dump);
      94             : 
      95           2 :         return 0;
      96             : }
      97             : 
      98           0 : DEFINE_TRIVIAL_REF_FUNC(sd_netlink_message, sd_netlink_message);
      99             : 
     100          56 : sd_netlink_message *sd_netlink_message_unref(sd_netlink_message *m) {
     101         158 :         while (m && --m->n_ref == 0) {
     102             :                 unsigned i;
     103             : 
     104         102 :                 free(m->hdr);
     105             : 
     106         204 :                 for (i = 0; i <= m->n_containers; i++)
     107         102 :                         free(m->containers[i].attributes);
     108             : 
     109         102 :                 sd_netlink_message *t = m;
     110         102 :                 m = m->next;
     111         102 :                 free(t);
     112             :         }
     113             : 
     114          56 :         return NULL;
     115             : }
     116             : 
     117          76 : int sd_netlink_message_get_type(sd_netlink_message *m, uint16_t *type) {
     118          76 :         assert_return(m, -EINVAL);
     119          76 :         assert_return(type, -EINVAL);
     120             : 
     121          76 :         *type = m->hdr->nlmsg_type;
     122             : 
     123          76 :         return 0;
     124             : }
     125             : 
     126           0 : int sd_netlink_message_set_flags(sd_netlink_message *m, uint16_t flags) {
     127           0 :         assert_return(m, -EINVAL);
     128           0 :         assert_return(flags, -EINVAL);
     129             : 
     130           0 :         m->hdr->nlmsg_flags = flags;
     131             : 
     132           0 :         return 0;
     133             : }
     134             : 
     135          10 : int sd_netlink_message_is_broadcast(sd_netlink_message *m) {
     136          10 :         assert_return(m, -EINVAL);
     137             : 
     138          10 :         return m->broadcast;
     139             : }
     140             : 
     141             : /* If successful the updated message will be correctly aligned, if
     142             :    unsuccessful the old message is untouched. */
     143          53 : static int add_rtattr(sd_netlink_message *m, unsigned short type, const void *data, size_t data_length) {
     144             :         uint32_t rta_length;
     145             :         size_t message_length, padding_length;
     146             :         struct nlmsghdr *new_hdr;
     147             :         struct rtattr *rta;
     148             :         char *padding;
     149             :         unsigned i;
     150             :         int offset;
     151             : 
     152          53 :         assert(m);
     153          53 :         assert(m->hdr);
     154          53 :         assert(!m->sealed);
     155          53 :         assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
     156          53 :         assert(!data || data_length);
     157             : 
     158             :         /* get offset of the new attribute */
     159          53 :         offset = m->hdr->nlmsg_len;
     160             : 
     161             :         /* get the size of the new rta attribute (with padding at the end) */
     162          53 :         rta_length = RTA_LENGTH(data_length);
     163             : 
     164             :         /* get the new message size (with padding at the end) */
     165          53 :         message_length = offset + RTA_ALIGN(rta_length);
     166             : 
     167             :         /* buffer should be smaller than both one page or 8K to be accepted by the kernel */
     168          53 :         if (message_length > MIN(page_size(), 8192UL))
     169           0 :                 return -ENOBUFS;
     170             : 
     171             :         /* realloc to fit the new attribute */
     172          53 :         new_hdr = realloc(m->hdr, message_length);
     173          53 :         if (!new_hdr)
     174           0 :                 return -ENOMEM;
     175          53 :         m->hdr = new_hdr;
     176             : 
     177             :         /* get pointer to the attribute we are about to add */
     178          53 :         rta = (struct rtattr *) ((uint8_t *) m->hdr + offset);
     179             : 
     180             :         /* if we are inside containers, extend them */
     181         109 :         for (i = 0; i < m->n_containers; i++)
     182          56 :                 GET_CONTAINER(m, i)->rta_len += message_length - offset;
     183             : 
     184             :         /* fill in the attribute */
     185          53 :         rta->rta_type = type;
     186          53 :         rta->rta_len = rta_length;
     187          53 :         if (data)
     188             :                 /* we don't deal with the case where the user lies about the type
     189             :                  * and gives us too little data (so don't do that)
     190             :                  */
     191          39 :                 padding = mempcpy(RTA_DATA(rta), data, data_length);
     192             : 
     193             :         else
     194             :                 /* if no data was passed, make sure we still initialize the padding
     195             :                    note that we can have data_length > 0 (used by some containers) */
     196          14 :                 padding = RTA_DATA(rta);
     197             : 
     198             :         /* make sure also the padding at the end of the message is initialized */
     199          53 :         padding_length = (uint8_t*)m->hdr + message_length - (uint8_t*)padding;
     200          53 :         memzero(padding, padding_length);
     201             : 
     202             :         /* update message size */
     203          53 :         m->hdr->nlmsg_len = message_length;
     204             : 
     205          53 :         return offset;
     206             : }
     207             : 
     208         171 : static int message_attribute_has_type(sd_netlink_message *m, size_t *out_size, uint16_t attribute_type, uint16_t data_type) {
     209             :         const NLType *type;
     210             :         int r;
     211             : 
     212         171 :         assert(m);
     213             : 
     214         171 :         r = type_system_get_type(m->containers[m->n_containers].type_system, &type, attribute_type);
     215         171 :         if (r < 0)
     216           0 :                 return r;
     217             : 
     218         171 :         if (type_get_type(type) != data_type)
     219           2 :                 return -EINVAL;
     220             : 
     221         169 :         if (out_size)
     222          16 :                 *out_size = type_get_size(type);
     223         169 :         return 0;
     224             : }
     225             : 
     226          13 : int sd_netlink_message_append_string(sd_netlink_message *m, unsigned short type, const char *data) {
     227             :         size_t length, size;
     228             :         int r;
     229             : 
     230          13 :         assert_return(m, -EINVAL);
     231          13 :         assert_return(!m->sealed, -EPERM);
     232          13 :         assert_return(data, -EINVAL);
     233             : 
     234          13 :         r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_STRING);
     235          13 :         if (r < 0)
     236           0 :                 return r;
     237             : 
     238          13 :         if (size) {
     239           1 :                 length = strnlen(data, size+1);
     240           1 :                 if (length > size)
     241           0 :                         return -EINVAL;
     242             :         } else
     243          12 :                 length = strlen(data);
     244             : 
     245          13 :         r = add_rtattr(m, type, data, length + 1);
     246          13 :         if (r < 0)
     247           0 :                 return r;
     248             : 
     249          13 :         return 0;
     250             : }
     251             : 
     252           0 : int sd_netlink_message_append_flag(sd_netlink_message *m, unsigned short type) {
     253             :         size_t size;
     254             :         int r;
     255             : 
     256           0 :         assert_return(m, -EINVAL);
     257           0 :         assert_return(!m->sealed, -EPERM);
     258             : 
     259           0 :         r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_FLAG);
     260           0 :         if (r < 0)
     261           0 :                 return r;
     262             : 
     263           0 :         r = add_rtattr(m, type, NULL, 0);
     264           0 :         if (r < 0)
     265           0 :                 return r;
     266             : 
     267           0 :         return 0;
     268             : }
     269             : 
     270           3 : int sd_netlink_message_append_u8(sd_netlink_message *m, unsigned short type, uint8_t data) {
     271             :         int r;
     272             : 
     273           3 :         assert_return(m, -EINVAL);
     274           3 :         assert_return(!m->sealed, -EPERM);
     275             : 
     276           3 :         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U8);
     277           3 :         if (r < 0)
     278           0 :                 return r;
     279             : 
     280           3 :         r = add_rtattr(m, type, &data, sizeof(uint8_t));
     281           3 :         if (r < 0)
     282           0 :                 return r;
     283             : 
     284           3 :         return 0;
     285             : }
     286             : 
     287           1 : int sd_netlink_message_append_u16(sd_netlink_message *m, unsigned short type, uint16_t data) {
     288             :         int r;
     289             : 
     290           1 :         assert_return(m, -EINVAL);
     291           1 :         assert_return(!m->sealed, -EPERM);
     292             : 
     293           1 :         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U16);
     294           1 :         if (r < 0)
     295           0 :                 return r;
     296             : 
     297           1 :         r = add_rtattr(m, type, &data, sizeof(uint16_t));
     298           1 :         if (r < 0)
     299           0 :                 return r;
     300             : 
     301           1 :         return 0;
     302             : }
     303             : 
     304          18 : int sd_netlink_message_append_u32(sd_netlink_message *m, unsigned short type, uint32_t data) {
     305             :         int r;
     306             : 
     307          18 :         assert_return(m, -EINVAL);
     308          18 :         assert_return(!m->sealed, -EPERM);
     309             : 
     310          18 :         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U32);
     311          18 :         if (r < 0)
     312           0 :                 return r;
     313             : 
     314          18 :         r = add_rtattr(m, type, &data, sizeof(uint32_t));
     315          18 :         if (r < 0)
     316           0 :                 return r;
     317             : 
     318          18 :         return 0;
     319             : }
     320             : 
     321           0 : int sd_netlink_message_append_u64(sd_netlink_message *m, unsigned short type, uint64_t data) {
     322             :         int r;
     323             : 
     324           0 :         assert_return(m, -EINVAL);
     325           0 :         assert_return(!m->sealed, -EPERM);
     326             : 
     327           0 :         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U64);
     328           0 :         if (r < 0)
     329           0 :                 return r;
     330             : 
     331           0 :         r = add_rtattr(m, type, &data, sizeof(uint64_t));
     332           0 :         if (r < 0)
     333           0 :                 return r;
     334             : 
     335           0 :         return 0;
     336             : }
     337             : 
     338           0 : int sd_netlink_message_append_data(sd_netlink_message *m, unsigned short type, const void *data, size_t len) {
     339             :         int r;
     340             : 
     341           0 :         assert_return(m, -EINVAL);
     342           0 :         assert_return(!m->sealed, -EPERM);
     343             : 
     344           0 :         r = add_rtattr(m, type, data, len);
     345           0 :         if (r < 0)
     346           0 :                 return r;
     347             : 
     348           0 :         return 0;
     349             : }
     350             : 
     351           3 : int netlink_message_append_in_addr_union(sd_netlink_message *m, unsigned short type, int family, const union in_addr_union *data) {
     352             :         int r;
     353             : 
     354           3 :         assert_return(m, -EINVAL);
     355           3 :         assert_return(!m->sealed, -EPERM);
     356           3 :         assert_return(data, -EINVAL);
     357           3 :         assert_return(IN_SET(family, AF_INET, AF_INET6), -EINVAL);
     358             : 
     359           3 :         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
     360           3 :         if (r < 0)
     361           0 :                 return r;
     362             : 
     363           3 :         r = add_rtattr(m, type, data, FAMILY_ADDRESS_SIZE(family));
     364           3 :         if (r < 0)
     365           0 :                 return r;
     366             : 
     367           3 :         return 0;
     368             : }
     369             : 
     370           2 : int sd_netlink_message_append_in_addr(sd_netlink_message *m, unsigned short type, const struct in_addr *data) {
     371           2 :         return netlink_message_append_in_addr_union(m, type, AF_INET, (const union in_addr_union *) data);
     372             : }
     373             : 
     374           1 : int sd_netlink_message_append_in6_addr(sd_netlink_message *m, unsigned short type, const struct in6_addr *data) {
     375           1 :         return netlink_message_append_in_addr_union(m, type, AF_INET6, (const union in_addr_union *) data);
     376             : }
     377             : 
     378           0 : int netlink_message_append_sockaddr_union(sd_netlink_message *m, unsigned short type, const union sockaddr_union *data) {
     379             :         int r;
     380             : 
     381           0 :         assert_return(m, -EINVAL);
     382           0 :         assert_return(!m->sealed, -EPERM);
     383           0 :         assert_return(data, -EINVAL);
     384           0 :         assert_return(IN_SET(data->sa.sa_family, AF_INET, AF_INET6), -EINVAL);
     385             : 
     386           0 :         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_SOCKADDR);
     387           0 :         if (r < 0)
     388           0 :                 return r;
     389             : 
     390           0 :         r = add_rtattr(m, type, data, data->sa.sa_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6));
     391           0 :         if (r < 0)
     392           0 :                 return r;
     393             : 
     394           0 :         return 0;
     395             : }
     396             : 
     397           0 : int sd_netlink_message_append_sockaddr_in(sd_netlink_message *m, unsigned short type, const struct sockaddr_in *data) {
     398           0 :         return netlink_message_append_sockaddr_union(m, type, (const union sockaddr_union *) data);
     399             : }
     400             : 
     401           0 : int sd_netlink_message_append_sockaddr_in6(sd_netlink_message *m, unsigned short type, const struct sockaddr_in6 *data) {
     402           0 :         return netlink_message_append_sockaddr_union(m, type, (const union sockaddr_union *) data);
     403             : }
     404             : 
     405           1 : int sd_netlink_message_append_ether_addr(sd_netlink_message *m, unsigned short type, const struct ether_addr *data) {
     406             :         int r;
     407             : 
     408           1 :         assert_return(m, -EINVAL);
     409           1 :         assert_return(!m->sealed, -EPERM);
     410           1 :         assert_return(data, -EINVAL);
     411             : 
     412           1 :         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_ETHER_ADDR);
     413           1 :         if (r < 0)
     414           0 :                 return r;
     415             : 
     416           1 :         r = add_rtattr(m, type, data, ETH_ALEN);
     417           1 :         if (r < 0)
     418           0 :                 return r;
     419             : 
     420           1 :         return 0;
     421             : }
     422             : 
     423           0 : int sd_netlink_message_append_cache_info(sd_netlink_message *m, unsigned short type, const struct ifa_cacheinfo *info) {
     424             :         int r;
     425             : 
     426           0 :         assert_return(m, -EINVAL);
     427           0 :         assert_return(!m->sealed, -EPERM);
     428           0 :         assert_return(info, -EINVAL);
     429             : 
     430           0 :         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_CACHE_INFO);
     431           0 :         if (r < 0)
     432           0 :                 return r;
     433             : 
     434           0 :         r = add_rtattr(m, type, info, sizeof(struct ifa_cacheinfo));
     435           0 :         if (r < 0)
     436           0 :                 return r;
     437             : 
     438           0 :         return 0;
     439             : }
     440             : 
     441           3 : int sd_netlink_message_open_container(sd_netlink_message *m, unsigned short type) {
     442             :         size_t size;
     443             :         int r;
     444             : 
     445           3 :         assert_return(m, -EINVAL);
     446           3 :         assert_return(!m->sealed, -EPERM);
     447           3 :         assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -ERANGE);
     448             : 
     449           3 :         r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_NESTED);
     450           3 :         if (r < 0) {
     451             :                 const NLTypeSystemUnion *type_system_union;
     452             :                 int family;
     453             : 
     454           1 :                 r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_UNION);
     455           1 :                 if (r < 0)
     456           0 :                         return r;
     457             : 
     458           1 :                 r = sd_rtnl_message_get_family(m, &family);
     459           1 :                 if (r < 0)
     460           0 :                         return r;
     461             : 
     462           1 :                 r = type_system_get_type_system_union(m->containers[m->n_containers].type_system, &type_system_union, type);
     463           1 :                 if (r < 0)
     464           0 :                         return r;
     465             : 
     466           2 :                 r = type_system_union_protocol_get_type_system(type_system_union,
     467           1 :                                                                &m->containers[m->n_containers + 1].type_system,
     468             :                                                                family);
     469           1 :                 if (r < 0)
     470           0 :                         return r;
     471             :         } else {
     472           4 :                 r = type_system_get_type_system(m->containers[m->n_containers].type_system,
     473           2 :                                                 &m->containers[m->n_containers + 1].type_system,
     474             :                                                 type);
     475           2 :                 if (r < 0)
     476           0 :                         return r;
     477             :         }
     478             : 
     479           3 :         r = add_rtattr(m, type | NLA_F_NESTED, NULL, size);
     480           3 :         if (r < 0)
     481           0 :                 return r;
     482             : 
     483           3 :         m->containers[m->n_containers++].offset = r;
     484             : 
     485           3 :         return 0;
     486             : }
     487             : 
     488           1 : int sd_netlink_message_open_container_union(sd_netlink_message *m, unsigned short type, const char *key) {
     489             :         const NLTypeSystemUnion *type_system_union;
     490             :         int r;
     491             : 
     492           1 :         assert_return(m, -EINVAL);
     493           1 :         assert_return(!m->sealed, -EPERM);
     494             : 
     495           1 :         r = type_system_get_type_system_union(m->containers[m->n_containers].type_system, &type_system_union, type);
     496           1 :         if (r < 0)
     497           0 :                 return r;
     498             : 
     499           1 :         r = type_system_union_get_type_system(type_system_union,
     500           1 :                                               &m->containers[m->n_containers + 1].type_system,
     501             :                                               key);
     502           1 :         if (r < 0)
     503           0 :                 return r;
     504             : 
     505           1 :         r = sd_netlink_message_append_string(m, type_system_union->match, key);
     506           1 :         if (r < 0)
     507           0 :                 return r;
     508             : 
     509             :         /* do we ever need non-null size */
     510           1 :         r = add_rtattr(m, type | NLA_F_NESTED, NULL, 0);
     511           1 :         if (r < 0)
     512           0 :                 return r;
     513             : 
     514           1 :         m->containers[m->n_containers++].offset = r;
     515             : 
     516           1 :         return 0;
     517             : }
     518             : 
     519          15 : int sd_netlink_message_close_container(sd_netlink_message *m) {
     520          15 :         assert_return(m, -EINVAL);
     521          15 :         assert_return(!m->sealed, -EPERM);
     522          15 :         assert_return(m->n_containers > 0, -EINVAL);
     523             : 
     524          14 :         m->containers[m->n_containers].type_system = NULL;
     525          14 :         m->containers[m->n_containers].offset = 0;
     526          14 :         m->n_containers--;
     527             : 
     528          14 :         return 0;
     529             : }
     530             : 
     531          10 : int sd_netlink_message_open_array(sd_netlink_message *m, uint16_t type) {
     532             :         int r;
     533             : 
     534          10 :         assert_return(m, -EINVAL);
     535          10 :         assert_return(!m->sealed, -EPERM);
     536          10 :         assert_return(m->n_containers > 0, -EINVAL);
     537             : 
     538          10 :         r = add_rtattr(m, type | NLA_F_NESTED, NULL, 0);
     539          10 :         if (r < 0)
     540           0 :                 return r;
     541             : 
     542          10 :         m->containers[m->n_containers].offset = r;
     543          10 :         m->n_containers++;
     544          10 :         m->containers[m->n_containers].type_system = m->containers[m->n_containers - 1].type_system;
     545             : 
     546          10 :         return 0;
     547             : }
     548             : 
     549           0 : int sd_netlink_message_cancel_array(sd_netlink_message *m) {
     550             :         unsigned i;
     551             :         uint32_t rta_len;
     552             : 
     553           0 :         assert_return(m, -EINVAL);
     554           0 :         assert_return(!m->sealed, -EPERM);
     555           0 :         assert_return(m->n_containers > 1, -EINVAL);
     556             : 
     557           0 :         rta_len = GET_CONTAINER(m, (m->n_containers - 1))->rta_len;
     558             : 
     559           0 :         for (i = 0; i < m->n_containers; i++)
     560           0 :                 GET_CONTAINER(m, i)->rta_len -= rta_len;
     561             : 
     562           0 :         m->hdr->nlmsg_len -= rta_len;
     563             : 
     564           0 :         m->n_containers--;
     565           0 :         m->containers[m->n_containers].type_system = NULL;
     566             : 
     567           0 :         return 0;
     568             : }
     569             : 
     570         147 : static int netlink_message_read_internal(sd_netlink_message *m, unsigned short type, void **data, bool *net_byteorder) {
     571             :         struct netlink_attribute *attribute;
     572             :         struct rtattr *rta;
     573             : 
     574         147 :         assert_return(m, -EINVAL);
     575         147 :         assert_return(m->sealed, -EPERM);
     576         146 :         assert_return(data, -EINVAL);
     577             : 
     578         146 :         assert(m->n_containers < RTNL_CONTAINER_DEPTH);
     579         146 :         assert(m->containers[m->n_containers].attributes);
     580         146 :         assert(type < m->containers[m->n_containers].n_attributes);
     581             : 
     582         146 :         attribute = &m->containers[m->n_containers].attributes[type];
     583             : 
     584         146 :         if (attribute->offset == 0)
     585          18 :                 return -ENODATA;
     586             : 
     587         128 :         rta = (struct rtattr*)((uint8_t *) m->hdr + attribute->offset);
     588             : 
     589         128 :         *data = RTA_DATA(rta);
     590             : 
     591         128 :         if (net_byteorder)
     592          31 :                 *net_byteorder = attribute->net_byteorder;
     593             : 
     594         128 :         return RTA_PAYLOAD(rta);
     595             : }
     596             : 
     597           0 : int sd_netlink_message_read(sd_netlink_message *m, unsigned short type, size_t size, void *data) {
     598             :         void *attr_data;
     599             :         int r;
     600             : 
     601           0 :         assert_return(m, -EINVAL);
     602             : 
     603           0 :         r = netlink_message_read_internal(m, type, &attr_data, NULL);
     604           0 :         if (r < 0)
     605           0 :                 return r;
     606             : 
     607           0 :         if ((size_t) r < size)
     608           0 :                 return -EIO;
     609             : 
     610           0 :         if (data)
     611           0 :                 memcpy(data, attr_data, size);
     612             : 
     613           0 :         return r;
     614             : }
     615             : 
     616          42 : int sd_netlink_message_read_string(sd_netlink_message *m, unsigned short type, const char **data) {
     617             :         int r;
     618             :         void *attr_data;
     619             : 
     620          42 :         assert_return(m, -EINVAL);
     621             : 
     622          42 :         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_STRING);
     623          42 :         if (r < 0)
     624           0 :                 return r;
     625             : 
     626          42 :         r = netlink_message_read_internal(m, type, &attr_data, NULL);
     627          42 :         if (r < 0)
     628           1 :                 return r;
     629          41 :         else if (strnlen(attr_data, r) >= (size_t) r)
     630           0 :                 return -EIO;
     631             : 
     632          41 :         if (data)
     633          41 :                 *data = (const char *) attr_data;
     634             : 
     635          41 :         return 0;
     636             : }
     637             : 
     638          15 : int sd_netlink_message_read_u8(sd_netlink_message *m, unsigned short type, uint8_t *data) {
     639             :         int r;
     640             :         void *attr_data;
     641             : 
     642          15 :         assert_return(m, -EINVAL);
     643             : 
     644          15 :         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U8);
     645          15 :         if (r < 0)
     646           0 :                 return r;
     647             : 
     648          15 :         r = netlink_message_read_internal(m, type, &attr_data, NULL);
     649          15 :         if (r < 0)
     650           0 :                 return r;
     651          15 :         else if ((size_t) r < sizeof(uint8_t))
     652           0 :                 return -EIO;
     653             : 
     654          15 :         if (data)
     655          15 :                 *data = *(uint8_t *) attr_data;
     656             : 
     657          15 :         return 0;
     658             : }
     659             : 
     660           1 : int sd_netlink_message_read_u16(sd_netlink_message *m, unsigned short type, uint16_t *data) {
     661             :         void *attr_data;
     662             :         bool net_byteorder;
     663             :         int r;
     664             : 
     665           1 :         assert_return(m, -EINVAL);
     666             : 
     667           1 :         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U16);
     668           1 :         if (r < 0)
     669           0 :                 return r;
     670             : 
     671           1 :         r = netlink_message_read_internal(m, type, &attr_data, &net_byteorder);
     672           1 :         if (r < 0)
     673           0 :                 return r;
     674           1 :         else if ((size_t) r < sizeof(uint16_t))
     675           0 :                 return -EIO;
     676             : 
     677           1 :         if (data) {
     678           1 :                 if (net_byteorder)
     679           0 :                         *data = be16toh(*(uint16_t *) attr_data);
     680             :                 else
     681           1 :                         *data = *(uint16_t *) attr_data;
     682             :         }
     683             : 
     684           1 :         return 0;
     685             : }
     686             : 
     687          41 : int sd_netlink_message_read_u32(sd_netlink_message *m, unsigned short type, uint32_t *data) {
     688             :         void *attr_data;
     689             :         bool net_byteorder;
     690             :         int r;
     691             : 
     692          41 :         assert_return(m, -EINVAL);
     693             : 
     694          41 :         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U32);
     695          41 :         if (r < 0)
     696           1 :                 return r;
     697             : 
     698          40 :         r = netlink_message_read_internal(m, type, &attr_data, &net_byteorder);
     699          40 :         if (r < 0)
     700          10 :                 return r;
     701          30 :         else if ((size_t)r < sizeof(uint32_t))
     702           0 :                 return -EIO;
     703             : 
     704          30 :         if (data) {
     705          30 :                 if (net_byteorder)
     706           0 :                         *data = be32toh(*(uint32_t *) attr_data);
     707             :                 else
     708          30 :                         *data = *(uint32_t *) attr_data;
     709             :         }
     710             : 
     711          30 :         return 0;
     712             : }
     713             : 
     714          14 : int sd_netlink_message_read_ether_addr(sd_netlink_message *m, unsigned short type, struct ether_addr *data) {
     715             :         int r;
     716             :         void *attr_data;
     717             : 
     718          14 :         assert_return(m, -EINVAL);
     719             : 
     720          14 :         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_ETHER_ADDR);
     721          14 :         if (r < 0)
     722           0 :                 return r;
     723             : 
     724          14 :         r = netlink_message_read_internal(m, type, &attr_data, NULL);
     725          14 :         if (r < 0)
     726           2 :                 return r;
     727          12 :         else if ((size_t)r < sizeof(struct ether_addr))
     728           0 :                 return -EIO;
     729             : 
     730          12 :         if (data)
     731          12 :                 memcpy(data, attr_data, sizeof(struct ether_addr));
     732             : 
     733          12 :         return 0;
     734             : }
     735             : 
     736           1 : int sd_netlink_message_read_cache_info(sd_netlink_message *m, unsigned short type, struct ifa_cacheinfo *info) {
     737             :         int r;
     738             :         void *attr_data;
     739             : 
     740           1 :         assert_return(m, -EINVAL);
     741             : 
     742           1 :         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_CACHE_INFO);
     743           1 :         if (r < 0)
     744           0 :                 return r;
     745             : 
     746           1 :         r = netlink_message_read_internal(m, type, &attr_data, NULL);
     747           1 :         if (r < 0)
     748           0 :                 return r;
     749           1 :         else if ((size_t)r < sizeof(struct ifa_cacheinfo))
     750           0 :                 return -EIO;
     751             : 
     752           1 :         if (info)
     753           1 :                 memcpy(info, attr_data, sizeof(struct ifa_cacheinfo));
     754             : 
     755           1 :         return 0;
     756             : }
     757             : 
     758           7 : int sd_netlink_message_read_in_addr(sd_netlink_message *m, unsigned short type, struct in_addr *data) {
     759             :         int r;
     760             :         void *attr_data;
     761             : 
     762           7 :         assert_return(m, -EINVAL);
     763             : 
     764           7 :         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
     765           7 :         if (r < 0)
     766           0 :                 return r;
     767             : 
     768           7 :         r = netlink_message_read_internal(m, type, &attr_data, NULL);
     769           7 :         if (r < 0)
     770           0 :                 return r;
     771           7 :         else if ((size_t)r < sizeof(struct in_addr))
     772           0 :                 return -EIO;
     773             : 
     774           7 :         if (data)
     775           7 :                 memcpy(data, attr_data, sizeof(struct in_addr));
     776             : 
     777           7 :         return 0;
     778             : }
     779             : 
     780           7 : int sd_netlink_message_read_in6_addr(sd_netlink_message *m, unsigned short type, struct in6_addr *data) {
     781             :         int r;
     782             :         void *attr_data;
     783             : 
     784           7 :         assert_return(m, -EINVAL);
     785             : 
     786           7 :         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
     787           7 :         if (r < 0)
     788           0 :                 return r;
     789             : 
     790           7 :         r = netlink_message_read_internal(m, type, &attr_data, NULL);
     791           7 :         if (r < 0)
     792           3 :                 return r;
     793           4 :         else if ((size_t)r < sizeof(struct in6_addr))
     794           0 :                 return -EIO;
     795             : 
     796           4 :         if (data)
     797           4 :                 memcpy(data, attr_data, sizeof(struct in6_addr));
     798             : 
     799           4 :         return 0;
     800             : }
     801             : 
     802          93 : static int netlink_container_parse(sd_netlink_message *m,
     803             :                                    struct netlink_container *container,
     804             :                                    struct rtattr *rta,
     805             :                                    unsigned rt_len) {
     806          93 :         _cleanup_free_ struct netlink_attribute *attributes = NULL;
     807          93 :         size_t n_allocated = 0;
     808             : 
     809         789 :         for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) {
     810             :                 unsigned short type;
     811             : 
     812         696 :                 type = RTA_TYPE(rta);
     813             : 
     814         696 :                 if (!GREEDY_REALLOC0(attributes, n_allocated, type + 1))
     815           0 :                         return -ENOMEM;
     816             : 
     817         696 :                 if (attributes[type].offset != 0)
     818           1 :                         log_debug("rtnl: message parse - overwriting repeated attribute");
     819             : 
     820         696 :                 attributes[type].offset = (uint8_t *) rta - (uint8_t *) m->hdr;
     821         696 :                 attributes[type].nested = RTA_FLAGS(rta) & NLA_F_NESTED;
     822         696 :                 attributes[type].net_byteorder = RTA_FLAGS(rta) & NLA_F_NET_BYTEORDER;
     823             :         }
     824             : 
     825          93 :         container->attributes = TAKE_PTR(attributes);
     826          93 :         container->n_attributes = n_allocated;
     827             : 
     828          93 :         return 0;
     829             : }
     830             : 
     831          10 : int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short type_id) {
     832             :         const NLType *nl_type;
     833             :         const NLTypeSystem *type_system;
     834             :         void *container;
     835             :         uint16_t type;
     836             :         size_t size;
     837             :         int r;
     838             : 
     839          10 :         assert_return(m, -EINVAL);
     840          10 :         assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL);
     841             : 
     842          10 :         r = type_system_get_type(m->containers[m->n_containers].type_system,
     843             :                                  &nl_type,
     844             :                                  type_id);
     845          10 :         if (r < 0)
     846           0 :                 return r;
     847             : 
     848          10 :         type = type_get_type(nl_type);
     849             : 
     850          10 :         if (type == NETLINK_TYPE_NESTED) {
     851           8 :                 r = type_system_get_type_system(m->containers[m->n_containers].type_system,
     852             :                                                 &type_system,
     853             :                                                 type_id);
     854           8 :                 if (r < 0)
     855           0 :                         return r;
     856           2 :         } else if (type == NETLINK_TYPE_UNION) {
     857             :                 const NLTypeSystemUnion *type_system_union;
     858             : 
     859           2 :                 r = type_system_get_type_system_union(m->containers[m->n_containers].type_system,
     860             :                                                       &type_system_union,
     861             :                                                       type_id);
     862           2 :                 if (r < 0)
     863           0 :                         return r;
     864             : 
     865           2 :                 switch (type_system_union->match_type) {
     866           1 :                 case NL_MATCH_SIBLING:
     867             :                 {
     868             :                         const char *key;
     869             : 
     870           1 :                         r = sd_netlink_message_read_string(m, type_system_union->match, &key);
     871           1 :                         if (r < 0)
     872           0 :                                 return r;
     873             : 
     874           1 :                         r = type_system_union_get_type_system(type_system_union,
     875             :                                                               &type_system,
     876             :                                                               key);
     877           1 :                         if (r < 0)
     878           0 :                                 return r;
     879             : 
     880           1 :                         break;
     881             :                 }
     882           1 :                 case NL_MATCH_PROTOCOL:
     883             :                 {
     884             :                         int family;
     885             : 
     886           1 :                         r = sd_rtnl_message_get_family(m, &family);
     887           1 :                         if (r < 0)
     888           0 :                                 return r;
     889             : 
     890           1 :                         r = type_system_union_protocol_get_type_system(type_system_union,
     891             :                                                                        &type_system,
     892             :                                                                        family);
     893           1 :                         if (r < 0)
     894           0 :                                 return r;
     895             : 
     896           1 :                         break;
     897             :                 }
     898           0 :                 default:
     899           0 :                         assert_not_reached("sd-netlink: invalid type system union type");
     900             :                 }
     901             :         } else
     902           0 :                 return -EINVAL;
     903             : 
     904          10 :         r = netlink_message_read_internal(m, type_id, &container, NULL);
     905          10 :         if (r < 0)
     906           3 :                 return r;
     907             : 
     908           7 :         size = (size_t)r;
     909             : 
     910           7 :         m->n_containers++;
     911             : 
     912          14 :         r = netlink_container_parse(m,
     913           7 :                                     &m->containers[m->n_containers],
     914             :                                     container,
     915             :                                     size);
     916           7 :         if (r < 0) {
     917           0 :                 m->n_containers--;
     918           0 :                 return r;
     919             :         }
     920             : 
     921           7 :         m->containers[m->n_containers].type_system = type_system;
     922             : 
     923           7 :         return 0;
     924             : }
     925             : 
     926          10 : int sd_netlink_message_enter_array(sd_netlink_message *m, unsigned short type_id) {
     927             :         void *container;
     928             :         size_t size;
     929             :         int r;
     930             : 
     931          10 :         assert_return(m, -EINVAL);
     932          10 :         assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL);
     933             : 
     934          10 :         r = netlink_message_read_internal(m, type_id, &container, NULL);
     935          10 :         if (r < 0)
     936           0 :                 return r;
     937             : 
     938          10 :         size = (size_t) r;
     939             : 
     940          10 :         m->n_containers++;
     941             : 
     942          20 :         r = netlink_container_parse(m,
     943          10 :                                     &m->containers[m->n_containers],
     944             :                                     container,
     945             :                                     size);
     946          10 :         if (r < 0) {
     947           0 :                 m->n_containers--;
     948           0 :                 return r;
     949             :         }
     950             : 
     951          10 :         m->containers[m->n_containers].type_system = m->containers[m->n_containers - 1].type_system;
     952             : 
     953          10 :         return 0;
     954             : }
     955             : 
     956          18 : int sd_netlink_message_exit_container(sd_netlink_message *m) {
     957          18 :         assert_return(m, -EINVAL);
     958          18 :         assert_return(m->sealed, -EINVAL);
     959          18 :         assert_return(m->n_containers > 0, -EINVAL);
     960             : 
     961          17 :         m->containers[m->n_containers].attributes = mfree(m->containers[m->n_containers].attributes);
     962          17 :         m->containers[m->n_containers].type_system = NULL;
     963             : 
     964          17 :         m->n_containers--;
     965             : 
     966          17 :         return 0;
     967             : }
     968             : 
     969          77 : uint32_t rtnl_message_get_serial(sd_netlink_message *m) {
     970          77 :         assert(m);
     971          77 :         assert(m->hdr);
     972             : 
     973          77 :         return m->hdr->nlmsg_seq;
     974             : }
     975             : 
     976          57 : int sd_netlink_message_is_error(sd_netlink_message *m) {
     977          57 :         assert_return(m, 0);
     978          57 :         assert_return(m->hdr, 0);
     979             : 
     980          57 :         return m->hdr->nlmsg_type == NLMSG_ERROR;
     981             : }
     982             : 
     983          51 : int sd_netlink_message_get_errno(sd_netlink_message *m) {
     984             :         struct nlmsgerr *err;
     985             : 
     986          51 :         assert_return(m, -EINVAL);
     987          51 :         assert_return(m->hdr, -EINVAL);
     988             : 
     989          51 :         if (!sd_netlink_message_is_error(m))
     990          47 :                 return 0;
     991             : 
     992           4 :         err = NLMSG_DATA(m->hdr);
     993             : 
     994           4 :         return err->error;
     995             : }
     996             : 
     997          76 : int sd_netlink_message_rewind(sd_netlink_message *m) {
     998             :         const NLType *nl_type;
     999             :         const NLTypeSystem *type_system_root;
    1000             :         uint16_t type;
    1001             :         size_t size;
    1002             :         unsigned i;
    1003             :         int r;
    1004             : 
    1005          76 :         assert_return(m, -EINVAL);
    1006             : 
    1007             :         /* don't allow appending to message once parsed */
    1008          76 :         if (!m->sealed)
    1009          74 :                 rtnl_message_seal(m);
    1010             : 
    1011          76 :         type_system_root = type_system_get_root(m->protocol);
    1012             : 
    1013          76 :         for (i = 1; i <= m->n_containers; i++)
    1014           0 :                 m->containers[i].attributes = mfree(m->containers[i].attributes);
    1015             : 
    1016          76 :         m->n_containers = 0;
    1017             : 
    1018          76 :         if (m->containers[0].attributes)
    1019             :                 /* top-level attributes have already been parsed */
    1020           0 :                 return 0;
    1021             : 
    1022          76 :         assert(m->hdr);
    1023             : 
    1024          76 :         r = type_system_get_type(type_system_root, &nl_type, m->hdr->nlmsg_type);
    1025          76 :         if (r < 0)
    1026           0 :                 return r;
    1027             : 
    1028          76 :         type = type_get_type(nl_type);
    1029          76 :         size = type_get_size(nl_type);
    1030             : 
    1031          76 :         if (type == NETLINK_TYPE_NESTED) {
    1032             :                 const NLTypeSystem *type_system;
    1033             : 
    1034          76 :                 type_get_type_system(nl_type, &type_system);
    1035             : 
    1036          76 :                 m->containers[0].type_system = type_system;
    1037             : 
    1038         228 :                 r = netlink_container_parse(m,
    1039          76 :                                             &m->containers[m->n_containers],
    1040          76 :                                             (struct rtattr*)((uint8_t*)NLMSG_DATA(m->hdr) + NLMSG_ALIGN(size)),
    1041          76 :                                             NLMSG_PAYLOAD(m->hdr, size));
    1042          76 :                 if (r < 0)
    1043           0 :                         return r;
    1044             :         }
    1045             : 
    1046          76 :         return 0;
    1047             : }
    1048             : 
    1049         101 : void rtnl_message_seal(sd_netlink_message *m) {
    1050         101 :         assert(m);
    1051         101 :         assert(!m->sealed);
    1052             : 
    1053         101 :         m->sealed = true;
    1054         101 : }
    1055             : 
    1056          50 : sd_netlink_message *sd_netlink_message_next(sd_netlink_message *m) {
    1057          50 :         assert_return(m, NULL);
    1058             : 
    1059          50 :         return m->next;
    1060             : }

Generated by: LCOV version 1.14