]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-rtnl/rtnl-message.c
accelerometer: display short options too
[thirdparty/systemd.git] / src / libsystemd / sd-rtnl / rtnl-message.c
CommitLineData
65f568bb
TG
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 <netinet/ether.h>
24#include <stdbool.h>
25#include <unistd.h>
26
27#include "util.h"
28#include "refcnt.h"
d5eff740 29#include "missing.h"
65f568bb
TG
30
31#include "sd-rtnl.h"
3815f36f 32#include "rtnl-util.h"
65f568bb 33#include "rtnl-internal.h"
d8e538ec 34#include "rtnl-types.h"
65f568bb 35
31a4e153 36#define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->container_offsets[i]) : NULL)
e5c4350b 37#define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers ++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
4ebe732c 38
0a2478a9
TG
39#define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK)
40
1b89cf56 41static int message_new_empty(sd_rtnl *rtnl, sd_rtnl_message **ret) {
65f568bb
TG
42 sd_rtnl_message *m;
43
44 assert_return(ret, -EINVAL);
65f568bb 45
8c578303
TG
46 /* Note that 'rtnl' is curretly unused, if we start using it internally
47 we must take care to avoid problems due to mutual references between
48 busses and their queued messages. See sd-bus.
49 */
50
65f568bb
TG
51 m = new0(sd_rtnl_message, 1);
52 if (!m)
53 return -ENOMEM;
54
65f568bb
TG
55 m->n_ref = REFCNT_INIT;
56
65f568bb
TG
57 m->sealed = false;
58
59 *ret = m;
60
61 return 0;
62}
63
d8e538ec 64int message_new(sd_rtnl *rtnl, sd_rtnl_message **ret, uint16_t type) {
1b89cf56 65 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
d8e538ec
TG
66 const NLType *nl_type;
67 size_t size;
68 int r;
69
70 r = type_system_get_type(NULL, &nl_type, type);
71 if (r < 0)
72 return r;
73
74 assert(nl_type->type == NLA_NESTED);
75
1b89cf56 76 r = message_new_empty(rtnl, &m);
d8e538ec
TG
77 if (r < 0)
78 return r;
79
1b89cf56
TG
80 size = NLMSG_SPACE(nl_type->size);
81
82 assert(size >= sizeof(struct nlmsghdr));
83 m->hdr = malloc0(size);
84 if (!m->hdr)
85 return -ENOMEM;
86
87 m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
88
89 m->container_type_system[0] = nl_type->type_system;
90 m->hdr->nlmsg_len = size;
91 m->hdr->nlmsg_type = type;
92
93 *ret = m;
94 m = NULL;
d8e538ec
TG
95
96 return 0;
97}
98
1f01fb4f
TG
99int sd_rtnl_message_route_set_dst_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
100 struct rtmsg *rtm;
101
5a723174
TG
102 assert_return(m, -EINVAL);
103 assert_return(m->hdr, -EINVAL);
3815f36f 104 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
5a723174 105
1f01fb4f
TG
106 rtm = NLMSG_DATA(m->hdr);
107
5a723174
TG
108 if ((rtm->rtm_family == AF_INET && prefixlen > 32) ||
109 (rtm->rtm_family == AF_INET6 && prefixlen > 128))
110 return -ERANGE;
111
1f01fb4f
TG
112 rtm->rtm_dst_len = prefixlen;
113
5c1d3fc9
UTL
114 return 0;
115}
116
9e7e4408
TG
117int sd_rtnl_message_route_set_src_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
118 struct rtmsg *rtm;
119
120 assert_return(m, -EINVAL);
121 assert_return(m->hdr, -EINVAL);
122 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
123
124 rtm = NLMSG_DATA(m->hdr);
125
126 if ((rtm->rtm_family == AF_INET && prefixlen > 32) ||
127 (rtm->rtm_family == AF_INET6 && prefixlen > 128))
128 return -ERANGE;
129
130 rtm->rtm_src_len = prefixlen;
131
132 return 0;
133}
134
5c1d3fc9
UTL
135int sd_rtnl_message_route_set_scope(sd_rtnl_message *m, unsigned char scope) {
136 struct rtmsg *rtm;
137
138 assert_return(m, -EINVAL);
139 assert_return(m->hdr, -EINVAL);
140 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
141
142 rtm = NLMSG_DATA(m->hdr);
143
144 rtm->rtm_scope = scope;
145
1f01fb4f
TG
146 return 0;
147}
148
dae4de9d
TG
149int sd_rtnl_message_route_get_family(sd_rtnl_message *m, int *family) {
150 struct rtmsg *rtm;
151
152 assert_return(m, -EINVAL);
153 assert_return(m->hdr, -EINVAL);
154 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
155 assert_return(family, -EINVAL);
156
157 rtm = NLMSG_DATA(m->hdr);
158
159 *family = rtm->rtm_family;
160
161 return 0;
162}
163
584d0d2a 164int sd_rtnl_message_route_get_dst_prefixlen(sd_rtnl_message *m, unsigned char *dst_len) {
e9140aff
LP
165 struct rtmsg *rtm;
166
167 assert_return(m, -EINVAL);
168 assert_return(m->hdr, -EINVAL);
169 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
170 assert_return(dst_len, -EINVAL);
171
172 rtm = NLMSG_DATA(m->hdr);
173
174 *dst_len = rtm->rtm_dst_len;
175
176 return 0;
177}
178
584d0d2a 179int sd_rtnl_message_route_get_src_prefixlen(sd_rtnl_message *m, unsigned char *src_len) {
a98433c0
LP
180 struct rtmsg *rtm;
181
182 assert_return(m, -EINVAL);
183 assert_return(m->hdr, -EINVAL);
184 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
185 assert_return(src_len, -EINVAL);
186
187 rtm = NLMSG_DATA(m->hdr);
188
189 *src_len = rtm->rtm_src_len;
190
191 return 0;
192}
193
151b9b96 194int sd_rtnl_message_new_route(sd_rtnl *rtnl, sd_rtnl_message **ret,
28cc555d
DW
195 uint16_t nlmsg_type, int rtm_family,
196 unsigned char rtm_protocol) {
03d7e632
TG
197 struct rtmsg *rtm;
198 int r;
199
3815f36f 200 assert_return(rtnl_message_type_is_route(nlmsg_type), -EINVAL);
722f7cc9
TG
201 assert_return((nlmsg_type == RTM_GETROUTE && rtm_family == AF_UNSPEC) ||
202 rtm_family == AF_INET || rtm_family == AF_INET6, -EINVAL);
03d7e632
TG
203 assert_return(ret, -EINVAL);
204
d8e538ec 205 r = message_new(rtnl, ret, nlmsg_type);
03d7e632
TG
206 if (r < 0)
207 return r;
208
03d7e632 209 if (nlmsg_type == RTM_NEWROUTE)
3f781aa8 210 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_APPEND;
03d7e632
TG
211
212 rtm = NLMSG_DATA((*ret)->hdr);
213
214 rtm->rtm_family = rtm_family;
1f01fb4f
TG
215 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
216 rtm->rtm_type = RTN_UNICAST;
217 rtm->rtm_table = RT_TABLE_MAIN;
28cc555d 218 rtm->rtm_protocol = rtm_protocol;
03d7e632
TG
219
220 return 0;
221}
222
b98b483b
AR
223int sd_rtnl_message_neigh_set_flags(sd_rtnl_message *m, uint8_t flags) {
224 struct ndmsg *ndm;
225
226 assert_return(m, -EINVAL);
227 assert_return(m->hdr, -EINVAL);
228 assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
229
230 ndm = NLMSG_DATA(m->hdr);
231 ndm->ndm_flags |= flags;
232
233 return 0;
234}
235
236int sd_rtnl_message_neigh_set_state(sd_rtnl_message *m, uint16_t state) {
237 struct ndmsg *ndm;
238
239 assert_return(m, -EINVAL);
240 assert_return(m->hdr, -EINVAL);
241 assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
242
243 ndm = NLMSG_DATA(m->hdr);
244 ndm->ndm_state |= state;
245
246 return 0;
247}
248
249int sd_rtnl_message_neigh_get_flags(sd_rtnl_message *m, uint8_t *flags) {
250 struct ndmsg *ndm;
251
252 assert_return(m, -EINVAL);
253 assert_return(m->hdr, -EINVAL);
254 assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
255
256 ndm = NLMSG_DATA(m->hdr);
257 *flags = ndm->ndm_flags;
258
259 return 0;
260}
261
262int sd_rtnl_message_neigh_get_state(sd_rtnl_message *m, uint16_t *state) {
263 struct ndmsg *ndm;
264
265 assert_return(m, -EINVAL);
266 assert_return(m->hdr, -EINVAL);
267 assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
268
269 ndm = NLMSG_DATA(m->hdr);
270 *state = ndm->ndm_state;
271
272 return 0;
273}
274
20dff6c4
TG
275int sd_rtnl_message_neigh_get_family(sd_rtnl_message *m, int *family) {
276 struct ndmsg *ndm;
277
278 assert_return(m, -EINVAL);
279 assert_return(m->hdr, -EINVAL);
280 assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
281 assert_return(family, -EINVAL);
282
283 ndm = NLMSG_DATA(m->hdr);
284
285 *family = ndm->ndm_family;
286
287 return 0;
288}
289
290int sd_rtnl_message_neigh_get_ifindex(sd_rtnl_message *m, int *index) {
291 struct ndmsg *ndm;
292
293 assert_return(m, -EINVAL);
294 assert_return(m->hdr, -EINVAL);
295 assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
296 assert_return(index, -EINVAL);
297
298 ndm = NLMSG_DATA(m->hdr);
299
300 *index = ndm->ndm_ifindex;
301
302 return 0;
303}
304
305int sd_rtnl_message_new_neigh(sd_rtnl *rtnl, sd_rtnl_message **ret, uint16_t nlmsg_type, int index, int ndm_family) {
306 struct ndmsg *ndm;
307 int r;
308
309 assert_return(rtnl_message_type_is_neigh(nlmsg_type), -EINVAL);
b98b483b
AR
310 assert_return(ndm_family == AF_INET ||
311 ndm_family == AF_INET6 ||
312 ndm_family == PF_BRIDGE, -EINVAL);
20dff6c4
TG
313 assert_return(ret, -EINVAL);
314
315 r = message_new(rtnl, ret, nlmsg_type);
316 if (r < 0)
317 return r;
318
319 if (nlmsg_type == RTM_NEWNEIGH)
320 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_APPEND;
321
322 ndm = NLMSG_DATA((*ret)->hdr);
323
324 ndm->ndm_family = ndm_family;
325 ndm->ndm_ifindex = index;
326
327 return 0;
328}
329
5d4795f3 330int sd_rtnl_message_link_set_flags(sd_rtnl_message *m, unsigned flags, unsigned change) {
fc25d7f8
TG
331 struct ifinfomsg *ifi;
332
5a723174
TG
333 assert_return(m, -EINVAL);
334 assert_return(m->hdr, -EINVAL);
3815f36f 335 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
a7b74db6 336 assert_return(change, -EINVAL);
5a723174 337
fc25d7f8
TG
338 ifi = NLMSG_DATA(m->hdr);
339
340 ifi->ifi_flags = flags;
a7b74db6 341 ifi->ifi_change = change;
fc25d7f8
TG
342
343 return 0;
344}
345
346int sd_rtnl_message_link_set_type(sd_rtnl_message *m, unsigned type) {
347 struct ifinfomsg *ifi;
348
5a723174
TG
349 assert_return(m, -EINVAL);
350 assert_return(m->hdr, -EINVAL);
3815f36f 351 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
5a723174 352
fc25d7f8
TG
353 ifi = NLMSG_DATA(m->hdr);
354
355 ifi->ifi_type = type;
356
357 return 0;
358}
359
64c84071
SS
360int sd_rtnl_message_link_set_family(sd_rtnl_message *m, unsigned family) {
361 struct ifinfomsg *ifi;
362
363 assert_return(m, -EINVAL);
364 assert_return(m->hdr, -EINVAL);
365 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
366
367 ifi = NLMSG_DATA(m->hdr);
368
369 ifi->ifi_family = family;
370
371 return 0;
372}
373
151b9b96
LP
374int sd_rtnl_message_new_link(sd_rtnl *rtnl, sd_rtnl_message **ret,
375 uint16_t nlmsg_type, int index) {
65f568bb
TG
376 struct ifinfomsg *ifi;
377 int r;
378
3815f36f 379 assert_return(rtnl_message_type_is_link(nlmsg_type), -EINVAL);
6a8402d9 380 assert_return(nlmsg_type != RTM_DELLINK || index > 0, -EINVAL);
65f568bb
TG
381 assert_return(ret, -EINVAL);
382
d8e538ec 383 r = message_new(rtnl, ret, nlmsg_type);
65f568bb
TG
384 if (r < 0)
385 return r;
386
33125ac5 387 if (nlmsg_type == RTM_NEWLINK)
6a8402d9 388 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
65f568bb 389
dabfa9d1 390 ifi = NLMSG_DATA((*ret)->hdr);
65f568bb
TG
391
392 ifi->ifi_family = AF_UNSPEC;
393 ifi->ifi_index = index;
65f568bb
TG
394
395 return 0;
396}
397
6e20c8f8
TG
398int sd_rtnl_message_request_dump(sd_rtnl_message *m, int dump) {
399 assert_return(m, -EINVAL);
400 assert_return(m->hdr, -EINVAL);
20dff6c4
TG
401 assert_return(m->hdr->nlmsg_type == RTM_GETLINK ||
402 m->hdr->nlmsg_type == RTM_GETADDR ||
403 m->hdr->nlmsg_type == RTM_GETROUTE ||
404 m->hdr->nlmsg_type == RTM_GETNEIGH,
6e20c8f8
TG
405 -EINVAL);
406
407 if (dump)
408 m->hdr->nlmsg_flags |= NLM_F_DUMP;
409 else
410 m->hdr->nlmsg_flags &= ~NLM_F_DUMP;
411
412 return 0;
413}
414
5a723174
TG
415int sd_rtnl_message_addr_set_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
416 struct ifaddrmsg *ifa;
417
418 assert_return(m, -EINVAL);
419 assert_return(m->hdr, -EINVAL);
3815f36f 420 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
5a723174
TG
421
422 ifa = NLMSG_DATA(m->hdr);
423
424 if ((ifa->ifa_family == AF_INET && prefixlen > 32) ||
425 (ifa->ifa_family == AF_INET6 && prefixlen > 128))
426 return -ERANGE;
427
428 ifa->ifa_prefixlen = prefixlen;
429
430 return 0;
431}
432
433int sd_rtnl_message_addr_set_flags(sd_rtnl_message *m, unsigned char flags) {
434 struct ifaddrmsg *ifa;
435
436 assert_return(m, -EINVAL);
437 assert_return(m->hdr, -EINVAL);
3815f36f 438 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
5a723174
TG
439
440 ifa = NLMSG_DATA(m->hdr);
441
442 ifa->ifa_flags = flags;
443
444 return 0;
445}
446
447int sd_rtnl_message_addr_set_scope(sd_rtnl_message *m, unsigned char scope) {
448 struct ifaddrmsg *ifa;
449
450 assert_return(m, -EINVAL);
451 assert_return(m->hdr, -EINVAL);
3815f36f 452 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
5a723174
TG
453
454 ifa = NLMSG_DATA(m->hdr);
455
456 ifa->ifa_scope = scope;
457
458 return 0;
459}
460
0dd25fb9 461int sd_rtnl_message_addr_get_family(sd_rtnl_message *m, int *family) {
e00d77dd
TG
462 struct ifaddrmsg *ifa;
463
464 assert_return(m, -EINVAL);
465 assert_return(m->hdr, -EINVAL);
466 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
467 assert_return(family, -EINVAL);
468
469 ifa = NLMSG_DATA(m->hdr);
470
471 *family = ifa->ifa_family;
472
473 return 0;
474}
475
f4e884dd
TG
476int sd_rtnl_message_addr_get_prefixlen(sd_rtnl_message *m, unsigned char *prefixlen) {
477 struct ifaddrmsg *ifa;
478
479 assert_return(m, -EINVAL);
480 assert_return(m->hdr, -EINVAL);
481 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
482 assert_return(prefixlen, -EINVAL);
483
484 ifa = NLMSG_DATA(m->hdr);
485
486 *prefixlen = ifa->ifa_prefixlen;
487
488 return 0;
489}
490
e00d77dd
TG
491int sd_rtnl_message_addr_get_scope(sd_rtnl_message *m, unsigned char *scope) {
492 struct ifaddrmsg *ifa;
493
494 assert_return(m, -EINVAL);
495 assert_return(m->hdr, -EINVAL);
496 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
497 assert_return(scope, -EINVAL);
498
499 ifa = NLMSG_DATA(m->hdr);
500
501 *scope = ifa->ifa_scope;
502
503 return 0;
504}
505
506int sd_rtnl_message_addr_get_flags(sd_rtnl_message *m, unsigned char *flags) {
507 struct ifaddrmsg *ifa;
508
509 assert_return(m, -EINVAL);
510 assert_return(m->hdr, -EINVAL);
511 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
512 assert_return(flags, -EINVAL);
513
514 ifa = NLMSG_DATA(m->hdr);
515
516 *flags = ifa->ifa_flags;
517
518 return 0;
519}
520
521int sd_rtnl_message_addr_get_ifindex(sd_rtnl_message *m, int *ifindex) {
522 struct ifaddrmsg *ifa;
523
524 assert_return(m, -EINVAL);
525 assert_return(m->hdr, -EINVAL);
526 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
527 assert_return(ifindex, -EINVAL);
528
529 ifa = NLMSG_DATA(m->hdr);
530
531 *ifindex = ifa->ifa_index;
532
533 return 0;
534}
535
151b9b96
LP
536int sd_rtnl_message_new_addr(sd_rtnl *rtnl, sd_rtnl_message **ret,
537 uint16_t nlmsg_type, int index,
0dd25fb9 538 int family) {
65f568bb
TG
539 struct ifaddrmsg *ifa;
540 int r;
541
3815f36f 542 assert_return(rtnl_message_type_is_addr(nlmsg_type), -EINVAL);
b9ef681b
TG
543 assert_return((nlmsg_type == RTM_GETADDR && index == 0) ||
544 index > 0, -EINVAL);
545 assert_return((nlmsg_type == RTM_GETADDR && family == AF_UNSPEC) ||
546 family == AF_INET || family == AF_INET6, -EINVAL);
65f568bb
TG
547 assert_return(ret, -EINVAL);
548
d8e538ec 549 r = message_new(rtnl, ret, nlmsg_type);
65f568bb
TG
550 if (r < 0)
551 return r;
552
b9ef681b 553 if (nlmsg_type == RTM_GETADDR)
818dc5e7 554 (*ret)->hdr->nlmsg_flags |= NLM_F_DUMP;
65f568bb 555
dabfa9d1 556 ifa = NLMSG_DATA((*ret)->hdr);
65f568bb 557
65f568bb 558 ifa->ifa_index = index;
5a723174
TG
559 ifa->ifa_family = family;
560 if (family == AF_INET)
561 ifa->ifa_prefixlen = 32;
562 else if (family == AF_INET6)
563 ifa->ifa_prefixlen = 128;
65f568bb
TG
564
565 return 0;
566}
567
aba496a5 568int sd_rtnl_message_new_addr_update(sd_rtnl *rtnl, sd_rtnl_message **ret,
0dd25fb9 569 int index, int family) {
aba496a5
UTL
570 int r;
571
572 r = sd_rtnl_message_new_addr(rtnl, ret, RTM_NEWADDR, index, family);
573 if (r < 0)
574 return r;
575
576 (*ret)->hdr->nlmsg_flags |= NLM_F_REPLACE;
577
578 return 0;
579}
580
65f568bb
TG
581sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) {
582 if (m)
583 assert_se(REFCNT_INC(m->n_ref) >= 2);
584
585 return m;
586}
587
588sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) {
589 if (m && REFCNT_DEC(m->n_ref) <= 0) {
3dd215e0
TG
590 unsigned i;
591
65f568bb 592 free(m->hdr);
3dd215e0 593
9f5bbfe3 594 for (i = 0; i <= m->n_containers; i++)
3dd215e0
TG
595 free(m->rta_offset_tb[i]);
596
1403f45a
TG
597 sd_rtnl_message_unref(m->next);
598
65f568bb
TG
599 free(m);
600 }
601
602 return NULL;
603}
604
dabfa9d1 605int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type) {
65f568bb
TG
606 assert_return(m, -EINVAL);
607 assert_return(type, -EINVAL);
608
609 *type = m->hdr->nlmsg_type;
610
611 return 0;
612}
613
1f0db3ed
TG
614int sd_rtnl_message_is_broadcast(sd_rtnl_message *m) {
615 assert_return(m, -EINVAL);
616
617 return !m->hdr->nlmsg_pid;
618}
619
33125ac5
TG
620int sd_rtnl_message_link_get_ifindex(sd_rtnl_message *m, int *ifindex) {
621 struct ifinfomsg *ifi;
622
623 assert_return(m, -EINVAL);
9d0db178 624 assert_return(m->hdr, -EINVAL);
3815f36f 625 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
33125ac5 626 assert_return(ifindex, -EINVAL);
33125ac5
TG
627
628 ifi = NLMSG_DATA(m->hdr);
629
630 *ifindex = ifi->ifi_index;
631
632 return 0;
633}
634
50b3c42f
TG
635int sd_rtnl_message_link_get_flags(sd_rtnl_message *m, unsigned *flags) {
636 struct ifinfomsg *ifi;
637
638 assert_return(m, -EINVAL);
9d0db178 639 assert_return(m->hdr, -EINVAL);
3815f36f 640 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
50b3c42f 641 assert_return(flags, -EINVAL);
50b3c42f
TG
642
643 ifi = NLMSG_DATA(m->hdr);
644
645 *flags = ifi->ifi_flags;
646
647 return 0;
648}
649
ee8c4568
LP
650int sd_rtnl_message_link_get_type(sd_rtnl_message *m, unsigned *type) {
651 struct ifinfomsg *ifi;
652
653 assert_return(m, -EINVAL);
654 assert_return(m->hdr, -EINVAL);
655 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
656 assert_return(type, -EINVAL);
657
658 ifi = NLMSG_DATA(m->hdr);
659
660 *type = ifi->ifi_type;
661
662 return 0;
663}
664
4ebe732c
ZJS
665/* If successful the updated message will be correctly aligned, if
666 unsuccessful the old message is untouched. */
65f568bb 667static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) {
7ca1d319
TG
668 uint32_t rta_length;
669 size_t message_length, padding_length;
65f568bb
TG
670 struct nlmsghdr *new_hdr;
671 struct rtattr *rta;
8e337e64 672 char *padding;
5a081409 673 unsigned i;
7ca1d319 674 int offset;
65f568bb 675
33125ac5
TG
676 assert(m);
677 assert(m->hdr);
e5c4350b 678 assert(!m->sealed);
33125ac5 679 assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
7ca1d319
TG
680 assert(!data || data_length);
681
682 /* get offset of the new attribute */
683 offset = m->hdr->nlmsg_len;
65f568bb 684
8e337e64 685 /* get the size of the new rta attribute (with padding at the end) */
65f568bb 686 rta_length = RTA_LENGTH(data_length);
4ebe732c
ZJS
687
688 /* get the new message size (with padding at the end) */
7ca1d319 689 message_length = offset + RTA_ALIGN(rta_length);
65f568bb
TG
690
691 /* realloc to fit the new attribute */
692 new_hdr = realloc(m->hdr, message_length);
693 if (!new_hdr)
694 return -ENOMEM;
695 m->hdr = new_hdr;
696
697 /* get pointer to the attribute we are about to add */
7ca1d319 698 rta = (struct rtattr *) ((uint8_t *) m->hdr + offset);
65f568bb 699
5a081409
TG
700 /* if we are inside containers, extend them */
701 for (i = 0; i < m->n_containers; i++)
7ca1d319 702 GET_CONTAINER(m, i)->rta_len += message_length - offset;
33125ac5 703
65f568bb
TG
704 /* fill in the attribute */
705 rta->rta_type = type;
706 rta->rta_len = rta_length;
7ca1d319 707 if (data)
33125ac5
TG
708 /* we don't deal with the case where the user lies about the type
709 * and gives us too little data (so don't do that)
7ca1d319 710 */
33125ac5 711 padding = mempcpy(RTA_DATA(rta), data, data_length);
7ca1d319
TG
712 else {
713 /* if no data was passed, make sure we still initialize the padding
714 note that we can have data_length > 0 (used by some containers) */
715 padding = RTA_DATA(rta);
33125ac5 716 }
65f568bb 717
7ca1d319
TG
718 /* make sure also the padding at the end of the message is initialized */
719 padding_length = (uint8_t*)m->hdr + message_length - (uint8_t*)padding;
720 memzero(padding, padding_length);
721
4ebe732c
ZJS
722 /* update message size */
723 m->hdr->nlmsg_len = message_length;
724
7ca1d319 725 return offset;
65f568bb
TG
726}
727
d8e538ec
TG
728static int message_attribute_has_type(sd_rtnl_message *m, uint16_t attribute_type, uint16_t data_type) {
729 const NLType *type;
730 int r;
731
732 r = type_system_get_type(m->container_type_system[m->n_containers], &type, attribute_type);
733 if (r < 0)
734 return r;
735
736 if (type->type != data_type)
737 return -EINVAL;
738
739 return type->size;
740}
741
0a0dc69b 742int sd_rtnl_message_append_string(sd_rtnl_message *m, unsigned short type, const char *data) {
d8e538ec 743 size_t length, size;
0a0dc69b 744 int r;
65f568bb
TG
745
746 assert_return(m, -EINVAL);
e5c4350b 747 assert_return(!m->sealed, -EPERM);
65f568bb
TG
748 assert_return(data, -EINVAL);
749
d8e538ec 750 r = message_attribute_has_type(m, type, NLA_STRING);
0a0dc69b
TG
751 if (r < 0)
752 return r;
d8e538ec
TG
753 else
754 size = (size_t)r;
65f568bb 755
d8e538ec 756 if (size) {
3072eecf
LP
757 length = strnlen(data, size+1);
758 if (length > size)
d8e538ec
TG
759 return -EINVAL;
760 } else
761 length = strlen(data);
33125ac5 762
d8e538ec 763 r = add_rtattr(m, type, data, length + 1);
0a0dc69b
TG
764 if (r < 0)
765 return r;
766
767 return 0;
768}
769
7b179640 770int sd_rtnl_message_append_u8(sd_rtnl_message *m, unsigned short type, uint8_t data) {
7b179640
SS
771 int r;
772
773 assert_return(m, -EINVAL);
774 assert_return(!m->sealed, -EPERM);
775
d8e538ec 776 r = message_attribute_has_type(m, type, NLA_U8);
7b179640
SS
777 if (r < 0)
778 return r;
779
7b179640
SS
780 r = add_rtattr(m, type, &data, sizeof(uint8_t));
781 if (r < 0)
782 return r;
783
784 return 0;
785}
786
787
01b36069 788int sd_rtnl_message_append_u16(sd_rtnl_message *m, unsigned short type, uint16_t data) {
01b36069
TG
789 int r;
790
791 assert_return(m, -EINVAL);
e5c4350b 792 assert_return(!m->sealed, -EPERM);
01b36069 793
d8e538ec 794 r = message_attribute_has_type(m, type, NLA_U16);
01b36069
TG
795 if (r < 0)
796 return r;
797
01b36069
TG
798 r = add_rtattr(m, type, &data, sizeof(uint16_t));
799 if (r < 0)
800 return r;
801
802 return 0;
803}
804
0a0dc69b 805int sd_rtnl_message_append_u32(sd_rtnl_message *m, unsigned short type, uint32_t data) {
0a0dc69b
TG
806 int r;
807
808 assert_return(m, -EINVAL);
e5c4350b 809 assert_return(!m->sealed, -EPERM);
0a0dc69b 810
d8e538ec 811 r = message_attribute_has_type(m, type, NLA_U32);
0a0dc69b
TG
812 if (r < 0)
813 return r;
814
4d47756b 815 r = add_rtattr(m, type, &data, sizeof(uint32_t));
0a0dc69b
TG
816 if (r < 0)
817 return r;
818
819 return 0;
820}
821
822int sd_rtnl_message_append_in_addr(sd_rtnl_message *m, unsigned short type, const struct in_addr *data) {
0a0dc69b
TG
823 int r;
824
825 assert_return(m, -EINVAL);
e5c4350b 826 assert_return(!m->sealed, -EPERM);
0a0dc69b
TG
827 assert_return(data, -EINVAL);
828
d8e538ec 829 r = message_attribute_has_type(m, type, NLA_IN_ADDR);
0a0dc69b
TG
830 if (r < 0)
831 return r;
832
4d47756b 833 r = add_rtattr(m, type, data, sizeof(struct in_addr));
0a0dc69b
TG
834 if (r < 0)
835 return r;
836
837 return 0;
838}
839
840int sd_rtnl_message_append_in6_addr(sd_rtnl_message *m, unsigned short type, const struct in6_addr *data) {
0a0dc69b
TG
841 int r;
842
843 assert_return(m, -EINVAL);
e5c4350b 844 assert_return(!m->sealed, -EPERM);
0a0dc69b
TG
845 assert_return(data, -EINVAL);
846
d8e538ec 847 r = message_attribute_has_type(m, type, NLA_IN_ADDR);
0a0dc69b
TG
848 if (r < 0)
849 return r;
850
4d47756b 851 r = add_rtattr(m, type, data, sizeof(struct in6_addr));
0a0dc69b
TG
852 if (r < 0)
853 return r;
854
855 return 0;
856}
857
858int sd_rtnl_message_append_ether_addr(sd_rtnl_message *m, unsigned short type, const struct ether_addr *data) {
0a0dc69b
TG
859 int r;
860
861 assert_return(m, -EINVAL);
e5c4350b 862 assert_return(!m->sealed, -EPERM);
0a0dc69b
TG
863 assert_return(data, -EINVAL);
864
d8e538ec
TG
865 r = message_attribute_has_type(m, type, NLA_ETHER_ADDR);
866 if (r < 0)
867 return r;
0a0dc69b 868
b9eaf3d1 869 r = add_rtattr(m, type, data, ETH_ALEN);
0a0dc69b
TG
870 if (r < 0)
871 return r;
872
873 return 0;
65f568bb
TG
874}
875
aba496a5
UTL
876int sd_rtnl_message_append_cache_info(sd_rtnl_message *m, unsigned short type, const struct ifa_cacheinfo *info) {
877 int r;
878
879 assert_return(m, -EINVAL);
880 assert_return(!m->sealed, -EPERM);
881 assert_return(info, -EINVAL);
882
883 r = message_attribute_has_type(m, type, NLA_CACHE_INFO);
884 if (r < 0)
885 return r;
886
887 r = add_rtattr(m, type, info, sizeof(struct ifa_cacheinfo));
888 if (r < 0)
889 return r;
890
891 return 0;
892}
893
ee3a6a51 894int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
d8e538ec
TG
895 size_t size;
896 int r;
33125ac5 897
65f568bb 898 assert_return(m, -EINVAL);
e5c4350b 899 assert_return(!m->sealed, -EPERM);
7ca1d319 900 assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -ERANGE);
33125ac5 901
d8e538ec
TG
902 r = message_attribute_has_type(m, type, NLA_NESTED);
903 if (r < 0)
904 return r;
905 else
906 size = (size_t)r;
33125ac5 907
d8e538ec
TG
908 r = type_system_get_type_system(m->container_type_system[m->n_containers],
909 &m->container_type_system[m->n_containers + 1],
910 type);
911 if (r < 0)
912 return r;
31a4e153 913
fcf81a54 914 r = add_rtattr(m, type | NLA_F_NESTED, NULL, size);
d8e538ec
TG
915 if (r < 0)
916 return r;
917
7ca1d319
TG
918 m->container_offsets[m->n_containers ++] = r;
919
d8e538ec
TG
920 return 0;
921}
922
923int sd_rtnl_message_open_container_union(sd_rtnl_message *m, unsigned short type, const char *key) {
924 const NLTypeSystemUnion *type_system_union;
925 int r;
926
927 assert_return(m, -EINVAL);
928 assert_return(!m->sealed, -EPERM);
929
930 r = type_system_get_type_system_union(m->container_type_system[m->n_containers], &type_system_union, type);
931 if (r < 0)
932 return r;
933
934 r = type_system_union_get_type_system(type_system_union,
935 &m->container_type_system[m->n_containers + 1],
936 key);
937 if (r < 0)
938 return r;
33125ac5 939
d8e538ec
TG
940 r = sd_rtnl_message_append_string(m, type_system_union->match, key);
941 if (r < 0)
942 return r;
943
944 /* do we evere need non-null size */
945 r = add_rtattr(m, type, NULL, 0);
946 if (r < 0)
947 return r;
948
7ca1d319
TG
949 m->container_offsets[m->n_containers ++] = r;
950
d8e538ec 951 return 0;
33125ac5
TG
952}
953
d8e538ec 954
33125ac5
TG
955int sd_rtnl_message_close_container(sd_rtnl_message *m) {
956 assert_return(m, -EINVAL);
e5c4350b 957 assert_return(!m->sealed, -EPERM);
5a081409 958 assert_return(m->n_containers > 0, -EINVAL);
33125ac5 959
d8e538ec 960 m->container_type_system[m->n_containers] = NULL;
5a081409 961 m->n_containers --;
33125ac5
TG
962
963 return 0;
964}
965
44caa5e7 966int rtnl_message_read_internal(sd_rtnl_message *m, unsigned short type, void **data) {
f66eeb6b
TG
967 struct rtattr *rta;
968
44caa5e7
SS
969 assert_return(m, -EINVAL);
970 assert_return(m->sealed, -EPERM);
971 assert_return(data, -EINVAL);
d8e538ec
TG
972 assert(m->n_containers <= RTNL_CONTAINER_DEPTH);
973 assert(m->rta_offset_tb[m->n_containers]);
974 assert(type < m->rta_tb_size[m->n_containers]);
44caa5e7 975
3dd215e0 976 if(!m->rta_offset_tb[m->n_containers][type])
44caa5e7
SS
977 return -ENODATA;
978
3dd215e0 979 rta = (struct rtattr*)((uint8_t *) m->hdr + m->rta_offset_tb[m->n_containers][type]);
44caa5e7 980
f66eeb6b
TG
981 *data = RTA_DATA(rta);
982
983 return RTA_PAYLOAD(rta);
44caa5e7
SS
984}
985
ca4e095a 986int sd_rtnl_message_read_string(sd_rtnl_message *m, unsigned short type, const char **data) {
44caa5e7
SS
987 int r;
988 void *attr_data;
989
73ae2b7d
TG
990 assert_return(m, -EINVAL);
991
d8e538ec
TG
992 r = message_attribute_has_type(m, type, NLA_STRING);
993 if (r < 0)
994 return r;
44caa5e7
SS
995
996 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 997 if (r < 0)
44caa5e7 998 return r;
f66eeb6b
TG
999 else if (strnlen(attr_data, r) >= (size_t) r)
1000 return -EIO;
44caa5e7 1001
73ae2b7d
TG
1002 if (data)
1003 *data = (const char *) attr_data;
44caa5e7
SS
1004
1005 return 0;
1006}
1007
1008int sd_rtnl_message_read_u8(sd_rtnl_message *m, unsigned short type, uint8_t *data) {
1009 int r;
1010 void *attr_data;
1011
73ae2b7d
TG
1012 assert_return(m, -EINVAL);
1013
d8e538ec
TG
1014 r = message_attribute_has_type(m, type, NLA_U8);
1015 if (r < 0)
1016 return r;
44caa5e7
SS
1017
1018 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 1019 if (r < 0)
44caa5e7 1020 return r;
f66eeb6b
TG
1021 else if ((size_t) r < sizeof(uint8_t))
1022 return -EIO;
44caa5e7 1023
73ae2b7d
TG
1024 if (data)
1025 *data = *(uint8_t *) attr_data;
44caa5e7
SS
1026
1027 return 0;
1028}
1029
1030int sd_rtnl_message_read_u16(sd_rtnl_message *m, unsigned short type, uint16_t *data) {
1031 int r;
1032 void *attr_data;
1033
73ae2b7d
TG
1034 assert_return(m, -EINVAL);
1035
d8e538ec
TG
1036 r = message_attribute_has_type(m, type, NLA_U16);
1037 if (r < 0)
1038 return r;
44caa5e7
SS
1039
1040 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 1041 if (r < 0)
44caa5e7 1042 return r;
f66eeb6b
TG
1043 else if ((size_t) r < sizeof(uint16_t))
1044 return -EIO;
44caa5e7 1045
73ae2b7d
TG
1046 if (data)
1047 *data = *(uint16_t *) attr_data;
44caa5e7
SS
1048
1049 return 0;
1050}
1051
1052int sd_rtnl_message_read_u32(sd_rtnl_message *m, unsigned short type, uint32_t *data) {
1053 int r;
1054 void *attr_data;
1055
73ae2b7d
TG
1056 assert_return(m, -EINVAL);
1057
d8e538ec
TG
1058 r = message_attribute_has_type(m, type, NLA_U32);
1059 if (r < 0)
1060 return r;
44caa5e7
SS
1061
1062 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 1063 if (r < 0)
44caa5e7 1064 return r;
f66eeb6b
TG
1065 else if ((size_t)r < sizeof(uint32_t))
1066 return -EIO;
44caa5e7 1067
73ae2b7d
TG
1068 if (data)
1069 *data = *(uint32_t *) attr_data;
44caa5e7
SS
1070
1071 return 0;
1072}
1073
4e9e7f18
SS
1074int sd_rtnl_message_read_ether_addr(sd_rtnl_message *m, unsigned short type, struct ether_addr *data) {
1075 int r;
1076 void *attr_data;
1077
73ae2b7d
TG
1078 assert_return(m, -EINVAL);
1079
d8e538ec
TG
1080 r = message_attribute_has_type(m, type, NLA_ETHER_ADDR);
1081 if (r < 0)
1082 return r;
4e9e7f18
SS
1083
1084 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 1085 if (r < 0)
4e9e7f18 1086 return r;
f66eeb6b
TG
1087 else if ((size_t)r < sizeof(struct ether_addr))
1088 return -EIO;
4e9e7f18 1089
73ae2b7d
TG
1090 if (data)
1091 memcpy(data, attr_data, sizeof(struct ether_addr));
4e9e7f18
SS
1092
1093 return 0;
1094}
1095
aba496a5
UTL
1096int sd_rtnl_message_read_cache_info(sd_rtnl_message *m, unsigned short type, struct ifa_cacheinfo *info) {
1097 int r;
1098 void *attr_data;
1099
73ae2b7d
TG
1100 assert_return(m, -EINVAL);
1101
aba496a5
UTL
1102 r = message_attribute_has_type(m, type, NLA_CACHE_INFO);
1103 if (r < 0)
1104 return r;
1105
1106 r = rtnl_message_read_internal(m, type, &attr_data);
1107 if (r < 0)
1108 return r;
1109 else if ((size_t)r < sizeof(struct ifa_cacheinfo))
1110 return -EIO;
1111
73ae2b7d
TG
1112 if (info)
1113 memcpy(info, attr_data, sizeof(struct ifa_cacheinfo));
aba496a5
UTL
1114
1115 return 0;
1116}
1117
4e9e7f18
SS
1118int sd_rtnl_message_read_in_addr(sd_rtnl_message *m, unsigned short type, struct in_addr *data) {
1119 int r;
1120 void *attr_data;
1121
73ae2b7d
TG
1122 assert_return(m, -EINVAL);
1123
d8e538ec
TG
1124 r = message_attribute_has_type(m, type, NLA_IN_ADDR);
1125 if (r < 0)
1126 return r;
4e9e7f18
SS
1127
1128 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 1129 if (r < 0)
4e9e7f18 1130 return r;
f66eeb6b
TG
1131 else if ((size_t)r < sizeof(struct in_addr))
1132 return -EIO;
4e9e7f18 1133
73ae2b7d
TG
1134 if (data)
1135 memcpy(data, attr_data, sizeof(struct in_addr));
4e9e7f18
SS
1136
1137 return 0;
1138}
1139
1140int sd_rtnl_message_read_in6_addr(sd_rtnl_message *m, unsigned short type, struct in6_addr *data) {
1141 int r;
1142 void *attr_data;
1143
73ae2b7d
TG
1144 assert_return(m, -EINVAL);
1145
d8e538ec
TG
1146 r = message_attribute_has_type(m, type, NLA_IN_ADDR);
1147 if (r < 0)
1148 return r;
4e9e7f18
SS
1149
1150 r = rtnl_message_read_internal(m, type, &attr_data);
3dd215e0 1151 if (r < 0)
4e9e7f18 1152 return r;
3dd215e0
TG
1153 else if ((size_t)r < sizeof(struct in6_addr))
1154 return -EIO;
4e9e7f18 1155
73ae2b7d
TG
1156 if (data)
1157 memcpy(data, attr_data, sizeof(struct in6_addr));
4e9e7f18
SS
1158
1159 return 0;
1160}
1161
3dd215e0 1162int sd_rtnl_message_enter_container(sd_rtnl_message *m, unsigned short type) {
d8e538ec
TG
1163 const NLType *nl_type;
1164 const NLTypeSystem *type_system;
3dd215e0 1165 void *container;
d8e538ec
TG
1166 size_t size;
1167 int r;
3dd215e0
TG
1168
1169 assert_return(m, -EINVAL);
1170 assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL);
1171
d8e538ec
TG
1172 r = type_system_get_type(m->container_type_system[m->n_containers],
1173 &nl_type,
1174 type);
3dd215e0
TG
1175 if (r < 0)
1176 return r;
3dd215e0 1177
d8e538ec
TG
1178 if (nl_type->type == NLA_NESTED) {
1179 r = type_system_get_type_system(m->container_type_system[m->n_containers],
1180 &type_system,
1181 type);
1182 if (r < 0)
1183 return r;
1184 } else if (nl_type->type == NLA_UNION) {
1185 const NLTypeSystemUnion *type_system_union;
ca4e095a 1186 const char *key;
d8e538ec
TG
1187
1188 r = type_system_get_type_system_union(m->container_type_system[m->n_containers],
1189 &type_system_union,
1190 type);
1191 if (r < 0)
1192 return r;
1193
1194 r = sd_rtnl_message_read_string(m, type_system_union->match, &key);
1195 if (r < 0)
1196 return r;
1197
1198 r = type_system_union_get_type_system(type_system_union,
1199 &type_system,
1200 key);
1201 if (r < 0)
1202 return r;
1203 } else
1204 return -EINVAL;
1205
1206 r = rtnl_message_read_internal(m, type, &container);
3dd215e0
TG
1207 if (r < 0)
1208 return r;
d8e538ec
TG
1209 else
1210 size = (size_t)r;
3dd215e0 1211
d8e538ec 1212 m->n_containers ++;
3dd215e0
TG
1213
1214 r = rtnl_message_parse(m,
d8e538ec
TG
1215 &m->rta_offset_tb[m->n_containers],
1216 &m->rta_tb_size[m->n_containers],
1217 type_system->max,
3dd215e0 1218 container,
d8e538ec
TG
1219 size);
1220 if (r < 0) {
1221 m->n_containers --;
3dd215e0 1222 return r;
d8e538ec 1223 }
3dd215e0 1224
d8e538ec 1225 m->container_type_system[m->n_containers] = type_system;
3dd215e0
TG
1226
1227 return 0;
1228}
1229
e5c4350b
TG
1230int sd_rtnl_message_exit_container(sd_rtnl_message *m) {
1231 assert_return(m, -EINVAL);
1232 assert_return(m->sealed, -EINVAL);
1233 assert_return(m->n_containers > 0, -EINVAL);
1234
3dd215e0
TG
1235 free(m->rta_offset_tb[m->n_containers]);
1236 m->rta_offset_tb[m->n_containers] = NULL;
d8e538ec 1237 m->container_type_system[m->n_containers] = NULL;
3dd215e0 1238
e5c4350b
TG
1239 m->n_containers --;
1240
1241 return 0;
1242}
1243
3815f36f 1244uint32_t rtnl_message_get_serial(sd_rtnl_message *m) {
65f568bb 1245 assert(m);
9d0db178 1246 assert(m->hdr);
65f568bb
TG
1247
1248 return m->hdr->nlmsg_seq;
1249}
1250
45af44d4
TG
1251int sd_rtnl_message_is_error(sd_rtnl_message *m) {
1252 assert_return(m, 0);
1253 assert_return(m->hdr, 0);
1254
1255 return m->hdr->nlmsg_type == NLMSG_ERROR;
1256}
1257
e16bcf98 1258int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
65f568bb
TG
1259 struct nlmsgerr *err;
1260
e16bcf98 1261 assert_return(m, -EINVAL);
9d0db178 1262 assert_return(m->hdr, -EINVAL);
65f568bb 1263
45af44d4 1264 if (!sd_rtnl_message_is_error(m))
65f568bb
TG
1265 return 0;
1266
1267 err = NLMSG_DATA(m->hdr);
1268
1269 return err->error;
1270}
1271
44caa5e7
SS
1272int rtnl_message_parse(sd_rtnl_message *m,
1273 size_t **rta_offset_tb,
1274 unsigned short *rta_tb_size,
1275 int max,
1276 struct rtattr *rta,
1277 unsigned int rt_len) {
e634cd40 1278 unsigned short type;
44caa5e7
SS
1279 size_t *tb;
1280
c8a7165f 1281 tb = new0(size_t, max + 1);
44caa5e7
SS
1282 if(!tb)
1283 return -ENOMEM;
1284
c8a7165f 1285 *rta_tb_size = max + 1;
44caa5e7
SS
1286
1287 for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) {
0a2478a9 1288 type = RTA_TYPE(rta);
44caa5e7 1289
aef0768e
TG
1290 /* if the kernel is newer than the headers we used
1291 when building, we ignore out-of-range attributes
1292 */
1293 if (type > max)
e634cd40 1294 continue;
e634cd40
TG
1295
1296 if (tb[type])
1297 log_debug("rtnl: message parse - overwriting repeated attribute");
1298
1299 tb[type] = (uint8_t *) rta - (uint8_t *) m->hdr;
44caa5e7
SS
1300 }
1301
1302 *rta_offset_tb = tb;
1303
1304 return 0;
1305}
1306
65f568bb
TG
1307/* returns the number of bytes sent, or a negative error code */
1308int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
d4bbdb77
TG
1309 union {
1310 struct sockaddr sa;
1311 struct sockaddr_nl nl;
1312 } addr = {
1313 .nl.nl_family = AF_NETLINK,
1314 };
65f568bb
TG
1315 ssize_t k;
1316
9d0db178
TG
1317 assert(nl);
1318 assert(m);
1319 assert(m->hdr);
65f568bb
TG
1320
1321 k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
d4bbdb77 1322 0, &addr.sa, sizeof(addr));
65f568bb
TG
1323 if (k < 0)
1324 return (errno == EAGAIN) ? 0 : -errno;
1325
1326 return k;
1327}
1328
66269b05
TG
1329static int socket_recv_message(int fd, struct iovec *iov, uint32_t *_group, bool peek) {
1330 uint8_t cred_buffer[CMSG_SPACE(sizeof(struct ucred)) +
1331 CMSG_SPACE(sizeof(struct nl_pktinfo))];
bc078e71 1332 struct msghdr msg = {
26349add 1333 .msg_iov = iov,
bc078e71
TG
1334 .msg_iovlen = 1,
1335 .msg_control = cred_buffer,
1336 .msg_controllen = sizeof(cred_buffer),
1337 };
1338 struct cmsghdr *cmsg;
66269b05 1339 uint32_t group = 0;
26349add 1340 bool auth = false;
4e996881 1341 int r;
d4bbdb77 1342
26349add
TG
1343 assert(fd >= 0);
1344 assert(iov);
bc078e71 1345
26349add 1346 r = recvmsg(fd, &msg, MSG_TRUNC | (peek ? MSG_PEEK : 0));
5968b1c3 1347 if (r < 0) {
bc078e71 1348 /* no data */
5968b1c3
TG
1349 if (errno == ENOBUFS)
1350 log_debug("rtnl: kernel receive buffer overrun");
0b2bbbdf
TG
1351 else if (errno == EAGAIN)
1352 log_debug("rtnl: no data in socket");
5968b1c3 1353
0b2bbbdf 1354 return (errno == EAGAIN || errno == EINTR) ? 0 : -errno;
5968b1c3 1355 } else if (r == 0)
bc078e71
TG
1356 /* connection was closed by the kernel */
1357 return -ECONNRESET;
3dd215e0 1358
bc078e71
TG
1359 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
1360 if (cmsg->cmsg_level == SOL_SOCKET &&
1361 cmsg->cmsg_type == SCM_CREDENTIALS &&
1362 cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
1363 struct ucred *ucred = (void *)CMSG_DATA(cmsg);
1364
1365 /* from the kernel */
09773ef4 1366 if (ucred->pid == 0)
bc078e71 1367 auth = true;
2263bb9a 1368 else
09773ef4 1369 log_debug("rtnl: ignoring message from pid %u", ucred->pid);
66269b05
TG
1370 } else if (cmsg->cmsg_level == SOL_NETLINK &&
1371 cmsg->cmsg_type == NETLINK_PKTINFO &&
1372 cmsg->cmsg_len == CMSG_LEN(sizeof(struct nl_pktinfo))) {
1373 struct nl_pktinfo *pktinfo = (void *)CMSG_DATA(cmsg);
1374
1375 /* multi-cast group */
1376 group = pktinfo->group;
bc078e71
TG
1377 }
1378 }
1379
c7460cce 1380 if (!auth) {
bc078e71 1381 /* not from the kernel, ignore */
c7460cce
TG
1382 if (peek) {
1383 /* drop the message */
1384 r = recvmsg(fd, &msg, 0);
1385 if (r < 0)
1386 return (errno == EAGAIN || errno == EINTR) ? 0 : -errno;
1387 }
1388
bc078e71 1389 return 0;
c7460cce 1390 }
bc078e71 1391
66269b05
TG
1392 if (group)
1393 *_group = group;
1394
26349add
TG
1395 return r;
1396}
1397
1398/* On success, the number of bytes received is returned and *ret points to the received message
1399 * which has a valid header and the correct size.
1400 * If nothing useful was received 0 is returned.
1401 * On failure, a negative error code is returned.
1402 */
1403int socket_read_message(sd_rtnl *rtnl) {
1404 _cleanup_rtnl_message_unref_ sd_rtnl_message *first = NULL;
1405 struct iovec iov = {};
66269b05 1406 uint32_t group = 0;
26349add
TG
1407 bool multi_part = false, done = false;
1408 struct nlmsghdr *new_msg;
1409 size_t len;
1410 int r;
1411 unsigned i = 0;
1412
1413 assert(rtnl);
1414 assert(rtnl->rbuffer);
1415 assert(rtnl->rbuffer_allocated >= sizeof(struct nlmsghdr));
1416
1417 /* read nothing, just get the pending message size */
66269b05 1418 r = socket_recv_message(rtnl->fd, &iov, &group, true);
26349add
TG
1419 if (r <= 0)
1420 return r;
1421 else
1422 len = (size_t)r;
1423
1424 /* make room for the pending message */
1425 if (!greedy_realloc((void **)&rtnl->rbuffer,
1426 &rtnl->rbuffer_allocated,
1427 len, sizeof(uint8_t)))
1428 return -ENOMEM;
1429
1430 iov.iov_base = rtnl->rbuffer;
1431 iov.iov_len = rtnl->rbuffer_allocated;
1432
1433 /* read the pending message */
66269b05 1434 r = socket_recv_message(rtnl->fd, &iov, &group, false);
26349add
TG
1435 if (r <= 0)
1436 return r;
1437 else
1438 len = (size_t)r;
1439
127dc4ea
TG
1440 if (len > rtnl->rbuffer_allocated)
1441 /* message did not fit in read buffer */
1442 return -EIO;
1443
4e996881
TG
1444 if (NLMSG_OK(rtnl->rbuffer, len) && rtnl->rbuffer->nlmsg_flags & NLM_F_MULTI) {
1445 multi_part = true;
1446
1447 for (i = 0; i < rtnl->rqueue_partial_size; i++) {
1448 if (rtnl_message_get_serial(rtnl->rqueue_partial[i]) ==
1449 rtnl->rbuffer->nlmsg_seq) {
1450 first = rtnl->rqueue_partial[i];
1451 break;
1452 }
1453 }
1454 }
1455
0e707326 1456 for (new_msg = rtnl->rbuffer; NLMSG_OK(new_msg, len) && !done; new_msg = NLMSG_NEXT(new_msg, len)) {
1b89cf56
TG
1457 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
1458 const NLType *nl_type;
3dd215e0 1459
8fe65c03 1460 if (!group && new_msg->nlmsg_pid != rtnl->sockaddr.nl.nl_pid)
1b89cf56
TG
1461 /* not broadcast and not for us */
1462 continue;
3dd215e0 1463
1b89cf56 1464 if (new_msg->nlmsg_type == NLMSG_NOOP)
4e996881 1465 /* silently drop noop messages */
1b89cf56 1466 continue;
bdd13f6b 1467
4e996881
TG
1468 if (new_msg->nlmsg_type == NLMSG_DONE) {
1469 /* finished reading multi-part message */
1470 done = true;
0e707326
TG
1471
1472 continue;
4e996881 1473 }
1403f45a 1474
1b89cf56
TG
1475 /* check that we support this message type */
1476 r = type_system_get_type(NULL, &nl_type, new_msg->nlmsg_type);
1477 if (r < 0) {
1478 if (r == -ENOTSUP)
1479 log_debug("sd-rtnl: ignored message with unknown type: %u",
1480 new_msg->nlmsg_type);
d8e538ec 1481
1b89cf56
TG
1482 continue;
1483 }
bdd13f6b 1484
1b89cf56 1485 /* check that the size matches the message type */
64918838
TG
1486 if (new_msg->nlmsg_len < NLMSG_LENGTH(nl_type->size)) {
1487 log_debug("sd-rtnl: message larger than expected, dropping");
1b89cf56 1488 continue;
64918838 1489 }
65f568bb 1490
1b89cf56
TG
1491 r = message_new_empty(rtnl, &m);
1492 if (r < 0)
1493 return r;
1494
1495 m->hdr = memdup(new_msg, new_msg->nlmsg_len);
1496 if (!m->hdr)
1497 return -ENOMEM;
1498
1499 /* seal and parse the top-level message */
1500 r = sd_rtnl_message_rewind(m);
1501 if (r < 0)
1502 return r;
1503
4e996881
TG
1504 /* push the message onto the multi-part message stack */
1505 if (first)
1506 m->next = first;
1507 first = m;
1b89cf56 1508 m = NULL;
4e996881 1509 }
1403f45a 1510
4e996881
TG
1511 if (len)
1512 log_debug("sd-rtnl: discarding %zu bytes of incoming message", len);
1b89cf56 1513
4e996881
TG
1514 if (!first)
1515 return 0;
65f568bb 1516
4e996881
TG
1517 if (!multi_part || done) {
1518 /* we got a complete message, push it on the read queue */
24a02673
TG
1519 r = rtnl_rqueue_make_room(rtnl);
1520 if (r < 0)
1521 return r;
1522
d4ef4f46
TG
1523 rtnl->rqueue[rtnl->rqueue_size ++] = first;
1524 first = NULL;
1525
1526 if (multi_part && (i < rtnl->rqueue_partial_size)) {
4e996881
TG
1527 /* remove the message form the partial read queue */
1528 memmove(rtnl->rqueue_partial + i,rtnl->rqueue_partial + i + 1,
1529 sizeof(sd_rtnl_message*) * (rtnl->rqueue_partial_size - i - 1));
1530 rtnl->rqueue_partial_size --;
1531 }
1532
4e996881
TG
1533 return 1;
1534 } else {
1535 /* we only got a partial multi-part message, push it on the
1536 partial read queue */
1537 if (i < rtnl->rqueue_partial_size) {
1538 rtnl->rqueue_partial[i] = first;
1539 } else {
1540 r = rtnl_rqueue_partial_make_room(rtnl);
1541 if (r < 0)
1542 return r;
1543
1544 rtnl->rqueue_partial[rtnl->rqueue_partial_size ++] = first;
1545 }
1546 first = NULL;
1403f45a 1547
4e996881
TG
1548 return 0;
1549 }
65f568bb 1550}
0fc7531b
TG
1551
1552int sd_rtnl_message_rewind(sd_rtnl_message *m) {
d8e538ec 1553 const NLType *type;
3dd215e0
TG
1554 unsigned i;
1555 int r;
0fc7531b
TG
1556
1557 assert_return(m, -EINVAL);
0fc7531b 1558
3dd215e0
TG
1559 /* don't allow appending to message once parsed */
1560 if (!m->sealed)
1561 rtnl_message_seal(m);
1562
1563 for (i = 1; i <= m->n_containers; i++) {
1564 free(m->rta_offset_tb[i]);
1565 m->rta_offset_tb[i] = NULL;
1566 m->rta_tb_size[i] = 0;
d8e538ec 1567 m->container_type_system[i] = NULL;
3dd215e0
TG
1568 }
1569
1570 m->n_containers = 0;
1571
1572 if (m->rta_offset_tb[0]) {
1573 /* top-level attributes have already been parsed */
1574 return 0;
1575 }
1576
d8e538ec
TG
1577 assert(m->hdr);
1578
1579 r = type_system_get_type(NULL, &type, m->hdr->nlmsg_type);
1580 if (r < 0)
1581 return r;
1582
1583 if (type->type == NLA_NESTED) {
1584 const NLTypeSystem *type_system = type->type_system;
1585
1586 assert(type_system);
1587
1588 m->container_type_system[0] = type_system;
1589
1590 r = rtnl_message_parse(m,
1591 &m->rta_offset_tb[m->n_containers],
1592 &m->rta_tb_size[m->n_containers],
1593 type_system->max,
0834ff93
TG
1594 (struct rtattr*)((uint8_t*)NLMSG_DATA(m->hdr) +
1595 NLMSG_ALIGN(type->size)),
d8e538ec
TG
1596 NLMSG_PAYLOAD(m->hdr, type->size));
1597 if (r < 0)
1598 return r;
0fc7531b
TG
1599 }
1600
1601 return 0;
1602}
3dd215e0
TG
1603
1604void rtnl_message_seal(sd_rtnl_message *m) {
1605 assert(m);
1606 assert(!m->sealed);
1607
1608 m->sealed = true;
1609}
1403f45a
TG
1610
1611sd_rtnl_message *sd_rtnl_message_next(sd_rtnl_message *m) {
1612 assert_return(m, NULL);
1613
1614 return m->next;
1615}