Line data Source code
1 : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2 :
3 : /***
4 : This file is part of systemd.
5 :
6 : Copyright 2013 Tom Gundersen <teg@jklm.no>
7 :
8 : systemd is free software; you can redistribute it and/or modify it
9 : under the terms of the GNU Lesser General Public License as published by
10 : the Free Software Foundation; either version 2.1 of the License, or
11 : (at your option) any later version.
12 :
13 : systemd is distributed in the hope that it will be useful, but
14 : WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 : Lesser General Public License for more details.
17 :
18 : You should have received a copy of the GNU Lesser General Public License
19 : along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 : ***/
21 :
22 : #include <netinet/in.h>
23 : #include <stdbool.h>
24 : #include <unistd.h>
25 :
26 : #include "util.h"
27 : #include "socket-util.h"
28 : #include "formats-util.h"
29 : #include "refcnt.h"
30 : #include "missing.h"
31 :
32 : #include "sd-netlink.h"
33 : #include "netlink-util.h"
34 : #include "netlink-internal.h"
35 : #include "netlink-types.h"
36 :
37 0 : int sd_rtnl_message_route_set_dst_prefixlen(sd_netlink_message *m, unsigned char prefixlen) {
38 : struct rtmsg *rtm;
39 :
40 0 : assert_return(m, -EINVAL);
41 0 : assert_return(m->hdr, -EINVAL);
42 0 : assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
43 :
44 0 : rtm = NLMSG_DATA(m->hdr);
45 :
46 0 : if ((rtm->rtm_family == AF_INET && prefixlen > 32) ||
47 0 : (rtm->rtm_family == AF_INET6 && prefixlen > 128))
48 0 : return -ERANGE;
49 :
50 0 : rtm->rtm_dst_len = prefixlen;
51 :
52 0 : return 0;
53 : }
54 :
55 0 : int sd_rtnl_message_route_set_src_prefixlen(sd_netlink_message *m, unsigned char prefixlen) {
56 : struct rtmsg *rtm;
57 :
58 0 : assert_return(m, -EINVAL);
59 0 : assert_return(m->hdr, -EINVAL);
60 0 : assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
61 :
62 0 : rtm = NLMSG_DATA(m->hdr);
63 :
64 0 : if ((rtm->rtm_family == AF_INET && prefixlen > 32) ||
65 0 : (rtm->rtm_family == AF_INET6 && prefixlen > 128))
66 0 : return -ERANGE;
67 :
68 0 : rtm->rtm_src_len = prefixlen;
69 :
70 0 : return 0;
71 : }
72 :
73 0 : int sd_rtnl_message_route_set_scope(sd_netlink_message *m, unsigned char scope) {
74 : struct rtmsg *rtm;
75 :
76 0 : assert_return(m, -EINVAL);
77 0 : assert_return(m->hdr, -EINVAL);
78 0 : assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
79 :
80 0 : rtm = NLMSG_DATA(m->hdr);
81 :
82 0 : rtm->rtm_scope = scope;
83 :
84 0 : return 0;
85 : }
86 :
87 3 : int sd_rtnl_message_route_get_family(sd_netlink_message *m, int *family) {
88 : struct rtmsg *rtm;
89 :
90 3 : assert_return(m, -EINVAL);
91 3 : assert_return(m->hdr, -EINVAL);
92 3 : assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
93 3 : assert_return(family, -EINVAL);
94 :
95 3 : rtm = NLMSG_DATA(m->hdr);
96 :
97 3 : *family = rtm->rtm_family;
98 :
99 3 : return 0;
100 : }
101 :
102 22 : int sd_rtnl_message_route_get_dst_prefixlen(sd_netlink_message *m, unsigned char *dst_len) {
103 : struct rtmsg *rtm;
104 :
105 22 : assert_return(m, -EINVAL);
106 22 : assert_return(m->hdr, -EINVAL);
107 22 : assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
108 22 : assert_return(dst_len, -EINVAL);
109 :
110 22 : rtm = NLMSG_DATA(m->hdr);
111 :
112 22 : *dst_len = rtm->rtm_dst_len;
113 :
114 22 : return 0;
115 : }
116 :
117 3 : int sd_rtnl_message_route_get_src_prefixlen(sd_netlink_message *m, unsigned char *src_len) {
118 : struct rtmsg *rtm;
119 :
120 3 : assert_return(m, -EINVAL);
121 3 : assert_return(m->hdr, -EINVAL);
122 3 : assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
123 3 : assert_return(src_len, -EINVAL);
124 :
125 3 : rtm = NLMSG_DATA(m->hdr);
126 :
127 3 : *src_len = rtm->rtm_src_len;
128 :
129 3 : return 0;
130 : }
131 :
132 2 : int sd_rtnl_message_new_route(sd_netlink *rtnl, sd_netlink_message **ret,
133 : uint16_t nlmsg_type, int rtm_family,
134 : unsigned char rtm_protocol) {
135 : struct rtmsg *rtm;
136 : int r;
137 :
138 2 : assert_return(rtnl_message_type_is_route(nlmsg_type), -EINVAL);
139 2 : assert_return((nlmsg_type == RTM_GETROUTE && rtm_family == AF_UNSPEC) ||
140 : rtm_family == AF_INET || rtm_family == AF_INET6, -EINVAL);
141 2 : assert_return(ret, -EINVAL);
142 :
143 2 : r = message_new(rtnl, ret, nlmsg_type);
144 2 : if (r < 0)
145 0 : return r;
146 :
147 2 : if (nlmsg_type == RTM_NEWROUTE)
148 1 : (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_APPEND;
149 :
150 2 : rtm = NLMSG_DATA((*ret)->hdr);
151 :
152 2 : rtm->rtm_family = rtm_family;
153 2 : rtm->rtm_scope = RT_SCOPE_UNIVERSE;
154 2 : rtm->rtm_type = RTN_UNICAST;
155 2 : rtm->rtm_table = RT_TABLE_MAIN;
156 2 : rtm->rtm_protocol = rtm_protocol;
157 :
158 2 : return 0;
159 : }
160 :
161 0 : int sd_rtnl_message_neigh_set_flags(sd_netlink_message *m, uint8_t flags) {
162 : struct ndmsg *ndm;
163 :
164 0 : assert_return(m, -EINVAL);
165 0 : assert_return(m->hdr, -EINVAL);
166 0 : assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
167 :
168 0 : ndm = NLMSG_DATA(m->hdr);
169 0 : ndm->ndm_flags |= flags;
170 :
171 0 : return 0;
172 : }
173 :
174 0 : int sd_rtnl_message_neigh_set_state(sd_netlink_message *m, uint16_t state) {
175 : struct ndmsg *ndm;
176 :
177 0 : assert_return(m, -EINVAL);
178 0 : assert_return(m->hdr, -EINVAL);
179 0 : assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
180 :
181 0 : ndm = NLMSG_DATA(m->hdr);
182 0 : ndm->ndm_state |= state;
183 :
184 0 : return 0;
185 : }
186 :
187 0 : int sd_rtnl_message_neigh_get_flags(sd_netlink_message *m, uint8_t *flags) {
188 : struct ndmsg *ndm;
189 :
190 0 : assert_return(m, -EINVAL);
191 0 : assert_return(m->hdr, -EINVAL);
192 0 : assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
193 :
194 0 : ndm = NLMSG_DATA(m->hdr);
195 0 : *flags = ndm->ndm_flags;
196 :
197 0 : return 0;
198 : }
199 :
200 0 : int sd_rtnl_message_neigh_get_state(sd_netlink_message *m, uint16_t *state) {
201 : struct ndmsg *ndm;
202 :
203 0 : assert_return(m, -EINVAL);
204 0 : assert_return(m->hdr, -EINVAL);
205 0 : assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
206 :
207 0 : ndm = NLMSG_DATA(m->hdr);
208 0 : *state = ndm->ndm_state;
209 :
210 0 : return 0;
211 : }
212 :
213 0 : int sd_rtnl_message_neigh_get_family(sd_netlink_message *m, int *family) {
214 : struct ndmsg *ndm;
215 :
216 0 : assert_return(m, -EINVAL);
217 0 : assert_return(m->hdr, -EINVAL);
218 0 : assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
219 0 : assert_return(family, -EINVAL);
220 :
221 0 : ndm = NLMSG_DATA(m->hdr);
222 :
223 0 : *family = ndm->ndm_family;
224 :
225 0 : return 0;
226 : }
227 :
228 0 : int sd_rtnl_message_neigh_get_ifindex(sd_netlink_message *m, int *index) {
229 : struct ndmsg *ndm;
230 :
231 0 : assert_return(m, -EINVAL);
232 0 : assert_return(m->hdr, -EINVAL);
233 0 : assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
234 0 : assert_return(index, -EINVAL);
235 :
236 0 : ndm = NLMSG_DATA(m->hdr);
237 :
238 0 : *index = ndm->ndm_ifindex;
239 :
240 0 : return 0;
241 : }
242 :
243 0 : int sd_rtnl_message_new_neigh(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_type, int index, int ndm_family) {
244 : struct ndmsg *ndm;
245 : int r;
246 :
247 0 : assert_return(rtnl_message_type_is_neigh(nlmsg_type), -EINVAL);
248 0 : assert_return(ndm_family == AF_INET ||
249 : ndm_family == AF_INET6 ||
250 : ndm_family == PF_BRIDGE, -EINVAL);
251 0 : assert_return(ret, -EINVAL);
252 :
253 0 : r = message_new(rtnl, ret, nlmsg_type);
254 0 : if (r < 0)
255 0 : return r;
256 :
257 0 : if (nlmsg_type == RTM_NEWNEIGH)
258 0 : (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_APPEND;
259 :
260 0 : ndm = NLMSG_DATA((*ret)->hdr);
261 :
262 0 : ndm->ndm_family = ndm_family;
263 0 : ndm->ndm_ifindex = index;
264 :
265 0 : return 0;
266 : }
267 :
268 0 : int sd_rtnl_message_link_set_flags(sd_netlink_message *m, unsigned flags, unsigned change) {
269 : struct ifinfomsg *ifi;
270 :
271 0 : assert_return(m, -EINVAL);
272 0 : assert_return(m->hdr, -EINVAL);
273 0 : assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
274 0 : assert_return(change, -EINVAL);
275 :
276 0 : ifi = NLMSG_DATA(m->hdr);
277 :
278 0 : ifi->ifi_flags = flags;
279 0 : ifi->ifi_change = change;
280 :
281 0 : return 0;
282 : }
283 :
284 0 : int sd_rtnl_message_link_set_type(sd_netlink_message *m, unsigned type) {
285 : struct ifinfomsg *ifi;
286 :
287 0 : assert_return(m, -EINVAL);
288 0 : assert_return(m->hdr, -EINVAL);
289 0 : assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
290 :
291 0 : ifi = NLMSG_DATA(m->hdr);
292 :
293 0 : ifi->ifi_type = type;
294 :
295 0 : return 0;
296 : }
297 :
298 1 : int sd_rtnl_message_link_set_family(sd_netlink_message *m, unsigned family) {
299 : struct ifinfomsg *ifi;
300 :
301 1 : assert_return(m, -EINVAL);
302 1 : assert_return(m->hdr, -EINVAL);
303 1 : assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
304 :
305 1 : ifi = NLMSG_DATA(m->hdr);
306 :
307 1 : ifi->ifi_family = family;
308 :
309 1 : return 0;
310 : }
311 :
312 14 : int sd_rtnl_message_new_link(sd_netlink *rtnl, sd_netlink_message **ret,
313 : uint16_t nlmsg_type, int index) {
314 : struct ifinfomsg *ifi;
315 : int r;
316 :
317 14 : assert_return(rtnl_message_type_is_link(nlmsg_type), -EINVAL);
318 14 : assert_return(nlmsg_type != RTM_DELLINK || index > 0, -EINVAL);
319 14 : assert_return(ret, -EINVAL);
320 :
321 14 : r = message_new(rtnl, ret, nlmsg_type);
322 14 : if (r < 0)
323 0 : return r;
324 :
325 14 : if (nlmsg_type == RTM_NEWLINK)
326 2 : (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
327 :
328 14 : ifi = NLMSG_DATA((*ret)->hdr);
329 :
330 14 : ifi->ifi_family = AF_UNSPEC;
331 14 : ifi->ifi_index = index;
332 :
333 14 : return 0;
334 : }
335 :
336 0 : int sd_rtnl_message_addr_set_prefixlen(sd_netlink_message *m, unsigned char prefixlen) {
337 : struct ifaddrmsg *ifa;
338 :
339 0 : assert_return(m, -EINVAL);
340 0 : assert_return(m->hdr, -EINVAL);
341 0 : assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
342 :
343 0 : ifa = NLMSG_DATA(m->hdr);
344 :
345 0 : if ((ifa->ifa_family == AF_INET && prefixlen > 32) ||
346 0 : (ifa->ifa_family == AF_INET6 && prefixlen > 128))
347 0 : return -ERANGE;
348 :
349 0 : ifa->ifa_prefixlen = prefixlen;
350 :
351 0 : return 0;
352 : }
353 :
354 0 : int sd_rtnl_message_addr_set_flags(sd_netlink_message *m, unsigned char flags) {
355 : struct ifaddrmsg *ifa;
356 :
357 0 : assert_return(m, -EINVAL);
358 0 : assert_return(m->hdr, -EINVAL);
359 0 : assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
360 :
361 0 : ifa = NLMSG_DATA(m->hdr);
362 :
363 0 : ifa->ifa_flags = flags;
364 :
365 0 : return 0;
366 : }
367 :
368 0 : int sd_rtnl_message_addr_set_scope(sd_netlink_message *m, unsigned char scope) {
369 : struct ifaddrmsg *ifa;
370 :
371 0 : assert_return(m, -EINVAL);
372 0 : assert_return(m->hdr, -EINVAL);
373 0 : assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
374 :
375 0 : ifa = NLMSG_DATA(m->hdr);
376 :
377 0 : ifa->ifa_scope = scope;
378 :
379 0 : return 0;
380 : }
381 :
382 12 : int sd_rtnl_message_addr_get_family(sd_netlink_message *m, int *family) {
383 : struct ifaddrmsg *ifa;
384 :
385 12 : assert_return(m, -EINVAL);
386 12 : assert_return(m->hdr, -EINVAL);
387 12 : assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
388 12 : assert_return(family, -EINVAL);
389 :
390 12 : ifa = NLMSG_DATA(m->hdr);
391 :
392 12 : *family = ifa->ifa_family;
393 :
394 12 : return 0;
395 : }
396 :
397 0 : int sd_rtnl_message_addr_get_prefixlen(sd_netlink_message *m, unsigned char *prefixlen) {
398 : struct ifaddrmsg *ifa;
399 :
400 0 : assert_return(m, -EINVAL);
401 0 : assert_return(m->hdr, -EINVAL);
402 0 : assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
403 0 : assert_return(prefixlen, -EINVAL);
404 :
405 0 : ifa = NLMSG_DATA(m->hdr);
406 :
407 0 : *prefixlen = ifa->ifa_prefixlen;
408 :
409 0 : return 0;
410 : }
411 :
412 12 : int sd_rtnl_message_addr_get_scope(sd_netlink_message *m, unsigned char *scope) {
413 : struct ifaddrmsg *ifa;
414 :
415 12 : assert_return(m, -EINVAL);
416 12 : assert_return(m->hdr, -EINVAL);
417 12 : assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
418 12 : assert_return(scope, -EINVAL);
419 :
420 12 : ifa = NLMSG_DATA(m->hdr);
421 :
422 12 : *scope = ifa->ifa_scope;
423 :
424 12 : return 0;
425 : }
426 :
427 12 : int sd_rtnl_message_addr_get_flags(sd_netlink_message *m, unsigned char *flags) {
428 : struct ifaddrmsg *ifa;
429 :
430 12 : assert_return(m, -EINVAL);
431 12 : assert_return(m->hdr, -EINVAL);
432 12 : assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
433 12 : assert_return(flags, -EINVAL);
434 :
435 12 : ifa = NLMSG_DATA(m->hdr);
436 :
437 12 : *flags = ifa->ifa_flags;
438 :
439 12 : return 0;
440 : }
441 :
442 12 : int sd_rtnl_message_addr_get_ifindex(sd_netlink_message *m, int *ifindex) {
443 : struct ifaddrmsg *ifa;
444 :
445 12 : assert_return(m, -EINVAL);
446 12 : assert_return(m->hdr, -EINVAL);
447 12 : assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
448 12 : assert_return(ifindex, -EINVAL);
449 :
450 12 : ifa = NLMSG_DATA(m->hdr);
451 :
452 12 : *ifindex = ifa->ifa_index;
453 :
454 12 : return 0;
455 : }
456 :
457 3 : int sd_rtnl_message_new_addr(sd_netlink *rtnl, sd_netlink_message **ret,
458 : uint16_t nlmsg_type, int index,
459 : int family) {
460 : struct ifaddrmsg *ifa;
461 : int r;
462 :
463 3 : assert_return(rtnl_message_type_is_addr(nlmsg_type), -EINVAL);
464 3 : assert_return((nlmsg_type == RTM_GETADDR && index == 0) ||
465 : index > 0, -EINVAL);
466 3 : assert_return((nlmsg_type == RTM_GETADDR && family == AF_UNSPEC) ||
467 : family == AF_INET || family == AF_INET6, -EINVAL);
468 3 : assert_return(ret, -EINVAL);
469 :
470 3 : r = message_new(rtnl, ret, nlmsg_type);
471 3 : if (r < 0)
472 0 : return r;
473 :
474 3 : if (nlmsg_type == RTM_GETADDR)
475 3 : (*ret)->hdr->nlmsg_flags |= NLM_F_DUMP;
476 :
477 3 : ifa = NLMSG_DATA((*ret)->hdr);
478 :
479 3 : ifa->ifa_index = index;
480 3 : ifa->ifa_family = family;
481 3 : if (family == AF_INET)
482 1 : ifa->ifa_prefixlen = 32;
483 2 : else if (family == AF_INET6)
484 0 : ifa->ifa_prefixlen = 128;
485 :
486 3 : return 0;
487 : }
488 :
489 0 : int sd_rtnl_message_new_addr_update(sd_netlink *rtnl, sd_netlink_message **ret,
490 : int index, int family) {
491 : int r;
492 :
493 0 : r = sd_rtnl_message_new_addr(rtnl, ret, RTM_NEWADDR, index, family);
494 0 : if (r < 0)
495 0 : return r;
496 :
497 0 : (*ret)->hdr->nlmsg_flags |= NLM_F_REPLACE;
498 :
499 0 : return 0;
500 : }
501 :
502 8 : int sd_rtnl_message_link_get_ifindex(sd_netlink_message *m, int *ifindex) {
503 : struct ifinfomsg *ifi;
504 :
505 8 : assert_return(m, -EINVAL);
506 8 : assert_return(m->hdr, -EINVAL);
507 8 : assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
508 8 : assert_return(ifindex, -EINVAL);
509 :
510 8 : ifi = NLMSG_DATA(m->hdr);
511 :
512 8 : *ifindex = ifi->ifi_index;
513 :
514 8 : return 0;
515 : }
516 :
517 8 : int sd_rtnl_message_link_get_flags(sd_netlink_message *m, unsigned *flags) {
518 : struct ifinfomsg *ifi;
519 :
520 8 : assert_return(m, -EINVAL);
521 8 : assert_return(m->hdr, -EINVAL);
522 8 : assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
523 8 : assert_return(flags, -EINVAL);
524 :
525 8 : ifi = NLMSG_DATA(m->hdr);
526 :
527 8 : *flags = ifi->ifi_flags;
528 :
529 8 : return 0;
530 : }
531 :
532 0 : int sd_rtnl_message_link_get_type(sd_netlink_message *m, unsigned *type) {
533 : struct ifinfomsg *ifi;
534 :
535 0 : assert_return(m, -EINVAL);
536 0 : assert_return(m->hdr, -EINVAL);
537 0 : assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
538 0 : assert_return(type, -EINVAL);
539 :
540 0 : ifi = NLMSG_DATA(m->hdr);
541 :
542 0 : *type = ifi->ifi_type;
543 :
544 0 : return 0;
545 : }
546 :
547 2 : int sd_rtnl_message_get_family(sd_netlink_message *m, int *family) {
548 2 : assert_return(m, -EINVAL);
549 2 : assert_return(family, -EINVAL);
550 :
551 2 : assert(m->hdr);
552 :
553 2 : if (rtnl_message_type_is_link(m->hdr->nlmsg_type)) {
554 : struct ifinfomsg *ifi;
555 :
556 2 : ifi = NLMSG_DATA(m->hdr);
557 :
558 2 : *family = ifi->ifi_family;
559 :
560 2 : return 0;
561 0 : } else if (rtnl_message_type_is_route(m->hdr->nlmsg_type)) {
562 : struct rtmsg *rtm;
563 :
564 0 : rtm = NLMSG_DATA(m->hdr);
565 :
566 0 : *family = rtm->rtm_family;
567 :
568 0 : return 0;
569 0 : } else if (rtnl_message_type_is_neigh(m->hdr->nlmsg_type)) {
570 : struct ndmsg *ndm;
571 :
572 0 : ndm = NLMSG_DATA(m->hdr);
573 :
574 0 : *family = ndm->ndm_family;
575 :
576 0 : return 0;
577 0 : } else if (rtnl_message_type_is_addr(m->hdr->nlmsg_type)) {
578 : struct ifaddrmsg *ifa;
579 :
580 0 : ifa = NLMSG_DATA(m->hdr);
581 :
582 0 : *family = ifa->ifa_family;
583 :
584 0 : return 0;
585 : }
586 :
587 0 : return -EOPNOTSUPP;
588 : }
|