LCOV - code coverage report
Current view: top level - libsystemd/sd-netlink - netlink-message.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 415 569 72.9 %
Date: 2019-08-23 13:36:53 Functions: 39 50 78.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 276 605 45.6 %

           Branch data     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                 :        452 : int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret) {
      25                 :            :         sd_netlink_message *m;
      26                 :            : 
      27   [ -  +  -  + ]:        452 :         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                 :        452 :         m = new0(sd_netlink_message, 1);
      35         [ -  + ]:        452 :         if (!m)
      36                 :          0 :                 return -ENOMEM;
      37                 :            : 
      38                 :        452 :         m->n_ref = 1;
      39                 :        452 :         m->protocol = rtnl->protocol;
      40                 :        452 :         m->sealed = false;
      41                 :            : 
      42                 :        452 :         *ret = m;
      43                 :            : 
      44                 :        452 :         return 0;
      45                 :            : }
      46                 :            : 
      47                 :        124 : int message_new(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t type) {
      48                 :        124 :         _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   [ -  +  -  + ]:        124 :         assert_return(rtnl, -EINVAL);
      55                 :            : 
      56                 :        124 :         type_system_root = type_system_get_root(rtnl->protocol);
      57                 :            : 
      58                 :        124 :         r = type_system_get_type(type_system_root, &nl_type, type);
      59         [ -  + ]:        124 :         if (r < 0)
      60                 :          0 :                 return r;
      61                 :            : 
      62         [ -  + ]:        124 :         if (type_get_type(nl_type) != NETLINK_TYPE_NESTED)
      63                 :          0 :                 return -EINVAL;
      64                 :            : 
      65                 :        124 :         r = message_new_empty(rtnl, &m);
      66         [ -  + ]:        124 :         if (r < 0)
      67                 :          0 :                 return r;
      68                 :            : 
      69                 :        124 :         size = NLMSG_SPACE(type_get_size(nl_type));
      70                 :            : 
      71         [ -  + ]:        124 :         assert(size >= sizeof(struct nlmsghdr));
      72                 :        124 :         m->hdr = malloc0(size);
      73         [ -  + ]:        124 :         if (!m->hdr)
      74                 :          0 :                 return -ENOMEM;
      75                 :            : 
      76                 :        124 :         m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
      77                 :            : 
      78                 :        124 :         type_get_type_system(nl_type, &m->containers[0].type_system);
      79                 :        124 :         m->hdr->nlmsg_len = size;
      80                 :        124 :         m->hdr->nlmsg_type = type;
      81                 :            : 
      82                 :        124 :         *ret = TAKE_PTR(m);
      83                 :            : 
      84                 :        124 :         return 0;
      85                 :            : }
      86                 :            : 
      87                 :          8 : int sd_netlink_message_request_dump(sd_netlink_message *m, int dump) {
      88   [ -  +  -  + ]:          8 :         assert_return(m, -EINVAL);
      89   [ -  +  -  + ]:          8 :         assert_return(m->hdr, -EINVAL);
      90                 :            : 
      91   [ +  -  -  +  :          8 :         assert_return(IN_SET(m->hdr->nlmsg_type, RTM_GETLINK, RTM_GETADDR, RTM_GETROUTE, RTM_GETNEIGH, RTM_GETRULE, RTM_GETADDRLABEL), -EINVAL);
                   -  + ]
      92                 :            : 
      93         [ +  - ]:          8 :         SET_FLAG(m->hdr->nlmsg_flags, NLM_F_DUMP, dump);
      94                 :            : 
      95                 :          8 :         return 0;
      96                 :            : }
      97                 :            : 
      98   [ #  #  #  # ]:          0 : DEFINE_TRIVIAL_REF_FUNC(sd_netlink_message, sd_netlink_message);
      99                 :            : 
     100                 :        228 : sd_netlink_message *sd_netlink_message_unref(sd_netlink_message *m) {
     101   [ +  +  +  - ]:        680 :         while (m && --m->n_ref == 0) {
     102                 :            :                 unsigned i;
     103                 :            : 
     104                 :        452 :                 free(m->hdr);
     105                 :            : 
     106         [ +  + ]:        904 :                 for (i = 0; i <= m->n_containers; i++)
     107                 :        452 :                         free(m->containers[i].attributes);
     108                 :            : 
     109                 :        452 :                 sd_netlink_message *t = m;
     110                 :        452 :                 m = m->next;
     111                 :        452 :                 free(t);
     112                 :            :         }
     113                 :            : 
     114                 :        228 :         return NULL;
     115                 :            : }
     116                 :            : 
     117                 :        344 : int sd_netlink_message_get_type(sd_netlink_message *m, uint16_t *type) {
     118   [ -  +  -  + ]:        344 :         assert_return(m, -EINVAL);
     119   [ -  +  -  + ]:        344 :         assert_return(type, -EINVAL);
     120                 :            : 
     121                 :        344 :         *type = m->hdr->nlmsg_type;
     122                 :            : 
     123                 :        344 :         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                 :         40 : int sd_netlink_message_is_broadcast(sd_netlink_message *m) {
     136   [ -  +  -  + ]:         40 :         assert_return(m, -EINVAL);
     137                 :            : 
     138                 :         40 :         return m->broadcast;
     139                 :            : }
     140                 :            : 
     141                 :            : /* If successful the updated message will be correctly aligned, if
     142                 :            :    unsuccessful the old message is untouched. */
     143                 :        212 : 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         [ -  + ]:        212 :         assert(m);
     153         [ -  + ]:        212 :         assert(m->hdr);
     154         [ -  + ]:        212 :         assert(!m->sealed);
     155         [ -  + ]:        212 :         assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
     156   [ +  +  -  + ]:        212 :         assert(!data || data_length);
     157                 :            : 
     158                 :            :         /* get offset of the new attribute */
     159                 :        212 :         offset = m->hdr->nlmsg_len;
     160                 :            : 
     161                 :            :         /* get the size of the new rta attribute (with padding at the end) */
     162                 :        212 :         rta_length = RTA_LENGTH(data_length);
     163                 :            : 
     164                 :            :         /* get the new message size (with padding at the end) */
     165                 :        212 :         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         [ -  + ]:        212 :         if (message_length > MIN(page_size(), 8192UL))
     169                 :          0 :                 return -ENOBUFS;
     170                 :            : 
     171                 :            :         /* realloc to fit the new attribute */
     172                 :        212 :         new_hdr = realloc(m->hdr, message_length);
     173         [ -  + ]:        212 :         if (!new_hdr)
     174                 :          0 :                 return -ENOMEM;
     175                 :        212 :         m->hdr = new_hdr;
     176                 :            : 
     177                 :            :         /* get pointer to the attribute we are about to add */
     178                 :        212 :         rta = (struct rtattr *) ((uint8_t *) m->hdr + offset);
     179                 :            : 
     180                 :            :         /* if we are inside containers, extend them */
     181         [ +  + ]:        436 :         for (i = 0; i < m->n_containers; i++)
     182   [ +  -  +  - ]:        224 :                 GET_CONTAINER(m, i)->rta_len += message_length - offset;
     183                 :            : 
     184                 :            :         /* fill in the attribute */
     185                 :        212 :         rta->rta_type = type;
     186                 :        212 :         rta->rta_len = rta_length;
     187         [ +  + ]:        212 :         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                 :        156 :                 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                 :         56 :                 padding = RTA_DATA(rta);
     197                 :            : 
     198                 :            :         /* make sure also the padding at the end of the message is initialized */
     199                 :        212 :         padding_length = (uint8_t*)m->hdr + message_length - (uint8_t*)padding;
     200         [ +  + ]:        212 :         memzero(padding, padding_length);
     201                 :            : 
     202                 :            :         /* update message size */
     203                 :        212 :         m->hdr->nlmsg_len = message_length;
     204                 :            : 
     205                 :        212 :         return offset;
     206                 :            : }
     207                 :            : 
     208                 :        720 : 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         [ -  + ]:        720 :         assert(m);
     213                 :            : 
     214                 :        720 :         r = type_system_get_type(m->containers[m->n_containers].type_system, &type, attribute_type);
     215         [ -  + ]:        720 :         if (r < 0)
     216                 :          0 :                 return r;
     217                 :            : 
     218         [ +  + ]:        720 :         if (type_get_type(type) != data_type)
     219                 :          8 :                 return -EINVAL;
     220                 :            : 
     221         [ +  + ]:        712 :         if (out_size)
     222                 :         64 :                 *out_size = type_get_size(type);
     223                 :        712 :         return 0;
     224                 :            : }
     225                 :            : 
     226                 :         52 : 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   [ -  +  -  + ]:         52 :         assert_return(m, -EINVAL);
     231   [ -  +  -  + ]:         52 :         assert_return(!m->sealed, -EPERM);
     232   [ -  +  -  + ]:         52 :         assert_return(data, -EINVAL);
     233                 :            : 
     234                 :         52 :         r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_STRING);
     235         [ -  + ]:         52 :         if (r < 0)
     236                 :          0 :                 return r;
     237                 :            : 
     238         [ +  + ]:         52 :         if (size) {
     239                 :          4 :                 length = strnlen(data, size+1);
     240         [ -  + ]:          4 :                 if (length > size)
     241                 :          0 :                         return -EINVAL;
     242                 :            :         } else
     243                 :         48 :                 length = strlen(data);
     244                 :            : 
     245                 :         52 :         r = add_rtattr(m, type, data, length + 1);
     246         [ -  + ]:         52 :         if (r < 0)
     247                 :          0 :                 return r;
     248                 :            : 
     249                 :         52 :         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                 :         12 : int sd_netlink_message_append_u8(sd_netlink_message *m, unsigned short type, uint8_t data) {
     271                 :            :         int r;
     272                 :            : 
     273   [ -  +  -  + ]:         12 :         assert_return(m, -EINVAL);
     274   [ -  +  -  + ]:         12 :         assert_return(!m->sealed, -EPERM);
     275                 :            : 
     276                 :         12 :         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U8);
     277         [ -  + ]:         12 :         if (r < 0)
     278                 :          0 :                 return r;
     279                 :            : 
     280                 :         12 :         r = add_rtattr(m, type, &data, sizeof(uint8_t));
     281         [ -  + ]:         12 :         if (r < 0)
     282                 :          0 :                 return r;
     283                 :            : 
     284                 :         12 :         return 0;
     285                 :            : }
     286                 :            : 
     287                 :          4 : int sd_netlink_message_append_u16(sd_netlink_message *m, unsigned short type, uint16_t data) {
     288                 :            :         int r;
     289                 :            : 
     290   [ -  +  -  + ]:          4 :         assert_return(m, -EINVAL);
     291   [ -  +  -  + ]:          4 :         assert_return(!m->sealed, -EPERM);
     292                 :            : 
     293                 :          4 :         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U16);
     294         [ -  + ]:          4 :         if (r < 0)
     295                 :          0 :                 return r;
     296                 :            : 
     297                 :          4 :         r = add_rtattr(m, type, &data, sizeof(uint16_t));
     298         [ -  + ]:          4 :         if (r < 0)
     299                 :          0 :                 return r;
     300                 :            : 
     301                 :          4 :         return 0;
     302                 :            : }
     303                 :            : 
     304                 :         72 : int sd_netlink_message_append_u32(sd_netlink_message *m, unsigned short type, uint32_t data) {
     305                 :            :         int r;
     306                 :            : 
     307   [ -  +  -  + ]:         72 :         assert_return(m, -EINVAL);
     308   [ -  +  -  + ]:         72 :         assert_return(!m->sealed, -EPERM);
     309                 :            : 
     310                 :         72 :         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U32);
     311         [ -  + ]:         72 :         if (r < 0)
     312                 :          0 :                 return r;
     313                 :            : 
     314                 :         72 :         r = add_rtattr(m, type, &data, sizeof(uint32_t));
     315         [ -  + ]:         72 :         if (r < 0)
     316                 :          0 :                 return r;
     317                 :            : 
     318                 :         72 :         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                 :         12 : 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   [ -  +  -  + ]:         12 :         assert_return(m, -EINVAL);
     355   [ -  +  -  + ]:         12 :         assert_return(!m->sealed, -EPERM);
     356   [ -  +  -  + ]:         12 :         assert_return(data, -EINVAL);
     357   [ +  -  -  +  :         12 :         assert_return(IN_SET(family, AF_INET, AF_INET6), -EINVAL);
                   -  + ]
     358                 :            : 
     359                 :         12 :         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
     360         [ -  + ]:         12 :         if (r < 0)
     361                 :          0 :                 return r;
     362                 :            : 
     363                 :         12 :         r = add_rtattr(m, type, data, FAMILY_ADDRESS_SIZE(family));
     364         [ -  + ]:         12 :         if (r < 0)
     365                 :          0 :                 return r;
     366                 :            : 
     367                 :         12 :         return 0;
     368                 :            : }
     369                 :            : 
     370                 :          8 : int sd_netlink_message_append_in_addr(sd_netlink_message *m, unsigned short type, const struct in_addr *data) {
     371                 :          8 :         return netlink_message_append_in_addr_union(m, type, AF_INET, (const union in_addr_union *) data);
     372                 :            : }
     373                 :            : 
     374                 :          4 : int sd_netlink_message_append_in6_addr(sd_netlink_message *m, unsigned short type, const struct in6_addr *data) {
     375                 :          4 :         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                 :          4 : int sd_netlink_message_append_ether_addr(sd_netlink_message *m, unsigned short type, const struct ether_addr *data) {
     406                 :            :         int r;
     407                 :            : 
     408   [ -  +  -  + ]:          4 :         assert_return(m, -EINVAL);
     409   [ -  +  -  + ]:          4 :         assert_return(!m->sealed, -EPERM);
     410   [ -  +  -  + ]:          4 :         assert_return(data, -EINVAL);
     411                 :            : 
     412                 :          4 :         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_ETHER_ADDR);
     413         [ -  + ]:          4 :         if (r < 0)
     414                 :          0 :                 return r;
     415                 :            : 
     416                 :          4 :         r = add_rtattr(m, type, data, ETH_ALEN);
     417         [ -  + ]:          4 :         if (r < 0)
     418                 :          0 :                 return r;
     419                 :            : 
     420                 :          4 :         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                 :         12 : int sd_netlink_message_open_container(sd_netlink_message *m, unsigned short type) {
     442                 :            :         size_t size;
     443                 :            :         int r;
     444                 :            : 
     445   [ -  +  -  + ]:         12 :         assert_return(m, -EINVAL);
     446   [ -  +  -  + ]:         12 :         assert_return(!m->sealed, -EPERM);
     447   [ -  +  -  + ]:         12 :         assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -ERANGE);
     448                 :            : 
     449                 :         12 :         r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_NESTED);
     450         [ +  + ]:         12 :         if (r < 0) {
     451                 :            :                 const NLTypeSystemUnion *type_system_union;
     452                 :            :                 int family;
     453                 :            : 
     454                 :          4 :                 r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_UNION);
     455         [ -  + ]:          4 :                 if (r < 0)
     456                 :          0 :                         return r;
     457                 :            : 
     458                 :          4 :                 r = sd_rtnl_message_get_family(m, &family);
     459         [ -  + ]:          4 :                 if (r < 0)
     460                 :          0 :                         return r;
     461                 :            : 
     462                 :          4 :                 r = type_system_get_type_system_union(m->containers[m->n_containers].type_system, &type_system_union, type);
     463         [ -  + ]:          4 :                 if (r < 0)
     464                 :          0 :                         return r;
     465                 :            : 
     466                 :          8 :                 r = type_system_union_protocol_get_type_system(type_system_union,
     467                 :          4 :                                                                &m->containers[m->n_containers + 1].type_system,
     468                 :            :                                                                family);
     469         [ -  + ]:          4 :                 if (r < 0)
     470                 :          0 :                         return r;
     471                 :            :         } else {
     472                 :         16 :                 r = type_system_get_type_system(m->containers[m->n_containers].type_system,
     473                 :          8 :                                                 &m->containers[m->n_containers + 1].type_system,
     474                 :            :                                                 type);
     475         [ -  + ]:          8 :                 if (r < 0)
     476                 :          0 :                         return r;
     477                 :            :         }
     478                 :            : 
     479                 :         12 :         r = add_rtattr(m, type | NLA_F_NESTED, NULL, size);
     480         [ -  + ]:         12 :         if (r < 0)
     481                 :          0 :                 return r;
     482                 :            : 
     483                 :         12 :         m->containers[m->n_containers++].offset = r;
     484                 :            : 
     485                 :         12 :         return 0;
     486                 :            : }
     487                 :            : 
     488                 :          4 : 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   [ -  +  -  + ]:          4 :         assert_return(m, -EINVAL);
     493   [ -  +  -  + ]:          4 :         assert_return(!m->sealed, -EPERM);
     494                 :            : 
     495                 :          4 :         r = type_system_get_type_system_union(m->containers[m->n_containers].type_system, &type_system_union, type);
     496         [ -  + ]:          4 :         if (r < 0)
     497                 :          0 :                 return r;
     498                 :            : 
     499                 :          4 :         r = type_system_union_get_type_system(type_system_union,
     500                 :          4 :                                               &m->containers[m->n_containers + 1].type_system,
     501                 :            :                                               key);
     502         [ -  + ]:          4 :         if (r < 0)
     503                 :          0 :                 return r;
     504                 :            : 
     505                 :          4 :         r = sd_netlink_message_append_string(m, type_system_union->match, key);
     506         [ -  + ]:          4 :         if (r < 0)
     507                 :          0 :                 return r;
     508                 :            : 
     509                 :            :         /* do we ever need non-null size */
     510                 :          4 :         r = add_rtattr(m, type | NLA_F_NESTED, NULL, 0);
     511         [ -  + ]:          4 :         if (r < 0)
     512                 :          0 :                 return r;
     513                 :            : 
     514                 :          4 :         m->containers[m->n_containers++].offset = r;
     515                 :            : 
     516                 :          4 :         return 0;
     517                 :            : }
     518                 :            : 
     519                 :         60 : int sd_netlink_message_close_container(sd_netlink_message *m) {
     520   [ -  +  -  + ]:         60 :         assert_return(m, -EINVAL);
     521   [ -  +  -  + ]:         60 :         assert_return(!m->sealed, -EPERM);
     522   [ +  +  +  + ]:         60 :         assert_return(m->n_containers > 0, -EINVAL);
     523                 :            : 
     524                 :         56 :         m->containers[m->n_containers].type_system = NULL;
     525                 :         56 :         m->containers[m->n_containers].offset = 0;
     526                 :         56 :         m->n_containers--;
     527                 :            : 
     528                 :         56 :         return 0;
     529                 :            : }
     530                 :            : 
     531                 :         40 : int sd_netlink_message_open_array(sd_netlink_message *m, uint16_t type) {
     532                 :            :         int r;
     533                 :            : 
     534   [ -  +  -  + ]:         40 :         assert_return(m, -EINVAL);
     535   [ -  +  -  + ]:         40 :         assert_return(!m->sealed, -EPERM);
     536   [ -  +  -  + ]:         40 :         assert_return(m->n_containers > 0, -EINVAL);
     537                 :            : 
     538                 :         40 :         r = add_rtattr(m, type | NLA_F_NESTED, NULL, 0);
     539         [ -  + ]:         40 :         if (r < 0)
     540                 :          0 :                 return r;
     541                 :            : 
     542                 :         40 :         m->containers[m->n_containers].offset = r;
     543                 :         40 :         m->n_containers++;
     544                 :         40 :         m->containers[m->n_containers].type_system = m->containers[m->n_containers - 1].type_system;
     545                 :            : 
     546                 :         40 :         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                 :        628 : 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   [ -  +  -  + ]:        628 :         assert_return(m, -EINVAL);
     575   [ +  +  +  + ]:        628 :         assert_return(m->sealed, -EPERM);
     576   [ -  +  -  + ]:        624 :         assert_return(data, -EINVAL);
     577                 :            : 
     578         [ -  + ]:        624 :         assert(m->n_containers < RTNL_CONTAINER_DEPTH);
     579         [ -  + ]:        624 :         assert(m->containers[m->n_containers].attributes);
     580         [ -  + ]:        624 :         assert(type < m->containers[m->n_containers].n_attributes);
     581                 :            : 
     582                 :        624 :         attribute = &m->containers[m->n_containers].attributes[type];
     583                 :            : 
     584         [ +  + ]:        624 :         if (attribute->offset == 0)
     585                 :         88 :                 return -ENODATA;
     586                 :            : 
     587                 :        536 :         rta = (struct rtattr*)((uint8_t *) m->hdr + attribute->offset);
     588                 :            : 
     589                 :        536 :         *data = RTA_DATA(rta);
     590                 :            : 
     591         [ +  + ]:        536 :         if (net_byteorder)
     592                 :        120 :                 *net_byteorder = attribute->net_byteorder;
     593                 :            : 
     594                 :        536 :         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                 :        184 : 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   [ -  +  -  + ]:        184 :         assert_return(m, -EINVAL);
     621                 :            : 
     622                 :        184 :         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_STRING);
     623         [ -  + ]:        184 :         if (r < 0)
     624                 :          0 :                 return r;
     625                 :            : 
     626                 :        184 :         r = netlink_message_read_internal(m, type, &attr_data, NULL);
     627         [ +  + ]:        184 :         if (r < 0)
     628                 :          4 :                 return r;
     629         [ -  + ]:        180 :         else if (strnlen(attr_data, r) >= (size_t) r)
     630                 :          0 :                 return -EIO;
     631                 :            : 
     632         [ +  - ]:        180 :         if (data)
     633                 :        180 :                 *data = (const char *) attr_data;
     634                 :            : 
     635                 :        180 :         return 0;
     636                 :            : }
     637                 :            : 
     638                 :         68 : 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   [ -  +  -  + ]:         68 :         assert_return(m, -EINVAL);
     643                 :            : 
     644                 :         68 :         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U8);
     645         [ -  + ]:         68 :         if (r < 0)
     646                 :          0 :                 return r;
     647                 :            : 
     648                 :         68 :         r = netlink_message_read_internal(m, type, &attr_data, NULL);
     649         [ -  + ]:         68 :         if (r < 0)
     650                 :          0 :                 return r;
     651         [ -  + ]:         68 :         else if ((size_t) r < sizeof(uint8_t))
     652                 :          0 :                 return -EIO;
     653                 :            : 
     654         [ +  - ]:         68 :         if (data)
     655                 :         68 :                 *data = *(uint8_t *) attr_data;
     656                 :            : 
     657                 :         68 :         return 0;
     658                 :            : }
     659                 :            : 
     660                 :          4 : 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   [ -  +  -  + ]:          4 :         assert_return(m, -EINVAL);
     666                 :            : 
     667                 :          4 :         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U16);
     668         [ -  + ]:          4 :         if (r < 0)
     669                 :          0 :                 return r;
     670                 :            : 
     671                 :          4 :         r = netlink_message_read_internal(m, type, &attr_data, &net_byteorder);
     672         [ -  + ]:          4 :         if (r < 0)
     673                 :          0 :                 return r;
     674         [ -  + ]:          4 :         else if ((size_t) r < sizeof(uint16_t))
     675                 :          0 :                 return -EIO;
     676                 :            : 
     677         [ +  - ]:          4 :         if (data) {
     678         [ -  + ]:          4 :                 if (net_byteorder)
     679                 :          0 :                         *data = be16toh(*(uint16_t *) attr_data);
     680                 :            :                 else
     681                 :          4 :                         *data = *(uint16_t *) attr_data;
     682                 :            :         }
     683                 :            : 
     684                 :          4 :         return 0;
     685                 :            : }
     686                 :            : 
     687                 :        168 : 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   [ -  +  -  + ]:        168 :         assert_return(m, -EINVAL);
     693                 :            : 
     694                 :        168 :         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U32);
     695         [ +  + ]:        168 :         if (r < 0)
     696                 :          4 :                 return r;
     697                 :            : 
     698                 :        164 :         r = netlink_message_read_internal(m, type, &attr_data, &net_byteorder);
     699         [ +  + ]:        164 :         if (r < 0)
     700                 :         48 :                 return r;
     701         [ -  + ]:        116 :         else if ((size_t)r < sizeof(uint32_t))
     702                 :          0 :                 return -EIO;
     703                 :            : 
     704         [ +  - ]:        116 :         if (data) {
     705         [ -  + ]:        116 :                 if (net_byteorder)
     706                 :          0 :                         *data = be32toh(*(uint32_t *) attr_data);
     707                 :            :                 else
     708                 :        116 :                         *data = *(uint32_t *) attr_data;
     709                 :            :         }
     710                 :            : 
     711                 :        116 :         return 0;
     712                 :            : }
     713                 :            : 
     714                 :         64 : 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   [ -  +  -  + ]:         64 :         assert_return(m, -EINVAL);
     719                 :            : 
     720                 :         64 :         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_ETHER_ADDR);
     721         [ -  + ]:         64 :         if (r < 0)
     722                 :          0 :                 return r;
     723                 :            : 
     724                 :         64 :         r = netlink_message_read_internal(m, type, &attr_data, NULL);
     725         [ +  + ]:         64 :         if (r < 0)
     726                 :         16 :                 return r;
     727         [ -  + ]:         48 :         else if ((size_t)r < sizeof(struct ether_addr))
     728                 :          0 :                 return -EIO;
     729                 :            : 
     730         [ +  - ]:         48 :         if (data)
     731                 :         48 :                 memcpy(data, attr_data, sizeof(struct ether_addr));
     732                 :            : 
     733                 :         48 :         return 0;
     734                 :            : }
     735                 :            : 
     736                 :          4 : 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   [ -  +  -  + ]:          4 :         assert_return(m, -EINVAL);
     741                 :            : 
     742                 :          4 :         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_CACHE_INFO);
     743         [ -  + ]:          4 :         if (r < 0)
     744                 :          0 :                 return r;
     745                 :            : 
     746                 :          4 :         r = netlink_message_read_internal(m, type, &attr_data, NULL);
     747         [ -  + ]:          4 :         if (r < 0)
     748                 :          0 :                 return r;
     749         [ -  + ]:          4 :         else if ((size_t)r < sizeof(struct ifa_cacheinfo))
     750                 :          0 :                 return -EIO;
     751                 :            : 
     752         [ +  - ]:          4 :         if (info)
     753                 :          4 :                 memcpy(info, attr_data, sizeof(struct ifa_cacheinfo));
     754                 :            : 
     755                 :          4 :         return 0;
     756                 :            : }
     757                 :            : 
     758                 :         32 : 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   [ -  +  -  + ]:         32 :         assert_return(m, -EINVAL);
     763                 :            : 
     764                 :         32 :         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
     765         [ -  + ]:         32 :         if (r < 0)
     766                 :          0 :                 return r;
     767                 :            : 
     768                 :         32 :         r = netlink_message_read_internal(m, type, &attr_data, NULL);
     769         [ -  + ]:         32 :         if (r < 0)
     770                 :          0 :                 return r;
     771         [ -  + ]:         32 :         else if ((size_t)r < sizeof(struct in_addr))
     772                 :          0 :                 return -EIO;
     773                 :            : 
     774         [ +  - ]:         32 :         if (data)
     775                 :         32 :                 memcpy(data, attr_data, sizeof(struct in_addr));
     776                 :            : 
     777                 :         32 :         return 0;
     778                 :            : }
     779                 :            : 
     780                 :         24 : 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   [ -  +  -  + ]:         24 :         assert_return(m, -EINVAL);
     785                 :            : 
     786                 :         24 :         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
     787         [ -  + ]:         24 :         if (r < 0)
     788                 :          0 :                 return r;
     789                 :            : 
     790                 :         24 :         r = netlink_message_read_internal(m, type, &attr_data, NULL);
     791         [ +  + ]:         24 :         if (r < 0)
     792                 :         12 :                 return r;
     793         [ -  + ]:         12 :         else if ((size_t)r < sizeof(struct in6_addr))
     794                 :          0 :                 return -EIO;
     795                 :            : 
     796         [ +  - ]:         12 :         if (data)
     797                 :         12 :                 memcpy(data, attr_data, sizeof(struct in6_addr));
     798                 :            : 
     799                 :         12 :         return 0;
     800                 :            : }
     801                 :            : 
     802                 :        416 : static int netlink_container_parse(sd_netlink_message *m,
     803                 :            :                                    struct netlink_container *container,
     804                 :            :                                    struct rtattr *rta,
     805                 :            :                                    unsigned rt_len) {
     806                 :        416 :         _cleanup_free_ struct netlink_attribute *attributes = NULL;
     807                 :        416 :         size_t n_allocated = 0;
     808                 :            : 
     809   [ +  +  +  +  :       3480 :         for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) {
                   +  + ]
     810                 :            :                 unsigned short type;
     811                 :            : 
     812                 :       3064 :                 type = RTA_TYPE(rta);
     813                 :            : 
     814         [ -  + ]:       3064 :                 if (!GREEDY_REALLOC0(attributes, n_allocated, type + 1))
     815                 :          0 :                         return -ENOMEM;
     816                 :            : 
     817         [ +  + ]:       3064 :                 if (attributes[type].offset != 0)
     818         [ -  + ]:          4 :                         log_debug("rtnl: message parse - overwriting repeated attribute");
     819                 :            : 
     820                 :       3064 :                 attributes[type].offset = (uint8_t *) rta - (uint8_t *) m->hdr;
     821                 :       3064 :                 attributes[type].nested = RTA_FLAGS(rta) & NLA_F_NESTED;
     822                 :       3064 :                 attributes[type].net_byteorder = RTA_FLAGS(rta) & NLA_F_NET_BYTEORDER;
     823                 :            :         }
     824                 :            : 
     825                 :        416 :         container->attributes = TAKE_PTR(attributes);
     826                 :        416 :         container->n_attributes = n_allocated;
     827                 :            : 
     828                 :        416 :         return 0;
     829                 :            : }
     830                 :            : 
     831                 :         44 : 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   [ -  +  -  + ]:         44 :         assert_return(m, -EINVAL);
     840   [ -  +  -  + ]:         44 :         assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL);
     841                 :            : 
     842                 :         44 :         r = type_system_get_type(m->containers[m->n_containers].type_system,
     843                 :            :                                  &nl_type,
     844                 :            :                                  type_id);
     845         [ -  + ]:         44 :         if (r < 0)
     846                 :          0 :                 return r;
     847                 :            : 
     848                 :         44 :         type = type_get_type(nl_type);
     849                 :            : 
     850         [ +  + ]:         44 :         if (type == NETLINK_TYPE_NESTED) {
     851                 :         36 :                 r = type_system_get_type_system(m->containers[m->n_containers].type_system,
     852                 :            :                                                 &type_system,
     853                 :            :                                                 type_id);
     854         [ -  + ]:         36 :                 if (r < 0)
     855                 :          0 :                         return r;
     856         [ +  - ]:          8 :         } else if (type == NETLINK_TYPE_UNION) {
     857                 :            :                 const NLTypeSystemUnion *type_system_union;
     858                 :            : 
     859                 :          8 :                 r = type_system_get_type_system_union(m->containers[m->n_containers].type_system,
     860                 :            :                                                       &type_system_union,
     861                 :            :                                                       type_id);
     862         [ -  + ]:          8 :                 if (r < 0)
     863                 :          0 :                         return r;
     864                 :            : 
     865      [ +  +  - ]:          8 :                 switch (type_system_union->match_type) {
     866                 :          4 :                 case NL_MATCH_SIBLING:
     867                 :            :                 {
     868                 :            :                         const char *key;
     869                 :            : 
     870                 :          4 :                         r = sd_netlink_message_read_string(m, type_system_union->match, &key);
     871         [ -  + ]:          4 :                         if (r < 0)
     872                 :          0 :                                 return r;
     873                 :            : 
     874                 :          4 :                         r = type_system_union_get_type_system(type_system_union,
     875                 :            :                                                               &type_system,
     876                 :            :                                                               key);
     877         [ -  + ]:          4 :                         if (r < 0)
     878                 :          0 :                                 return r;
     879                 :            : 
     880                 :          4 :                         break;
     881                 :            :                 }
     882                 :          4 :                 case NL_MATCH_PROTOCOL:
     883                 :            :                 {
     884                 :            :                         int family;
     885                 :            : 
     886                 :          4 :                         r = sd_rtnl_message_get_family(m, &family);
     887         [ -  + ]:          4 :                         if (r < 0)
     888                 :          0 :                                 return r;
     889                 :            : 
     890                 :          4 :                         r = type_system_union_protocol_get_type_system(type_system_union,
     891                 :            :                                                                        &type_system,
     892                 :            :                                                                        family);
     893         [ -  + ]:          4 :                         if (r < 0)
     894                 :          0 :                                 return r;
     895                 :            : 
     896                 :          4 :                         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                 :         44 :         r = netlink_message_read_internal(m, type_id, &container, NULL);
     905         [ +  + ]:         44 :         if (r < 0)
     906                 :         12 :                 return r;
     907                 :            : 
     908                 :         32 :         size = (size_t)r;
     909                 :            : 
     910                 :         32 :         m->n_containers++;
     911                 :            : 
     912                 :         64 :         r = netlink_container_parse(m,
     913                 :         32 :                                     &m->containers[m->n_containers],
     914                 :            :                                     container,
     915                 :            :                                     size);
     916         [ -  + ]:         32 :         if (r < 0) {
     917                 :          0 :                 m->n_containers--;
     918                 :          0 :                 return r;
     919                 :            :         }
     920                 :            : 
     921                 :         32 :         m->containers[m->n_containers].type_system = type_system;
     922                 :            : 
     923                 :         32 :         return 0;
     924                 :            : }
     925                 :            : 
     926                 :         40 : 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   [ -  +  -  + ]:         40 :         assert_return(m, -EINVAL);
     932   [ -  +  -  + ]:         40 :         assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL);
     933                 :            : 
     934                 :         40 :         r = netlink_message_read_internal(m, type_id, &container, NULL);
     935         [ -  + ]:         40 :         if (r < 0)
     936                 :          0 :                 return r;
     937                 :            : 
     938                 :         40 :         size = (size_t) r;
     939                 :            : 
     940                 :         40 :         m->n_containers++;
     941                 :            : 
     942                 :         80 :         r = netlink_container_parse(m,
     943                 :         40 :                                     &m->containers[m->n_containers],
     944                 :            :                                     container,
     945                 :            :                                     size);
     946         [ -  + ]:         40 :         if (r < 0) {
     947                 :          0 :                 m->n_containers--;
     948                 :          0 :                 return r;
     949                 :            :         }
     950                 :            : 
     951                 :         40 :         m->containers[m->n_containers].type_system = m->containers[m->n_containers - 1].type_system;
     952                 :            : 
     953                 :         40 :         return 0;
     954                 :            : }
     955                 :            : 
     956                 :         76 : int sd_netlink_message_exit_container(sd_netlink_message *m) {
     957   [ -  +  -  + ]:         76 :         assert_return(m, -EINVAL);
     958   [ -  +  -  + ]:         76 :         assert_return(m->sealed, -EINVAL);
     959   [ +  +  +  + ]:         76 :         assert_return(m->n_containers > 0, -EINVAL);
     960                 :            : 
     961                 :         72 :         m->containers[m->n_containers].attributes = mfree(m->containers[m->n_containers].attributes);
     962                 :         72 :         m->containers[m->n_containers].type_system = NULL;
     963                 :            : 
     964                 :         72 :         m->n_containers--;
     965                 :            : 
     966                 :         72 :         return 0;
     967                 :            : }
     968                 :            : 
     969                 :        312 : uint32_t rtnl_message_get_serial(sd_netlink_message *m) {
     970         [ -  + ]:        312 :         assert(m);
     971         [ -  + ]:        312 :         assert(m->hdr);
     972                 :            : 
     973                 :        312 :         return m->hdr->nlmsg_seq;
     974                 :            : }
     975                 :            : 
     976                 :        260 : int sd_netlink_message_is_error(sd_netlink_message *m) {
     977   [ -  +  -  + ]:        260 :         assert_return(m, 0);
     978   [ -  +  -  + ]:        260 :         assert_return(m->hdr, 0);
     979                 :            : 
     980                 :        260 :         return m->hdr->nlmsg_type == NLMSG_ERROR;
     981                 :            : }
     982                 :            : 
     983                 :        232 : int sd_netlink_message_get_errno(sd_netlink_message *m) {
     984                 :            :         struct nlmsgerr *err;
     985                 :            : 
     986   [ -  +  -  + ]:        232 :         assert_return(m, -EINVAL);
     987   [ -  +  -  + ]:        232 :         assert_return(m->hdr, -EINVAL);
     988                 :            : 
     989         [ +  + ]:        232 :         if (!sd_netlink_message_is_error(m))
     990                 :        216 :                 return 0;
     991                 :            : 
     992                 :         16 :         err = NLMSG_DATA(m->hdr);
     993                 :            : 
     994                 :         16 :         return err->error;
     995                 :            : }
     996                 :            : 
     997                 :        344 : 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   [ -  +  -  + ]:        344 :         assert_return(m, -EINVAL);
    1006                 :            : 
    1007                 :            :         /* don't allow appending to message once parsed */
    1008         [ +  + ]:        344 :         if (!m->sealed)
    1009                 :        336 :                 rtnl_message_seal(m);
    1010                 :            : 
    1011                 :        344 :         type_system_root = type_system_get_root(m->protocol);
    1012                 :            : 
    1013         [ -  + ]:        344 :         for (i = 1; i <= m->n_containers; i++)
    1014                 :          0 :                 m->containers[i].attributes = mfree(m->containers[i].attributes);
    1015                 :            : 
    1016                 :        344 :         m->n_containers = 0;
    1017                 :            : 
    1018         [ -  + ]:        344 :         if (m->containers[0].attributes)
    1019                 :            :                 /* top-level attributes have already been parsed */
    1020                 :          0 :                 return 0;
    1021                 :            : 
    1022         [ -  + ]:        344 :         assert(m->hdr);
    1023                 :            : 
    1024                 :        344 :         r = type_system_get_type(type_system_root, &nl_type, m->hdr->nlmsg_type);
    1025         [ -  + ]:        344 :         if (r < 0)
    1026                 :          0 :                 return r;
    1027                 :            : 
    1028                 :        344 :         type = type_get_type(nl_type);
    1029                 :        344 :         size = type_get_size(nl_type);
    1030                 :            : 
    1031         [ +  - ]:        344 :         if (type == NETLINK_TYPE_NESTED) {
    1032                 :            :                 const NLTypeSystem *type_system;
    1033                 :            : 
    1034                 :        344 :                 type_get_type_system(nl_type, &type_system);
    1035                 :            : 
    1036                 :        344 :                 m->containers[0].type_system = type_system;
    1037                 :            : 
    1038                 :       1032 :                 r = netlink_container_parse(m,
    1039                 :        344 :                                             &m->containers[m->n_containers],
    1040                 :        344 :                                             (struct rtattr*)((uint8_t*)NLMSG_DATA(m->hdr) + NLMSG_ALIGN(size)),
    1041                 :        344 :                                             NLMSG_PAYLOAD(m->hdr, size));
    1042         [ -  + ]:        344 :                 if (r < 0)
    1043                 :          0 :                         return r;
    1044                 :            :         }
    1045                 :            : 
    1046                 :        344 :         return 0;
    1047                 :            : }
    1048                 :            : 
    1049                 :        448 : void rtnl_message_seal(sd_netlink_message *m) {
    1050         [ -  + ]:        448 :         assert(m);
    1051         [ -  + ]:        448 :         assert(!m->sealed);
    1052                 :            : 
    1053                 :        448 :         m->sealed = true;
    1054                 :        448 : }
    1055                 :            : 
    1056                 :        236 : sd_netlink_message *sd_netlink_message_next(sd_netlink_message *m) {
    1057   [ -  +  -  + ]:        236 :         assert_return(m, NULL);
    1058                 :            : 
    1059                 :        236 :         return m->next;
    1060                 :            : }

Generated by: LCOV version 1.14