1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
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 "memory-util.h"
12 #include "netlink-internal.h"
13 #include "netlink-types.h"
14 #include "netlink-util.h"
15 #include "socket-util.h"
16 #include "strv.h"
17 
18 #define GET_CONTAINER(m, i) ((struct rtattr*)((uint8_t*)(m)->hdr + (m)->containers[i].offset))
19 
20 #define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK)
21 #define RTA_FLAGS(rta) ((rta)->rta_type & ~NLA_TYPE_MASK)
22 
message_new_empty(sd_netlink * nl,sd_netlink_message ** ret)23 int message_new_empty(sd_netlink *nl, sd_netlink_message **ret) {
24         sd_netlink_message *m;
25 
26         assert(nl);
27         assert(ret);
28 
29         /* Note that 'nl' is currently unused, if we start using it internally we must take care to
30          * avoid problems due to mutual references between buses and their queued messages. See sd-bus. */
31 
32         m = new(sd_netlink_message, 1);
33         if (!m)
34                 return -ENOMEM;
35 
36         *m = (sd_netlink_message) {
37                 .n_ref = 1,
38                 .protocol = nl->protocol,
39                 .sealed = false,
40         };
41 
42         *ret = m;
43         return 0;
44 }
45 
message_new_full(sd_netlink * nl,uint16_t nlmsg_type,const NLTypeSystem * type_system,size_t header_size,sd_netlink_message ** ret)46 int message_new_full(
47                 sd_netlink *nl,
48                 uint16_t nlmsg_type,
49                 const NLTypeSystem *type_system,
50                 size_t header_size,
51                 sd_netlink_message **ret) {
52 
53         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
54         size_t size;
55         int r;
56 
57         assert(nl);
58         assert(type_system);
59         assert(ret);
60 
61         size = NLMSG_SPACE(header_size);
62         assert(size >= sizeof(struct nlmsghdr));
63 
64         r = message_new_empty(nl, &m);
65         if (r < 0)
66                 return r;
67 
68         m->containers[0].type_system = type_system;
69 
70         m->hdr = malloc0(size);
71         if (!m->hdr)
72                 return -ENOMEM;
73 
74         m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
75         m->hdr->nlmsg_len = size;
76         m->hdr->nlmsg_type = nlmsg_type;
77 
78         *ret = TAKE_PTR(m);
79         return 0;
80 }
81 
message_new(sd_netlink * nl,sd_netlink_message ** ret,uint16_t type)82 int message_new(sd_netlink *nl, sd_netlink_message **ret, uint16_t type) {
83         const NLTypeSystem *type_system;
84         size_t size;
85         int r;
86 
87         assert_return(nl, -EINVAL);
88         assert_return(ret, -EINVAL);
89 
90         r = type_system_root_get_type_system_and_header_size(nl, type, &type_system, &size);
91         if (r < 0)
92                 return r;
93 
94         return message_new_full(nl, type, type_system, size, ret);
95 }
96 
message_new_synthetic_error(sd_netlink * nl,int error,uint32_t serial,sd_netlink_message ** ret)97 int message_new_synthetic_error(sd_netlink *nl, int error, uint32_t serial, sd_netlink_message **ret) {
98         struct nlmsgerr *err;
99         int r;
100 
101         assert(error <= 0);
102 
103         r = message_new(nl, ret, NLMSG_ERROR);
104         if (r < 0)
105                 return r;
106 
107         message_seal(*ret);
108         (*ret)->hdr->nlmsg_seq = serial;
109 
110         err = NLMSG_DATA((*ret)->hdr);
111         err->error = error;
112 
113         return 0;
114 }
115 
sd_netlink_message_request_dump(sd_netlink_message * m,int dump)116 int sd_netlink_message_request_dump(sd_netlink_message *m, int dump) {
117         assert_return(m, -EINVAL);
118         assert_return(m->hdr, -EINVAL);
119         assert_return(m->protocol != NETLINK_ROUTE ||
120                       IN_SET(m->hdr->nlmsg_type,
121                              RTM_GETLINK, RTM_GETLINKPROP, RTM_GETADDR, RTM_GETROUTE, RTM_GETNEIGH,
122                              RTM_GETRULE, RTM_GETADDRLABEL, RTM_GETNEXTHOP, RTM_GETQDISC, RTM_GETTCLASS),
123                       -EINVAL);
124 
125         SET_FLAG(m->hdr->nlmsg_flags, NLM_F_DUMP, dump);
126 
127         return 0;
128 }
129 
130 DEFINE_TRIVIAL_REF_FUNC(sd_netlink_message, sd_netlink_message);
131 
sd_netlink_message_unref(sd_netlink_message * m)132 sd_netlink_message *sd_netlink_message_unref(sd_netlink_message *m) {
133         while (m && --m->n_ref == 0) {
134                 unsigned i;
135 
136                 free(m->hdr);
137 
138                 for (i = 0; i <= m->n_containers; i++)
139                         free(m->containers[i].attributes);
140 
141                 sd_netlink_message *t = m;
142                 m = m->next;
143                 free(t);
144         }
145 
146         return NULL;
147 }
148 
sd_netlink_message_get_type(sd_netlink_message * m,uint16_t * type)149 int sd_netlink_message_get_type(sd_netlink_message *m, uint16_t *type) {
150         assert_return(m, -EINVAL);
151         assert_return(type != 0, -EINVAL);
152 
153         *type = m->hdr->nlmsg_type;
154 
155         return 0;
156 }
157 
sd_netlink_message_set_flags(sd_netlink_message * m,uint16_t flags)158 int sd_netlink_message_set_flags(sd_netlink_message *m, uint16_t flags) {
159         assert_return(m, -EINVAL);
160         assert_return(flags != 0, -EINVAL);
161 
162         m->hdr->nlmsg_flags = flags;
163 
164         return 0;
165 }
166 
sd_netlink_message_is_broadcast(sd_netlink_message * m)167 int sd_netlink_message_is_broadcast(sd_netlink_message *m) {
168         assert_return(m, -EINVAL);
169 
170         return m->multicast_group != 0;
171 }
172 
173 /* If successful the updated message will be correctly aligned, if
174    unsuccessful the old message is untouched. */
add_rtattr(sd_netlink_message * m,unsigned short type,const void * data,size_t data_length)175 static int add_rtattr(sd_netlink_message *m, unsigned short type, const void *data, size_t data_length) {
176         size_t message_length;
177         struct nlmsghdr *new_hdr;
178         struct rtattr *rta;
179         int offset;
180 
181         assert(m);
182         assert(m->hdr);
183         assert(!m->sealed);
184         assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
185         assert(!data || data_length > 0);
186 
187         /* get the new message size (with padding at the end) */
188         message_length = m->hdr->nlmsg_len + RTA_SPACE(data_length);
189 
190         /* buffer should be smaller than both one page or 8K to be accepted by the kernel */
191         if (message_length > MIN(page_size(), 8192UL))
192                 return -ENOBUFS;
193 
194         /* realloc to fit the new attribute */
195         new_hdr = realloc(m->hdr, message_length);
196         if (!new_hdr)
197                 return -ENOMEM;
198         m->hdr = new_hdr;
199 
200         /* get pointer to the attribute we are about to add */
201         rta = (struct rtattr *) ((uint8_t *) m->hdr + m->hdr->nlmsg_len);
202 
203         rtattr_append_attribute_internal(rta, type, data, data_length);
204 
205         /* if we are inside containers, extend them */
206         for (unsigned i = 0; i < m->n_containers; i++)
207                 GET_CONTAINER(m, i)->rta_len += RTA_SPACE(data_length);
208 
209         /* update message size */
210         offset = m->hdr->nlmsg_len;
211         m->hdr->nlmsg_len = message_length;
212 
213         /* return old message size */
214         return offset;
215 }
216 
message_attribute_has_type(sd_netlink_message * m,size_t * out_size,uint16_t attribute_type,uint16_t data_type)217 static int message_attribute_has_type(sd_netlink_message *m, size_t *out_size, uint16_t attribute_type, uint16_t data_type) {
218         const NLType *type;
219 
220         assert(m);
221 
222         type = type_system_get_type(m->containers[m->n_containers].type_system, attribute_type);
223         if (!type)
224                 return -EOPNOTSUPP;
225 
226         if (type_get_type(type) != data_type)
227                 return -EINVAL;
228 
229         if (out_size)
230                 *out_size = type_get_size(type);
231         return 0;
232 }
233 
sd_netlink_message_append_string(sd_netlink_message * m,unsigned short type,const char * data)234 int sd_netlink_message_append_string(sd_netlink_message *m, unsigned short type, const char *data) {
235         size_t length, size;
236         int r;
237 
238         assert_return(m, -EINVAL);
239         assert_return(!m->sealed, -EPERM);
240         assert_return(data, -EINVAL);
241 
242         r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_STRING);
243         if (r < 0)
244                 return r;
245 
246         if (size) {
247                 length = strnlen(data, size+1);
248                 if (length > size)
249                         return -EINVAL;
250         } else
251                 length = strlen(data);
252 
253         r = add_rtattr(m, type, data, length + 1);
254         if (r < 0)
255                 return r;
256 
257         return 0;
258 }
259 
sd_netlink_message_append_strv(sd_netlink_message * m,unsigned short type,char * const * data)260 int sd_netlink_message_append_strv(sd_netlink_message *m, unsigned short type, char * const *data) {
261         size_t length, size;
262         int r;
263 
264         assert_return(m, -EINVAL);
265         assert_return(!m->sealed, -EPERM);
266         assert_return(data, -EINVAL);
267 
268         r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_STRING);
269         if (r < 0)
270                 return r;
271 
272         STRV_FOREACH(p, data) {
273                 if (size) {
274                         length = strnlen(*p, size+1);
275                         if (length > size)
276                                 return -EINVAL;
277                 } else
278                         length = strlen(*p);
279 
280                 r = add_rtattr(m, type, *p, length + 1);
281                 if (r < 0)
282                         return r;
283         }
284 
285         return 0;
286 }
287 
sd_netlink_message_append_flag(sd_netlink_message * m,unsigned short type)288 int sd_netlink_message_append_flag(sd_netlink_message *m, unsigned short type) {
289         size_t size;
290         int r;
291 
292         assert_return(m, -EINVAL);
293         assert_return(!m->sealed, -EPERM);
294 
295         r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_FLAG);
296         if (r < 0)
297                 return r;
298 
299         r = add_rtattr(m, type, NULL, 0);
300         if (r < 0)
301                 return r;
302 
303         return 0;
304 }
305 
sd_netlink_message_append_u8(sd_netlink_message * m,unsigned short type,uint8_t data)306 int sd_netlink_message_append_u8(sd_netlink_message *m, unsigned short type, uint8_t data) {
307         int r;
308 
309         assert_return(m, -EINVAL);
310         assert_return(!m->sealed, -EPERM);
311 
312         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U8);
313         if (r < 0)
314                 return r;
315 
316         r = add_rtattr(m, type, &data, sizeof(uint8_t));
317         if (r < 0)
318                 return r;
319 
320         return 0;
321 }
322 
sd_netlink_message_append_u16(sd_netlink_message * m,unsigned short type,uint16_t data)323 int sd_netlink_message_append_u16(sd_netlink_message *m, unsigned short type, uint16_t data) {
324         int r;
325 
326         assert_return(m, -EINVAL);
327         assert_return(!m->sealed, -EPERM);
328 
329         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U16);
330         if (r < 0)
331                 return r;
332 
333         r = add_rtattr(m, type, &data, sizeof(uint16_t));
334         if (r < 0)
335                 return r;
336 
337         return 0;
338 }
339 
sd_netlink_message_append_u32(sd_netlink_message * m,unsigned short type,uint32_t data)340 int sd_netlink_message_append_u32(sd_netlink_message *m, unsigned short type, uint32_t data) {
341         int r;
342 
343         assert_return(m, -EINVAL);
344         assert_return(!m->sealed, -EPERM);
345 
346         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U32);
347         if (r < 0)
348                 return r;
349 
350         r = add_rtattr(m, type, &data, sizeof(uint32_t));
351         if (r < 0)
352                 return r;
353 
354         return 0;
355 }
356 
sd_netlink_message_append_u64(sd_netlink_message * m,unsigned short type,uint64_t data)357 int sd_netlink_message_append_u64(sd_netlink_message *m, unsigned short type, uint64_t data) {
358         int r;
359 
360         assert_return(m, -EINVAL);
361         assert_return(!m->sealed, -EPERM);
362 
363         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U64);
364         if (r < 0)
365                 return r;
366 
367         r = add_rtattr(m, type, &data, sizeof(uint64_t));
368         if (r < 0)
369                 return r;
370 
371         return 0;
372 }
373 
sd_netlink_message_append_s8(sd_netlink_message * m,unsigned short type,int8_t data)374 int sd_netlink_message_append_s8(sd_netlink_message *m, unsigned short type, int8_t data) {
375         int r;
376 
377         assert_return(m, -EINVAL);
378         assert_return(!m->sealed, -EPERM);
379 
380         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_S8);
381         if (r < 0)
382                 return r;
383 
384         r = add_rtattr(m, type, &data, sizeof(int8_t));
385         if (r < 0)
386                 return r;
387 
388         return 0;
389 }
390 
sd_netlink_message_append_s16(sd_netlink_message * m,unsigned short type,int16_t data)391 int sd_netlink_message_append_s16(sd_netlink_message *m, unsigned short type, int16_t data) {
392         int r;
393 
394         assert_return(m, -EINVAL);
395         assert_return(!m->sealed, -EPERM);
396 
397         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_S16);
398         if (r < 0)
399                 return r;
400 
401         r = add_rtattr(m, type, &data, sizeof(int16_t));
402         if (r < 0)
403                 return r;
404 
405         return 0;
406 }
407 
sd_netlink_message_append_s32(sd_netlink_message * m,unsigned short type,int32_t data)408 int sd_netlink_message_append_s32(sd_netlink_message *m, unsigned short type, int32_t data) {
409         int r;
410 
411         assert_return(m, -EINVAL);
412         assert_return(!m->sealed, -EPERM);
413 
414         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_S32);
415         if (r < 0)
416                 return r;
417 
418         r = add_rtattr(m, type, &data, sizeof(int32_t));
419         if (r < 0)
420                 return r;
421 
422         return 0;
423 }
424 
sd_netlink_message_append_s64(sd_netlink_message * m,unsigned short type,int64_t data)425 int sd_netlink_message_append_s64(sd_netlink_message *m, unsigned short type, int64_t data) {
426         int r;
427 
428         assert_return(m, -EINVAL);
429         assert_return(!m->sealed, -EPERM);
430 
431         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_S64);
432         if (r < 0)
433                 return r;
434 
435         r = add_rtattr(m, type, &data, sizeof(int64_t));
436         if (r < 0)
437                 return r;
438 
439         return 0;
440 }
441 
sd_netlink_message_append_data(sd_netlink_message * m,unsigned short type,const void * data,size_t len)442 int sd_netlink_message_append_data(sd_netlink_message *m, unsigned short type, const void *data, size_t len) {
443         int r;
444 
445         assert_return(m, -EINVAL);
446         assert_return(!m->sealed, -EPERM);
447 
448         r = add_rtattr(m, type, data, len);
449         if (r < 0)
450                 return r;
451 
452         return 0;
453 }
454 
netlink_message_append_in_addr_union(sd_netlink_message * m,unsigned short type,int family,const union in_addr_union * data)455 int netlink_message_append_in_addr_union(sd_netlink_message *m, unsigned short type, int family, const union in_addr_union *data) {
456         int r;
457 
458         assert_return(m, -EINVAL);
459         assert_return(!m->sealed, -EPERM);
460         assert_return(data, -EINVAL);
461         assert_return(IN_SET(family, AF_INET, AF_INET6), -EINVAL);
462 
463         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
464         if (r < 0)
465                 return r;
466 
467         r = add_rtattr(m, type, data, FAMILY_ADDRESS_SIZE(family));
468         if (r < 0)
469                 return r;
470 
471         return 0;
472 }
473 
sd_netlink_message_append_in_addr(sd_netlink_message * m,unsigned short type,const struct in_addr * data)474 int sd_netlink_message_append_in_addr(sd_netlink_message *m, unsigned short type, const struct in_addr *data) {
475         return netlink_message_append_in_addr_union(m, type, AF_INET, (const union in_addr_union *) data);
476 }
477 
sd_netlink_message_append_in6_addr(sd_netlink_message * m,unsigned short type,const struct in6_addr * data)478 int sd_netlink_message_append_in6_addr(sd_netlink_message *m, unsigned short type, const struct in6_addr *data) {
479         return netlink_message_append_in_addr_union(m, type, AF_INET6, (const union in_addr_union *) data);
480 }
481 
netlink_message_append_sockaddr_union(sd_netlink_message * m,unsigned short type,const union sockaddr_union * data)482 int netlink_message_append_sockaddr_union(sd_netlink_message *m, unsigned short type, const union sockaddr_union *data) {
483         int r;
484 
485         assert_return(m, -EINVAL);
486         assert_return(!m->sealed, -EPERM);
487         assert_return(data, -EINVAL);
488         assert_return(IN_SET(data->sa.sa_family, AF_INET, AF_INET6), -EINVAL);
489 
490         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_SOCKADDR);
491         if (r < 0)
492                 return r;
493 
494         r = add_rtattr(m, type, data, data->sa.sa_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6));
495         if (r < 0)
496                 return r;
497 
498         return 0;
499 }
500 
sd_netlink_message_append_sockaddr_in(sd_netlink_message * m,unsigned short type,const struct sockaddr_in * data)501 int sd_netlink_message_append_sockaddr_in(sd_netlink_message *m, unsigned short type, const struct sockaddr_in *data) {
502         return netlink_message_append_sockaddr_union(m, type, (const union sockaddr_union *) data);
503 }
504 
sd_netlink_message_append_sockaddr_in6(sd_netlink_message * m,unsigned short type,const struct sockaddr_in6 * data)505 int sd_netlink_message_append_sockaddr_in6(sd_netlink_message *m, unsigned short type, const struct sockaddr_in6 *data) {
506         return netlink_message_append_sockaddr_union(m, type, (const union sockaddr_union *) data);
507 }
508 
sd_netlink_message_append_ether_addr(sd_netlink_message * m,unsigned short type,const struct ether_addr * data)509 int sd_netlink_message_append_ether_addr(sd_netlink_message *m, unsigned short type, const struct ether_addr *data) {
510         int r;
511 
512         assert_return(m, -EINVAL);
513         assert_return(!m->sealed, -EPERM);
514         assert_return(data, -EINVAL);
515 
516         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_ETHER_ADDR);
517         if (r < 0)
518                 return r;
519 
520         r = add_rtattr(m, type, data, ETH_ALEN);
521         if (r < 0)
522                 return r;
523 
524         return 0;
525 }
526 
netlink_message_append_hw_addr(sd_netlink_message * m,unsigned short type,const struct hw_addr_data * data)527 int netlink_message_append_hw_addr(sd_netlink_message *m, unsigned short type, const struct hw_addr_data *data) {
528         int r;
529 
530         assert_return(m, -EINVAL);
531         assert_return(!m->sealed, -EPERM);
532         assert_return(data, -EINVAL);
533         assert_return(data->length > 0, -EINVAL);
534 
535         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_ETHER_ADDR);
536         if (r < 0)
537                 return r;
538 
539         r = add_rtattr(m, type, data->bytes, data->length);
540         if (r < 0)
541                 return r;
542 
543         return 0;
544 }
545 
sd_netlink_message_append_cache_info(sd_netlink_message * m,unsigned short type,const struct ifa_cacheinfo * info)546 int sd_netlink_message_append_cache_info(sd_netlink_message *m, unsigned short type, const struct ifa_cacheinfo *info) {
547         int r;
548 
549         assert_return(m, -EINVAL);
550         assert_return(!m->sealed, -EPERM);
551         assert_return(info, -EINVAL);
552 
553         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_CACHE_INFO);
554         if (r < 0)
555                 return r;
556 
557         r = add_rtattr(m, type, info, sizeof(struct ifa_cacheinfo));
558         if (r < 0)
559                 return r;
560 
561         return 0;
562 }
563 
sd_netlink_message_open_container(sd_netlink_message * m,unsigned short type)564 int sd_netlink_message_open_container(sd_netlink_message *m, unsigned short type) {
565         size_t size;
566         int r;
567 
568         assert_return(m, -EINVAL);
569         assert_return(!m->sealed, -EPERM);
570         /* m->containers[m->n_containers + 1] is accessed both in read and write. Prevent access out of bound */
571         assert_return(m->n_containers < (NETLINK_CONTAINER_DEPTH - 1), -ERANGE);
572 
573         r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_NESTED);
574         if (r < 0) {
575                 const NLTypeSystemUnion *type_system_union;
576                 int family;
577 
578                 r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_UNION);
579                 if (r < 0)
580                         return r;
581 
582                 r = sd_rtnl_message_get_family(m, &family);
583                 if (r < 0)
584                         return r;
585 
586                 type_system_union = type_system_get_type_system_union(
587                                 m->containers[m->n_containers].type_system,
588                                 type);
589                 if (!type_system_union)
590                         return -EOPNOTSUPP;
591 
592                 m->containers[m->n_containers + 1].type_system =
593                         type_system_union_get_type_system_by_protocol(
594                                 type_system_union,
595                                 family);
596         } else
597                 m->containers[m->n_containers + 1].type_system =
598                         type_system_get_type_system(
599                                 m->containers[m->n_containers].type_system,
600                                 type);
601         if (!m->containers[m->n_containers + 1].type_system)
602                 return -EOPNOTSUPP;
603 
604         r = add_rtattr(m, type | NLA_F_NESTED, NULL, size);
605         if (r < 0)
606                 return r;
607 
608         m->containers[m->n_containers++].offset = r;
609 
610         return 0;
611 }
612 
sd_netlink_message_open_container_union(sd_netlink_message * m,unsigned short type,const char * key)613 int sd_netlink_message_open_container_union(sd_netlink_message *m, unsigned short type, const char *key) {
614         const NLTypeSystemUnion *type_system_union;
615         int r;
616 
617         assert_return(m, -EINVAL);
618         assert_return(!m->sealed, -EPERM);
619         assert_return(m->n_containers < (NETLINK_CONTAINER_DEPTH - 1), -ERANGE);
620 
621         type_system_union = type_system_get_type_system_union(
622                         m->containers[m->n_containers].type_system,
623                         type);
624         if (!type_system_union)
625                 return -EOPNOTSUPP;
626 
627         m->containers[m->n_containers + 1].type_system =
628                 type_system_union_get_type_system_by_string(
629                         type_system_union,
630                         key);
631         if (!m->containers[m->n_containers + 1].type_system)
632                 return -EOPNOTSUPP;
633 
634         r = sd_netlink_message_append_string(m, type_system_union_get_match_attribute(type_system_union), key);
635         if (r < 0)
636                 return r;
637 
638         /* do we ever need non-null size */
639         r = add_rtattr(m, type | NLA_F_NESTED, NULL, 0);
640         if (r < 0)
641                 return r;
642 
643         m->containers[m->n_containers++].offset = r;
644 
645         return 0;
646 }
647 
sd_netlink_message_close_container(sd_netlink_message * m)648 int sd_netlink_message_close_container(sd_netlink_message *m) {
649         assert_return(m, -EINVAL);
650         assert_return(!m->sealed, -EPERM);
651         assert_return(m->n_containers > 0, -EINVAL);
652 
653         m->containers[m->n_containers].type_system = NULL;
654         m->containers[m->n_containers].offset = 0;
655         m->n_containers--;
656 
657         return 0;
658 }
659 
sd_netlink_message_open_array(sd_netlink_message * m,uint16_t type)660 int sd_netlink_message_open_array(sd_netlink_message *m, uint16_t type) {
661         int r;
662 
663         assert_return(m, -EINVAL);
664         assert_return(!m->sealed, -EPERM);
665         assert_return(m->n_containers < (NETLINK_CONTAINER_DEPTH - 1), -ERANGE);
666 
667         r = add_rtattr(m, type | NLA_F_NESTED, NULL, 0);
668         if (r < 0)
669                 return r;
670 
671         m->containers[m->n_containers].offset = r;
672         m->n_containers++;
673         m->containers[m->n_containers].type_system = m->containers[m->n_containers - 1].type_system;
674 
675         return 0;
676 }
677 
sd_netlink_message_cancel_array(sd_netlink_message * m)678 int sd_netlink_message_cancel_array(sd_netlink_message *m) {
679         uint32_t rta_len;
680 
681         assert_return(m, -EINVAL);
682         assert_return(!m->sealed, -EPERM);
683         assert_return(m->n_containers > 1, -EINVAL);
684 
685         rta_len = GET_CONTAINER(m, (m->n_containers - 1))->rta_len;
686 
687         for (unsigned i = 0; i < m->n_containers; i++)
688                 GET_CONTAINER(m, i)->rta_len -= rta_len;
689 
690         m->hdr->nlmsg_len -= rta_len;
691 
692         m->n_containers--;
693         m->containers[m->n_containers].type_system = NULL;
694 
695         return 0;
696 }
697 
netlink_message_read_internal(sd_netlink_message * m,unsigned short type,void ** ret_data,bool * ret_net_byteorder)698 static int netlink_message_read_internal(
699                 sd_netlink_message *m,
700                 unsigned short type,
701                 void **ret_data,
702                 bool *ret_net_byteorder) {
703 
704         struct netlink_attribute *attribute;
705         struct rtattr *rta;
706 
707         assert_return(m, -EINVAL);
708         assert_return(m->sealed, -EPERM);
709 
710         assert(m->n_containers < NETLINK_CONTAINER_DEPTH);
711 
712         if (!m->containers[m->n_containers].attributes)
713                 return -ENODATA;
714 
715         if (type > m->containers[m->n_containers].max_attribute)
716                 return -ENODATA;
717 
718         attribute = &m->containers[m->n_containers].attributes[type];
719 
720         if (attribute->offset == 0)
721                 return -ENODATA;
722 
723         rta = (struct rtattr*)((uint8_t *) m->hdr + attribute->offset);
724 
725         if (ret_data)
726                 *ret_data = RTA_DATA(rta);
727 
728         if (ret_net_byteorder)
729                 *ret_net_byteorder = attribute->net_byteorder;
730 
731         return RTA_PAYLOAD(rta);
732 }
733 
sd_netlink_message_read(sd_netlink_message * m,unsigned short type,size_t size,void * data)734 int sd_netlink_message_read(sd_netlink_message *m, unsigned short type, size_t size, void *data) {
735         void *attr_data;
736         int r;
737 
738         assert_return(m, -EINVAL);
739 
740         r = netlink_message_read_internal(m, type, &attr_data, NULL);
741         if (r < 0)
742                 return r;
743 
744         if ((size_t) r < size)
745                 return -EIO;
746 
747         if (data)
748                 memcpy(data, attr_data, size);
749 
750         return r;
751 }
752 
sd_netlink_message_read_data(sd_netlink_message * m,unsigned short type,size_t * ret_size,void ** ret_data)753 int sd_netlink_message_read_data(sd_netlink_message *m, unsigned short type, size_t *ret_size, void **ret_data) {
754         void *attr_data;
755         int r;
756 
757         assert_return(m, -EINVAL);
758 
759         r = netlink_message_read_internal(m, type, &attr_data, NULL);
760         if (r < 0)
761                 return r;
762 
763         if (ret_data) {
764                 void *data;
765 
766                 data = memdup(attr_data, r);
767                 if (!data)
768                         return -ENOMEM;
769 
770                 *ret_data = data;
771         }
772 
773         if (ret_size)
774                 *ret_size = r;
775 
776         return r;
777 }
778 
sd_netlink_message_read_data_suffix0(sd_netlink_message * m,unsigned short type,size_t * ret_size,void ** ret_data)779 int sd_netlink_message_read_data_suffix0(sd_netlink_message *m, unsigned short type, size_t *ret_size, void **ret_data) {
780         void *attr_data;
781         int r;
782 
783         assert_return(m, -EINVAL);
784 
785         r = netlink_message_read_internal(m, type, &attr_data, NULL);
786         if (r < 0)
787                 return r;
788 
789         if (ret_data) {
790                 void *data;
791 
792                 data = memdup_suffix0(attr_data, r);
793                 if (!data)
794                         return -ENOMEM;
795 
796                 *ret_data = data;
797         }
798 
799         if (ret_size)
800                 *ret_size = r;
801 
802         return r;
803 }
804 
sd_netlink_message_read_string_strdup(sd_netlink_message * m,unsigned short type,char ** data)805 int sd_netlink_message_read_string_strdup(sd_netlink_message *m, unsigned short type, char **data) {
806         void *attr_data;
807         int r;
808 
809         assert_return(m, -EINVAL);
810 
811         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_STRING);
812         if (r < 0)
813                 return r;
814 
815         r = netlink_message_read_internal(m, type, &attr_data, NULL);
816         if (r < 0)
817                 return r;
818 
819         if (data) {
820                 char *str;
821 
822                 str = strndup(attr_data, r);
823                 if (!str)
824                         return -ENOMEM;
825 
826                 *data = str;
827         }
828 
829         return 0;
830 }
831 
sd_netlink_message_read_string(sd_netlink_message * m,unsigned short type,const char ** data)832 int sd_netlink_message_read_string(sd_netlink_message *m, unsigned short type, const char **data) {
833         void *attr_data;
834         int r;
835 
836         assert_return(m, -EINVAL);
837 
838         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_STRING);
839         if (r < 0)
840                 return r;
841 
842         r = netlink_message_read_internal(m, type, &attr_data, NULL);
843         if (r < 0)
844                 return r;
845 
846         if (strnlen(attr_data, r) >= (size_t) r)
847                 return -EIO;
848 
849         if (data)
850                 *data = (const char *) attr_data;
851 
852         return 0;
853 }
854 
sd_netlink_message_read_u8(sd_netlink_message * m,unsigned short type,uint8_t * data)855 int sd_netlink_message_read_u8(sd_netlink_message *m, unsigned short type, uint8_t *data) {
856         void *attr_data;
857         int r;
858 
859         assert_return(m, -EINVAL);
860 
861         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U8);
862         if (r < 0)
863                 return r;
864 
865         r = netlink_message_read_internal(m, type, &attr_data, NULL);
866         if (r < 0)
867                 return r;
868 
869         if ((size_t) r < sizeof(uint8_t))
870                 return -EIO;
871 
872         if (data)
873                 *data = *(uint8_t *) attr_data;
874 
875         return 0;
876 }
877 
sd_netlink_message_read_u16(sd_netlink_message * m,unsigned short type,uint16_t * data)878 int sd_netlink_message_read_u16(sd_netlink_message *m, unsigned short type, uint16_t *data) {
879         void *attr_data;
880         bool net_byteorder;
881         int r;
882 
883         assert_return(m, -EINVAL);
884 
885         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U16);
886         if (r < 0)
887                 return r;
888 
889         r = netlink_message_read_internal(m, type, &attr_data, &net_byteorder);
890         if (r < 0)
891                 return r;
892 
893         if ((size_t) r < sizeof(uint16_t))
894                 return -EIO;
895 
896         if (data) {
897                 if (net_byteorder)
898                         *data = be16toh(*(uint16_t *) attr_data);
899                 else
900                         *data = *(uint16_t *) attr_data;
901         }
902 
903         return 0;
904 }
905 
sd_netlink_message_read_u32(sd_netlink_message * m,unsigned short type,uint32_t * data)906 int sd_netlink_message_read_u32(sd_netlink_message *m, unsigned short type, uint32_t *data) {
907         void *attr_data;
908         bool net_byteorder;
909         int r;
910 
911         assert_return(m, -EINVAL);
912 
913         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U32);
914         if (r < 0)
915                 return r;
916 
917         r = netlink_message_read_internal(m, type, &attr_data, &net_byteorder);
918         if (r < 0)
919                 return r;
920 
921         if ((size_t) r < sizeof(uint32_t))
922                 return -EIO;
923 
924         if (data) {
925                 if (net_byteorder)
926                         *data = be32toh(*(uint32_t *) attr_data);
927                 else
928                         *data = *(uint32_t *) attr_data;
929         }
930 
931         return 0;
932 }
933 
sd_netlink_message_read_ether_addr(sd_netlink_message * m,unsigned short type,struct ether_addr * data)934 int sd_netlink_message_read_ether_addr(sd_netlink_message *m, unsigned short type, struct ether_addr *data) {
935         void *attr_data;
936         int r;
937 
938         assert_return(m, -EINVAL);
939 
940         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_ETHER_ADDR);
941         if (r < 0)
942                 return r;
943 
944         r = netlink_message_read_internal(m, type, &attr_data, NULL);
945         if (r < 0)
946                 return r;
947 
948         if ((size_t) r < sizeof(struct ether_addr))
949                 return -EIO;
950 
951         if (data)
952                 memcpy(data, attr_data, sizeof(struct ether_addr));
953 
954         return 0;
955 }
956 
netlink_message_read_hw_addr(sd_netlink_message * m,unsigned short type,struct hw_addr_data * data)957 int netlink_message_read_hw_addr(sd_netlink_message *m, unsigned short type, struct hw_addr_data *data) {
958         void *attr_data;
959         int r;
960 
961         assert_return(m, -EINVAL);
962 
963         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_ETHER_ADDR);
964         if (r < 0)
965                 return r;
966 
967         r = netlink_message_read_internal(m, type, &attr_data, NULL);
968         if (r < 0)
969                 return r;
970 
971         if (r > HW_ADDR_MAX_SIZE)
972                 return -EIO;
973 
974         if (data) {
975                 memcpy(data->bytes, attr_data, r);
976                 data->length = r;
977         }
978 
979         return 0;
980 }
981 
sd_netlink_message_read_cache_info(sd_netlink_message * m,unsigned short type,struct ifa_cacheinfo * info)982 int sd_netlink_message_read_cache_info(sd_netlink_message *m, unsigned short type, struct ifa_cacheinfo *info) {
983         void *attr_data;
984         int r;
985 
986         assert_return(m, -EINVAL);
987 
988         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_CACHE_INFO);
989         if (r < 0)
990                 return r;
991 
992         r = netlink_message_read_internal(m, type, &attr_data, NULL);
993         if (r < 0)
994                 return r;
995 
996         if ((size_t) r < sizeof(struct ifa_cacheinfo))
997                 return -EIO;
998 
999         if (info)
1000                 memcpy(info, attr_data, sizeof(struct ifa_cacheinfo));
1001 
1002         return 0;
1003 }
1004 
netlink_message_read_in_addr_union(sd_netlink_message * m,unsigned short type,int family,union in_addr_union * data)1005 int netlink_message_read_in_addr_union(sd_netlink_message *m, unsigned short type, int family, union in_addr_union *data) {
1006         void *attr_data;
1007         int r;
1008 
1009         assert_return(m, -EINVAL);
1010         assert_return(IN_SET(family, AF_INET, AF_INET6), -EINVAL);
1011 
1012         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
1013         if (r < 0)
1014                 return r;
1015 
1016         r = netlink_message_read_internal(m, type, &attr_data, NULL);
1017         if (r < 0)
1018                 return r;
1019 
1020         if ((size_t) r < FAMILY_ADDRESS_SIZE(family))
1021                 return -EIO;
1022 
1023         if (data)
1024                 memcpy(data, attr_data, FAMILY_ADDRESS_SIZE(family));
1025 
1026         return 0;
1027 }
1028 
sd_netlink_message_read_in_addr(sd_netlink_message * m,unsigned short type,struct in_addr * data)1029 int sd_netlink_message_read_in_addr(sd_netlink_message *m, unsigned short type, struct in_addr *data) {
1030         union in_addr_union u;
1031         int r;
1032 
1033         r = netlink_message_read_in_addr_union(m, type, AF_INET, &u);
1034         if (r >= 0 && data)
1035                 *data = u.in;
1036 
1037         return r;
1038 }
1039 
sd_netlink_message_read_in6_addr(sd_netlink_message * m,unsigned short type,struct in6_addr * data)1040 int sd_netlink_message_read_in6_addr(sd_netlink_message *m, unsigned short type, struct in6_addr *data) {
1041         union in_addr_union u;
1042         int r;
1043 
1044         r = netlink_message_read_in_addr_union(m, type, AF_INET6, &u);
1045         if (r >= 0 && data)
1046                 *data = u.in6;
1047 
1048         return r;
1049 }
1050 
sd_netlink_message_has_flag(sd_netlink_message * m,unsigned short type)1051 int sd_netlink_message_has_flag(sd_netlink_message *m, unsigned short type) {
1052         void *attr_data;
1053         int r;
1054 
1055         assert_return(m, -EINVAL);
1056 
1057         /* This returns 1 when the flag is set, 0 when not set, negative errno on error. */
1058 
1059         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_FLAG);
1060         if (r < 0)
1061                 return r;
1062 
1063         r = netlink_message_read_internal(m, type, &attr_data, NULL);
1064         if (r == -ENODATA)
1065                 return 0;
1066         if (r < 0)
1067                 return r;
1068 
1069         return 1;
1070 }
1071 
sd_netlink_message_read_strv(sd_netlink_message * m,unsigned short container_type,unsigned short type_id,char *** ret)1072 int sd_netlink_message_read_strv(sd_netlink_message *m, unsigned short container_type, unsigned short type_id, char ***ret) {
1073         _cleanup_strv_free_ char **s = NULL;
1074         const NLTypeSystem *type_system;
1075         const NLType *nl_type;
1076         struct rtattr *rta;
1077         void *container;
1078         size_t rt_len;
1079         int r;
1080 
1081         assert_return(m, -EINVAL);
1082         assert_return(m->n_containers < NETLINK_CONTAINER_DEPTH, -EINVAL);
1083 
1084         nl_type = type_system_get_type(
1085                         m->containers[m->n_containers].type_system,
1086                         container_type);
1087         if (!nl_type)
1088                 return -EOPNOTSUPP;
1089 
1090         if (type_get_type(nl_type) != NETLINK_TYPE_NESTED)
1091                 return -EINVAL;
1092 
1093         type_system = type_system_get_type_system(
1094                         m->containers[m->n_containers].type_system,
1095                         container_type);
1096         if (!type_system)
1097                 return -EOPNOTSUPP;
1098 
1099         nl_type = type_system_get_type(type_system, type_id);
1100         if (!nl_type)
1101                 return -EOPNOTSUPP;
1102 
1103         if (type_get_type(nl_type) != NETLINK_TYPE_STRING)
1104                 return -EINVAL;
1105 
1106         r = netlink_message_read_internal(m, container_type, &container, NULL);
1107         if (r < 0)
1108                 return r;
1109 
1110         rt_len = (size_t) r;
1111         rta = container;
1112 
1113         /* RTA_OK() macro compares with rta->rt_len, which is unsigned short, and
1114          * LGTM.com analysis does not like the type difference. Hence, here we
1115          * introduce an unsigned short variable as a workaround. */
1116         unsigned short len = rt_len;
1117         for (; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
1118                 unsigned short type;
1119 
1120                 type = RTA_TYPE(rta);
1121                 if (type != type_id)
1122                         continue;
1123 
1124                 r = strv_extend(&s, RTA_DATA(rta));
1125                 if (r < 0)
1126                         return r;
1127         }
1128 
1129         *ret = TAKE_PTR(s);
1130         return 0;
1131 }
1132 
netlink_container_parse(sd_netlink_message * m,struct netlink_container * container,struct rtattr * rta,size_t rt_len)1133 static int netlink_container_parse(
1134                 sd_netlink_message *m,
1135                 struct netlink_container *container,
1136                 struct rtattr *rta,
1137                 size_t rt_len) {
1138 
1139         _cleanup_free_ struct netlink_attribute *attributes = NULL;
1140         uint16_t max_attr = 0;
1141 
1142         /* RTA_OK() macro compares with rta->rt_len, which is unsigned short, and
1143          * LGTM.com analysis does not like the type difference. Hence, here we
1144          * introduce an unsigned short variable as a workaround. */
1145         unsigned short len = rt_len;
1146         for (; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
1147                 uint16_t attr;
1148 
1149                 attr = RTA_TYPE(rta);
1150                 max_attr = MAX(max_attr, attr);
1151 
1152                 if (!GREEDY_REALLOC0(attributes, (size_t) max_attr + 1))
1153                         return -ENOMEM;
1154 
1155                 if (attributes[attr].offset != 0)
1156                         log_debug("sd-netlink: message parse - overwriting repeated attribute");
1157 
1158                 attributes[attr].offset = (uint8_t *) rta - (uint8_t *) m->hdr;
1159                 attributes[attr].nested = RTA_FLAGS(rta) & NLA_F_NESTED;
1160                 attributes[attr].net_byteorder = RTA_FLAGS(rta) & NLA_F_NET_BYTEORDER;
1161         }
1162 
1163         container->attributes = TAKE_PTR(attributes);
1164         container->max_attribute = max_attr;
1165 
1166         return 0;
1167 }
1168 
sd_netlink_message_enter_container(sd_netlink_message * m,unsigned short type_id)1169 int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short type_id) {
1170         const NLType *nl_type;
1171         const NLTypeSystem *type_system;
1172         void *container;
1173         uint16_t type;
1174         size_t size;
1175         int r;
1176 
1177         assert_return(m, -EINVAL);
1178         assert_return(m->n_containers < (NETLINK_CONTAINER_DEPTH - 1), -EINVAL);
1179 
1180         nl_type = type_system_get_type(
1181                         m->containers[m->n_containers].type_system,
1182                         type_id);
1183         if (!nl_type)
1184                 return -EOPNOTSUPP;
1185 
1186         type = type_get_type(nl_type);
1187 
1188         if (type == NETLINK_TYPE_NESTED) {
1189                 type_system = type_system_get_type_system(
1190                                 m->containers[m->n_containers].type_system,
1191                                 type_id);
1192                 if (!type_system)
1193                         return -EOPNOTSUPP;
1194         } else if (type == NETLINK_TYPE_UNION) {
1195                 const NLTypeSystemUnion *type_system_union;
1196 
1197                 type_system_union = type_system_get_type_system_union(
1198                                  m->containers[m->n_containers].type_system,
1199                                  type_id);
1200                 if (!type_system_union)
1201                         return -EOPNOTSUPP;
1202 
1203                 switch (type_system_union_get_match_type(type_system_union)) {
1204                 case NL_MATCH_SIBLING: {
1205                         const char *key;
1206 
1207                         r = sd_netlink_message_read_string(
1208                                         m,
1209                                         type_system_union_get_match_attribute(type_system_union),
1210                                         &key);
1211                         if (r < 0)
1212                                 return r;
1213 
1214                         type_system = type_system_union_get_type_system_by_string(
1215                                         type_system_union,
1216                                         key);
1217                         if (!type_system)
1218                                 return -EOPNOTSUPP;
1219 
1220                         break;
1221                 }
1222                 case NL_MATCH_PROTOCOL: {
1223                         int family;
1224 
1225                         r = sd_rtnl_message_get_family(m, &family);
1226                         if (r < 0)
1227                                 return r;
1228 
1229                         type_system = type_system_union_get_type_system_by_protocol(
1230                                         type_system_union,
1231                                         family);
1232                         if (!type_system)
1233                                 return -EOPNOTSUPP;
1234 
1235                         break;
1236                 }
1237                 default:
1238                         assert_not_reached();
1239                 }
1240         } else
1241                 return -EINVAL;
1242 
1243         r = netlink_message_read_internal(m, type_id, &container, NULL);
1244         if (r < 0)
1245                 return r;
1246 
1247         size = (size_t) r;
1248         m->n_containers++;
1249 
1250         r = netlink_container_parse(m,
1251                                     &m->containers[m->n_containers],
1252                                     container,
1253                                     size);
1254         if (r < 0) {
1255                 m->n_containers--;
1256                 return r;
1257         }
1258 
1259         m->containers[m->n_containers].type_system = type_system;
1260 
1261         return 0;
1262 }
1263 
sd_netlink_message_enter_array(sd_netlink_message * m,unsigned short type_id)1264 int sd_netlink_message_enter_array(sd_netlink_message *m, unsigned short type_id) {
1265         void *container;
1266         size_t size;
1267         int r;
1268 
1269         assert_return(m, -EINVAL);
1270         assert_return(m->n_containers < (NETLINK_CONTAINER_DEPTH - 1), -EINVAL);
1271 
1272         r = netlink_message_read_internal(m, type_id, &container, NULL);
1273         if (r < 0)
1274                 return r;
1275 
1276         size = (size_t) r;
1277         m->n_containers++;
1278 
1279         r = netlink_container_parse(m,
1280                                     &m->containers[m->n_containers],
1281                                     container,
1282                                     size);
1283         if (r < 0) {
1284                 m->n_containers--;
1285                 return r;
1286         }
1287 
1288         m->containers[m->n_containers].type_system = m->containers[m->n_containers - 1].type_system;
1289 
1290         return 0;
1291 }
1292 
sd_netlink_message_exit_container(sd_netlink_message * m)1293 int sd_netlink_message_exit_container(sd_netlink_message *m) {
1294         assert_return(m, -EINVAL);
1295         assert_return(m->sealed, -EINVAL);
1296         assert_return(m->n_containers > 0, -EINVAL);
1297 
1298         m->containers[m->n_containers].attributes = mfree(m->containers[m->n_containers].attributes);
1299         m->containers[m->n_containers].max_attribute = 0;
1300         m->containers[m->n_containers].type_system = NULL;
1301 
1302         m->n_containers--;
1303 
1304         return 0;
1305 }
1306 
sd_netlink_message_get_max_attribute(sd_netlink_message * m,uint16_t * ret)1307 int sd_netlink_message_get_max_attribute(sd_netlink_message *m, uint16_t *ret) {
1308         assert_return(m, -EINVAL);
1309         assert_return(m->sealed, -EINVAL);
1310         assert_return(ret, -EINVAL);
1311 
1312         *ret = m->containers[m->n_containers].max_attribute;
1313         return 0;
1314 }
1315 
message_get_serial(sd_netlink_message * m)1316 uint32_t message_get_serial(sd_netlink_message *m) {
1317         assert(m);
1318         assert(m->hdr);
1319 
1320         return m->hdr->nlmsg_seq;
1321 }
1322 
sd_netlink_message_is_error(sd_netlink_message * m)1323 int sd_netlink_message_is_error(sd_netlink_message *m) {
1324         assert_return(m, 0);
1325         assert_return(m->hdr, 0);
1326 
1327         return m->hdr->nlmsg_type == NLMSG_ERROR;
1328 }
1329 
sd_netlink_message_get_errno(sd_netlink_message * m)1330 int sd_netlink_message_get_errno(sd_netlink_message *m) {
1331         struct nlmsgerr *err;
1332 
1333         assert_return(m, -EINVAL);
1334         assert_return(m->hdr, -EINVAL);
1335 
1336         if (!sd_netlink_message_is_error(m))
1337                 return 0;
1338 
1339         err = NLMSG_DATA(m->hdr);
1340 
1341         return err->error;
1342 }
1343 
netlink_message_parse_error(sd_netlink_message * m)1344 static int netlink_message_parse_error(sd_netlink_message *m) {
1345         struct nlmsgerr *err = NLMSG_DATA(m->hdr);
1346         size_t hlen = sizeof(struct nlmsgerr);
1347 
1348         /* no TLVs, nothing to do here */
1349         if (!(m->hdr->nlmsg_flags & NLM_F_ACK_TLVS))
1350                 return 0;
1351 
1352         /* if NLM_F_CAPPED is set then the inner err msg was capped */
1353         if (!(m->hdr->nlmsg_flags & NLM_F_CAPPED))
1354                 hlen += err->msg.nlmsg_len - sizeof(struct nlmsghdr);
1355 
1356         if (m->hdr->nlmsg_len <= NLMSG_SPACE(hlen))
1357                 return 0;
1358 
1359         return netlink_container_parse(m,
1360                                        &m->containers[m->n_containers],
1361                                        (struct rtattr*)((uint8_t*) NLMSG_DATA(m->hdr) + hlen),
1362                                        NLMSG_PAYLOAD(m->hdr, hlen));
1363 }
1364 
sd_netlink_message_rewind(sd_netlink_message * m,sd_netlink * nl)1365 int sd_netlink_message_rewind(sd_netlink_message *m, sd_netlink *nl) {
1366         size_t size;
1367         int r;
1368 
1369         assert_return(m, -EINVAL);
1370         assert_return(nl, -EINVAL);
1371 
1372         /* don't allow appending to message once parsed */
1373         message_seal(m);
1374 
1375         for (unsigned i = 1; i <= m->n_containers; i++)
1376                 m->containers[i].attributes = mfree(m->containers[i].attributes);
1377 
1378         m->n_containers = 0;
1379 
1380         if (m->containers[0].attributes)
1381                 /* top-level attributes have already been parsed */
1382                 return 0;
1383 
1384         assert(m->hdr);
1385 
1386         r = type_system_root_get_type_system_and_header_size(nl, m->hdr->nlmsg_type,
1387                                                              &m->containers[0].type_system, &size);
1388         if (r < 0)
1389                 return r;
1390 
1391         if (sd_netlink_message_is_error(m))
1392                 return netlink_message_parse_error(m);
1393 
1394         return netlink_container_parse(m,
1395                                        &m->containers[0],
1396                                        (struct rtattr*)((uint8_t*) NLMSG_DATA(m->hdr) + NLMSG_ALIGN(size)),
1397                                        NLMSG_PAYLOAD(m->hdr, size));
1398 }
1399 
message_seal(sd_netlink_message * m)1400 void message_seal(sd_netlink_message *m) {
1401         assert(m);
1402 
1403         m->sealed = true;
1404 }
1405 
sd_netlink_message_next(sd_netlink_message * m)1406 sd_netlink_message *sd_netlink_message_next(sd_netlink_message *m) {
1407         assert_return(m, NULL);
1408 
1409         return m->next;
1410 }
1411