]>
git.ipfire.org Git - people/ms/rstp.git/blob - libnetlink.c
2 * libnetlink.c RTnetlink service routines.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
18 #include <net/if_arp.h>
19 #include <sys/socket.h>
20 #include <netinet/in.h>
26 #include "libnetlink.h"
28 void rtnl_close(struct rtnl_handle
*rth
)
33 int rtnl_open_byproto(struct rtnl_handle
*rth
, unsigned subscriptions
,
40 memset(rth
, 0, sizeof(rth
));
42 rth
->fd
= socket(AF_NETLINK
, SOCK_RAW
, protocol
);
44 perror("Cannot open netlink socket");
48 if (setsockopt(rth
->fd
, SOL_SOCKET
, SO_SNDBUF
, &sndbuf
, sizeof(sndbuf
))
54 if (setsockopt(rth
->fd
, SOL_SOCKET
, SO_RCVBUF
, &rcvbuf
, sizeof(rcvbuf
))
60 memset(&rth
->local
, 0, sizeof(rth
->local
));
61 rth
->local
.nl_family
= AF_NETLINK
;
62 rth
->local
.nl_groups
= subscriptions
;
64 if (bind(rth
->fd
, (struct sockaddr
*)&rth
->local
, sizeof(rth
->local
)) <
66 perror("Cannot bind netlink socket");
69 addr_len
= sizeof(rth
->local
);
70 if (getsockname(rth
->fd
, (struct sockaddr
*)&rth
->local
, &addr_len
) < 0) {
71 perror("Cannot getsockname");
74 if (addr_len
!= sizeof(rth
->local
)) {
75 fprintf(stderr
, "Wrong address length %d\n", addr_len
);
78 if (rth
->local
.nl_family
!= AF_NETLINK
) {
79 fprintf(stderr
, "Wrong address family %d\n",
80 rth
->local
.nl_family
);
83 rth
->seq
= time(NULL
);
87 int rtnl_open(struct rtnl_handle
*rth
, unsigned subscriptions
)
89 return rtnl_open_byproto(rth
, subscriptions
, NETLINK_ROUTE
);
92 int rtnl_wilddump_request(struct rtnl_handle
*rth
, int family
, int type
)
98 struct sockaddr_nl nladdr
;
100 memset(&nladdr
, 0, sizeof(nladdr
));
101 nladdr
.nl_family
= AF_NETLINK
;
103 memset(&req
, 0, sizeof(req
));
104 req
.nlh
.nlmsg_len
= sizeof(req
);
105 req
.nlh
.nlmsg_type
= type
;
106 req
.nlh
.nlmsg_flags
= NLM_F_ROOT
| NLM_F_MATCH
| NLM_F_REQUEST
;
107 req
.nlh
.nlmsg_pid
= 0;
108 req
.nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
;
109 req
.g
.rtgen_family
= family
;
111 return sendto(rth
->fd
, (void *)&req
, sizeof(req
), 0,
112 (struct sockaddr
*)&nladdr
, sizeof(nladdr
));
115 int rtnl_send(struct rtnl_handle
*rth
, const char *buf
, int len
)
117 struct sockaddr_nl nladdr
;
119 memset(&nladdr
, 0, sizeof(nladdr
));
120 nladdr
.nl_family
= AF_NETLINK
;
122 return sendto(rth
->fd
, buf
, len
, 0, (struct sockaddr
*)&nladdr
,
126 int rtnl_dump_request(struct rtnl_handle
*rth
, int type
, void *req
, int len
)
129 struct sockaddr_nl nladdr
;
130 struct iovec iov
[2] = {
131 {.iov_base
= &nlh
,.iov_len
= sizeof(nlh
)}
133 {.iov_base
= req
,.iov_len
= len
}
135 struct msghdr msg
= {
137 .msg_namelen
= sizeof(nladdr
),
142 memset(&nladdr
, 0, sizeof(nladdr
));
143 nladdr
.nl_family
= AF_NETLINK
;
145 nlh
.nlmsg_len
= NLMSG_LENGTH(len
);
146 nlh
.nlmsg_type
= type
;
147 nlh
.nlmsg_flags
= NLM_F_ROOT
| NLM_F_MATCH
| NLM_F_REQUEST
;
149 nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
;
151 return sendmsg(rth
->fd
, &msg
, 0);
154 int rtnl_dump_filter(struct rtnl_handle
*rth
,
155 rtnl_filter_t filter
,
156 void *arg1
, rtnl_filter_t junk
, void *arg2
)
158 struct sockaddr_nl nladdr
;
160 struct msghdr msg
= {
162 .msg_namelen
= sizeof(nladdr
),
173 iov
.iov_len
= sizeof(buf
);
174 status
= recvmsg(rth
->fd
, &msg
, 0);
184 fprintf(stderr
, "EOF on netlink\n");
188 h
= (struct nlmsghdr
*)buf
;
189 while (NLMSG_OK(h
, status
)) {
192 if (nladdr
.nl_pid
!= 0 ||
193 h
->nlmsg_pid
!= rth
->local
.nl_pid
||
194 h
->nlmsg_seq
!= rth
->dump
) {
196 err
= junk(&nladdr
, h
, arg2
);
203 if (h
->nlmsg_type
== NLMSG_DONE
)
205 if (h
->nlmsg_type
== NLMSG_ERROR
) {
206 struct nlmsgerr
*err
=
207 (struct nlmsgerr
*)NLMSG_DATA(h
);
209 NLMSG_LENGTH(sizeof(struct nlmsgerr
))) {
210 fprintf(stderr
, "ERROR truncated\n");
213 perror("RTNETLINK answers");
217 err
= filter(&nladdr
, h
, arg1
);
222 h
= NLMSG_NEXT(h
, status
);
224 if (msg
.msg_flags
& MSG_TRUNC
) {
225 fprintf(stderr
, "Message truncated\n");
229 fprintf(stderr
, "!!!Remnant of size %d\n", status
);
235 int rtnl_talk(struct rtnl_handle
*rtnl
, struct nlmsghdr
*n
, pid_t peer
,
236 unsigned groups
, struct nlmsghdr
*answer
,
237 rtnl_filter_t junk
, void *jarg
)
242 struct sockaddr_nl nladdr
;
244 .iov_base
= (void *)n
,
245 .iov_len
= n
->nlmsg_len
247 struct msghdr msg
= {
249 .msg_namelen
= sizeof(nladdr
),
255 memset(&nladdr
, 0, sizeof(nladdr
));
256 nladdr
.nl_family
= AF_NETLINK
;
257 nladdr
.nl_pid
= peer
;
258 nladdr
.nl_groups
= groups
;
260 n
->nlmsg_seq
= seq
= ++rtnl
->seq
;
263 n
->nlmsg_flags
|= NLM_F_ACK
;
265 status
= sendmsg(rtnl
->fd
, &msg
, 0);
268 perror("Cannot talk to rtnetlink");
272 memset(buf
, 0, sizeof(buf
));
277 iov
.iov_len
= sizeof(buf
);
278 status
= recvmsg(rtnl
->fd
, &msg
, 0);
287 fprintf(stderr
, "EOF on netlink\n");
290 if (msg
.msg_namelen
!= sizeof(nladdr
)) {
291 fprintf(stderr
, "sender address length == %d\n",
295 for (h
= (struct nlmsghdr
*)buf
; status
>= sizeof(*h
);) {
297 int len
= h
->nlmsg_len
;
298 int l
= len
- sizeof(*h
);
300 if (l
< 0 || len
> status
) {
301 if (msg
.msg_flags
& MSG_TRUNC
) {
302 fprintf(stderr
, "Truncated message\n");
306 "!!!malformed message: len=%d\n", len
);
310 if (nladdr
.nl_pid
!= peer
||
311 h
->nlmsg_pid
!= rtnl
->local
.nl_pid
||
312 h
->nlmsg_seq
!= seq
) {
314 err
= junk(&nladdr
, h
, jarg
);
318 /* Don't forget to skip that message. */
319 status
-= NLMSG_ALIGN(len
);
320 h
= (struct nlmsghdr
*)((char *)h
+
325 if (h
->nlmsg_type
== NLMSG_ERROR
) {
326 struct nlmsgerr
*err
=
327 (struct nlmsgerr
*)NLMSG_DATA(h
);
328 if (l
< sizeof(struct nlmsgerr
)) {
329 fprintf(stderr
, "ERROR truncated\n");
338 perror("RTNETLINK answers");
343 memcpy(answer
, h
, h
->nlmsg_len
);
347 fprintf(stderr
, "Unexpected reply!!!\n");
349 status
-= NLMSG_ALIGN(len
);
350 h
= (struct nlmsghdr
*)((char *)h
+ NLMSG_ALIGN(len
));
352 if (msg
.msg_flags
& MSG_TRUNC
) {
353 fprintf(stderr
, "Message truncated\n");
357 fprintf(stderr
, "!!!Remnant of size %d\n", status
);
363 int rtnl_listen(struct rtnl_handle
*rtnl
, rtnl_filter_t handler
, void *jarg
)
367 struct sockaddr_nl nladdr
;
369 struct msghdr msg
= {
371 .msg_namelen
= sizeof(nladdr
),
377 memset(&nladdr
, 0, sizeof(nladdr
));
378 nladdr
.nl_family
= AF_NETLINK
;
380 nladdr
.nl_groups
= 0;
384 iov
.iov_len
= sizeof(buf
);
385 status
= recvmsg(rtnl
->fd
, &msg
, 0);
396 fprintf(stderr
, "EOF on netlink\n");
399 if (msg
.msg_namelen
!= sizeof(nladdr
)) {
400 fprintf(stderr
, "Sender address length == %d\n",
404 for (h
= (struct nlmsghdr
*)buf
; status
>= sizeof(*h
);) {
406 int len
= h
->nlmsg_len
;
407 int l
= len
- sizeof(*h
);
409 if (l
< 0 || len
> status
) {
410 if (msg
.msg_flags
& MSG_TRUNC
) {
411 fprintf(stderr
, "Truncated message\n");
415 "!!!malformed message: len=%d\n", len
);
419 err
= handler(&nladdr
, h
, jarg
);
421 fprintf(stderr
, "Handler returned %d\n", err
);
425 status
-= NLMSG_ALIGN(len
);
426 h
= (struct nlmsghdr
*)((char *)h
+ NLMSG_ALIGN(len
));
428 if (msg
.msg_flags
& MSG_TRUNC
) {
429 fprintf(stderr
, "Message truncated\n");
433 fprintf(stderr
, "!!!Remnant of size %d\n", status
);
439 int rtnl_from_file(FILE * rtnl
, rtnl_filter_t handler
, void *jarg
)
442 struct sockaddr_nl nladdr
;
444 struct nlmsghdr
*h
= (void *)buf
;
446 memset(&nladdr
, 0, sizeof(nladdr
));
447 nladdr
.nl_family
= AF_NETLINK
;
449 nladdr
.nl_groups
= 0;
455 status
= fread(&buf
, 1, sizeof(*h
), rtnl
);
460 perror("rtnl_from_file: fread");
467 type
= h
->nlmsg_type
;
468 l
= len
- sizeof(*h
);
470 if (l
< 0 || len
> sizeof(buf
)) {
471 fprintf(stderr
, "!!!malformed message: len=%d @%lu\n",
476 status
= fread(NLMSG_DATA(h
), 1, NLMSG_ALIGN(l
), rtnl
);
479 perror("rtnl_from_file: fread");
483 fprintf(stderr
, "rtnl-from_file: truncated message\n");
487 err
= handler(&nladdr
, h
, jarg
);
493 int addattr32(struct nlmsghdr
*n
, int maxlen
, int type
, __u32 data
)
495 int len
= RTA_LENGTH(4);
497 if (NLMSG_ALIGN(n
->nlmsg_len
) + len
> maxlen
) {
499 "addattr32: Error! max allowed bound %d exceeded\n",
504 rta
->rta_type
= type
;
506 memcpy(RTA_DATA(rta
), &data
, 4);
507 n
->nlmsg_len
= NLMSG_ALIGN(n
->nlmsg_len
) + len
;
511 int addattr_l(struct nlmsghdr
*n
, int maxlen
, int type
, const void *data
,
514 int len
= RTA_LENGTH(alen
);
517 if (NLMSG_ALIGN(n
->nlmsg_len
) + RTA_ALIGN(len
) > maxlen
) {
519 "addattr_l ERROR: message exceeded bound of %d\n",
524 rta
->rta_type
= type
;
526 memcpy(RTA_DATA(rta
), data
, alen
);
527 n
->nlmsg_len
= NLMSG_ALIGN(n
->nlmsg_len
) + RTA_ALIGN(len
);
531 int addraw_l(struct nlmsghdr
*n
, int maxlen
, const void *data
, int len
)
533 if (NLMSG_ALIGN(n
->nlmsg_len
) + NLMSG_ALIGN(len
) > maxlen
) {
535 "addraw_l ERROR: message exceeded bound of %d\n",
540 memcpy(NLMSG_TAIL(n
), data
, len
);
541 memset((void *)NLMSG_TAIL(n
) + len
, 0, NLMSG_ALIGN(len
) - len
);
542 n
->nlmsg_len
= NLMSG_ALIGN(n
->nlmsg_len
) + NLMSG_ALIGN(len
);
546 int rta_addattr32(struct rtattr
*rta
, int maxlen
, int type
, __u32 data
)
548 int len
= RTA_LENGTH(4);
549 struct rtattr
*subrta
;
551 if (RTA_ALIGN(rta
->rta_len
) + len
> maxlen
) {
553 "rta_addattr32: Error! max allowed bound %d exceeded\n",
557 subrta
= (struct rtattr
*)(((char *)rta
) + RTA_ALIGN(rta
->rta_len
));
558 subrta
->rta_type
= type
;
559 subrta
->rta_len
= len
;
560 memcpy(RTA_DATA(subrta
), &data
, 4);
561 rta
->rta_len
= NLMSG_ALIGN(rta
->rta_len
) + len
;
565 int rta_addattr_l(struct rtattr
*rta
, int maxlen
, int type
,
566 const void *data
, int alen
)
568 struct rtattr
*subrta
;
569 int len
= RTA_LENGTH(alen
);
571 if (RTA_ALIGN(rta
->rta_len
) + RTA_ALIGN(len
) > maxlen
) {
573 "rta_addattr_l: Error! max allowed bound %d exceeded\n",
577 subrta
= (struct rtattr
*)(((char *)rta
) + RTA_ALIGN(rta
->rta_len
));
578 subrta
->rta_type
= type
;
579 subrta
->rta_len
= len
;
580 memcpy(RTA_DATA(subrta
), data
, alen
);
581 rta
->rta_len
= NLMSG_ALIGN(rta
->rta_len
) + RTA_ALIGN(len
);
585 int parse_rtattr(struct rtattr
*tb
[], int max
, struct rtattr
*rta
, int len
)
587 memset(tb
, 0, sizeof(struct rtattr
*) * (max
+ 1));
588 while (RTA_OK(rta
, len
)) {
589 if (rta
->rta_type
<= max
)
590 tb
[rta
->rta_type
] = rta
;
591 rta
= RTA_NEXT(rta
, len
);
594 fprintf(stderr
, "!!!Deficit %d, rta_len=%d\n", len
,
599 int parse_rtattr_byindex(struct rtattr
*tb
[], int max
, struct rtattr
*rta
,
604 memset(tb
, 0, sizeof(struct rtattr
*) * max
);
605 while (RTA_OK(rta
, len
)) {
606 if (rta
->rta_type
<= max
&& i
< max
)
608 rta
= RTA_NEXT(rta
, len
);
611 fprintf(stderr
, "!!!Deficit %d, rta_len=%d\n", len
,