LCOV - code coverage report
Current view: top level - libsystemd/sd-netlink - netlink-message.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 385 482 79.9 %
Date: 2015-07-29 18:47:03 Functions: 35 38 92.1 %

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

Generated by: LCOV version 1.11