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