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 : }
|