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