]>
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
)) < 0) {
53 if (setsockopt(rth
->fd
,SOL_SOCKET
,SO_RCVBUF
,&rcvbuf
,sizeof(rcvbuf
)) < 0) {
58 memset(&rth
->local
, 0, sizeof(rth
->local
));
59 rth
->local
.nl_family
= AF_NETLINK
;
60 rth
->local
.nl_groups
= subscriptions
;
62 if (bind(rth
->fd
, (struct sockaddr
*)&rth
->local
, sizeof(rth
->local
)) < 0) {
63 perror("Cannot bind netlink socket");
66 addr_len
= sizeof(rth
->local
);
67 if (getsockname(rth
->fd
, (struct sockaddr
*)&rth
->local
, &addr_len
) < 0) {
68 perror("Cannot getsockname");
71 if (addr_len
!= sizeof(rth
->local
)) {
72 fprintf(stderr
, "Wrong address length %d\n", addr_len
);
75 if (rth
->local
.nl_family
!= AF_NETLINK
) {
76 fprintf(stderr
, "Wrong address family %d\n", rth
->local
.nl_family
);
79 rth
->seq
= time(NULL
);
83 int rtnl_open(struct rtnl_handle
*rth
, unsigned subscriptions
)
85 return rtnl_open_byproto(rth
, subscriptions
, NETLINK_ROUTE
);
88 int rtnl_wilddump_request(struct rtnl_handle
*rth
, int family
, int type
)
94 struct sockaddr_nl nladdr
;
96 memset(&nladdr
, 0, sizeof(nladdr
));
97 nladdr
.nl_family
= AF_NETLINK
;
99 memset(&req
, 0, sizeof(req
));
100 req
.nlh
.nlmsg_len
= sizeof(req
);
101 req
.nlh
.nlmsg_type
= type
;
102 req
.nlh
.nlmsg_flags
= NLM_F_ROOT
|NLM_F_MATCH
|NLM_F_REQUEST
;
103 req
.nlh
.nlmsg_pid
= 0;
104 req
.nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
;
105 req
.g
.rtgen_family
= family
;
107 return sendto(rth
->fd
, (void*)&req
, sizeof(req
), 0,
108 (struct sockaddr
*)&nladdr
, sizeof(nladdr
));
111 int rtnl_send(struct rtnl_handle
*rth
, const char *buf
, int len
)
113 struct sockaddr_nl nladdr
;
115 memset(&nladdr
, 0, sizeof(nladdr
));
116 nladdr
.nl_family
= AF_NETLINK
;
118 return sendto(rth
->fd
, buf
, len
, 0, (struct sockaddr
*)&nladdr
, sizeof(nladdr
));
121 int rtnl_dump_request(struct rtnl_handle
*rth
, int type
, void *req
, int len
)
124 struct sockaddr_nl nladdr
;
125 struct iovec iov
[2] = {
126 { .iov_base
= &nlh
, .iov_len
= sizeof(nlh
) },
127 { .iov_base
= req
, .iov_len
= len
}
129 struct msghdr msg
= {
131 .msg_namelen
= sizeof(nladdr
),
136 memset(&nladdr
, 0, sizeof(nladdr
));
137 nladdr
.nl_family
= AF_NETLINK
;
139 nlh
.nlmsg_len
= NLMSG_LENGTH(len
);
140 nlh
.nlmsg_type
= type
;
141 nlh
.nlmsg_flags
= NLM_F_ROOT
|NLM_F_MATCH
|NLM_F_REQUEST
;
143 nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
;
145 return sendmsg(rth
->fd
, &msg
, 0);
148 int rtnl_dump_filter(struct rtnl_handle
*rth
,
149 rtnl_filter_t filter
,
154 struct sockaddr_nl nladdr
;
156 struct msghdr msg
= {
158 .msg_namelen
= sizeof(nladdr
),
169 iov
.iov_len
= sizeof(buf
);
170 status
= recvmsg(rth
->fd
, &msg
, 0);
180 fprintf(stderr
, "EOF on netlink\n");
184 h
= (struct nlmsghdr
*)buf
;
185 while (NLMSG_OK(h
, status
)) {
188 if (nladdr
.nl_pid
!= 0 ||
189 h
->nlmsg_pid
!= rth
->local
.nl_pid
||
190 h
->nlmsg_seq
!= rth
->dump
) {
192 err
= junk(&nladdr
, h
, arg2
);
199 if (h
->nlmsg_type
== NLMSG_DONE
)
201 if (h
->nlmsg_type
== NLMSG_ERROR
) {
202 struct nlmsgerr
*err
= (struct nlmsgerr
*)NLMSG_DATA(h
);
203 if (h
->nlmsg_len
< NLMSG_LENGTH(sizeof(struct nlmsgerr
))) {
204 fprintf(stderr
, "ERROR truncated\n");
207 perror("RTNETLINK answers");
211 err
= filter(&nladdr
, h
, arg1
);
216 h
= NLMSG_NEXT(h
, status
);
218 if (msg
.msg_flags
& MSG_TRUNC
) {
219 fprintf(stderr
, "Message truncated\n");
223 fprintf(stderr
, "!!!Remnant of size %d\n", status
);
229 int rtnl_talk(struct rtnl_handle
*rtnl
, struct nlmsghdr
*n
, pid_t peer
,
230 unsigned groups
, struct nlmsghdr
*answer
,
237 struct sockaddr_nl nladdr
;
239 .iov_base
= (void*) n
,
240 .iov_len
= n
->nlmsg_len
242 struct msghdr msg
= {
244 .msg_namelen
= sizeof(nladdr
),
250 memset(&nladdr
, 0, sizeof(nladdr
));
251 nladdr
.nl_family
= AF_NETLINK
;
252 nladdr
.nl_pid
= peer
;
253 nladdr
.nl_groups
= groups
;
255 n
->nlmsg_seq
= seq
= ++rtnl
->seq
;
258 n
->nlmsg_flags
|= NLM_F_ACK
;
260 status
= sendmsg(rtnl
->fd
, &msg
, 0);
263 perror("Cannot talk to rtnetlink");
267 memset(buf
,0,sizeof(buf
));
272 iov
.iov_len
= sizeof(buf
);
273 status
= recvmsg(rtnl
->fd
, &msg
, 0);
282 fprintf(stderr
, "EOF on netlink\n");
285 if (msg
.msg_namelen
!= sizeof(nladdr
)) {
286 fprintf(stderr
, "sender address length == %d\n", msg
.msg_namelen
);
289 for (h
= (struct nlmsghdr
*)buf
; status
>= sizeof(*h
); ) {
291 int len
= h
->nlmsg_len
;
292 int l
= len
- sizeof(*h
);
294 if (l
<0 || len
>status
) {
295 if (msg
.msg_flags
& MSG_TRUNC
) {
296 fprintf(stderr
, "Truncated message\n");
299 fprintf(stderr
, "!!!malformed message: len=%d\n", len
);
303 if (nladdr
.nl_pid
!= peer
||
304 h
->nlmsg_pid
!= rtnl
->local
.nl_pid
||
305 h
->nlmsg_seq
!= seq
) {
307 err
= junk(&nladdr
, h
, jarg
);
311 /* Don't forget to skip that message. */
312 status
-= NLMSG_ALIGN(len
);
313 h
= (struct nlmsghdr
*)((char*)h
+ NLMSG_ALIGN(len
));
317 if (h
->nlmsg_type
== NLMSG_ERROR
) {
318 struct nlmsgerr
*err
= (struct nlmsgerr
*)NLMSG_DATA(h
);
319 if (l
< sizeof(struct nlmsgerr
)) {
320 fprintf(stderr
, "ERROR truncated\n");
325 memcpy(answer
, h
, h
->nlmsg_len
);
328 perror("RTNETLINK answers");
333 memcpy(answer
, h
, h
->nlmsg_len
);
337 fprintf(stderr
, "Unexpected reply!!!\n");
339 status
-= NLMSG_ALIGN(len
);
340 h
= (struct nlmsghdr
*)((char*)h
+ NLMSG_ALIGN(len
));
342 if (msg
.msg_flags
& MSG_TRUNC
) {
343 fprintf(stderr
, "Message truncated\n");
347 fprintf(stderr
, "!!!Remnant of size %d\n", status
);
353 int rtnl_listen(struct rtnl_handle
*rtnl
,
354 rtnl_filter_t handler
,
359 struct sockaddr_nl nladdr
;
361 struct msghdr msg
= {
363 .msg_namelen
= sizeof(nladdr
),
369 memset(&nladdr
, 0, sizeof(nladdr
));
370 nladdr
.nl_family
= AF_NETLINK
;
372 nladdr
.nl_groups
= 0;
376 iov
.iov_len
= sizeof(buf
);
377 status
= recvmsg(rtnl
->fd
, &msg
, 0);
388 fprintf(stderr
, "EOF on netlink\n");
391 if (msg
.msg_namelen
!= sizeof(nladdr
)) {
392 fprintf(stderr
, "Sender address length == %d\n", msg
.msg_namelen
);
395 for (h
= (struct nlmsghdr
*)buf
; status
>= sizeof(*h
); ) {
397 int len
= h
->nlmsg_len
;
398 int l
= len
- sizeof(*h
);
400 if (l
<0 || len
>status
) {
401 if (msg
.msg_flags
& MSG_TRUNC
) {
402 fprintf(stderr
, "Truncated message\n");
405 fprintf(stderr
, "!!!malformed message: len=%d\n", len
);
409 err
= handler(&nladdr
, h
, jarg
);
411 fprintf(stderr
, "Handler returned %d\n", err
);
415 status
-= NLMSG_ALIGN(len
);
416 h
= (struct nlmsghdr
*)((char*)h
+ NLMSG_ALIGN(len
));
418 if (msg
.msg_flags
& MSG_TRUNC
) {
419 fprintf(stderr
, "Message truncated\n");
423 fprintf(stderr
, "!!!Remnant of size %d\n", status
);
429 int rtnl_from_file(FILE *rtnl
, rtnl_filter_t handler
,
433 struct sockaddr_nl nladdr
;
435 struct nlmsghdr
*h
= (void*)buf
;
437 memset(&nladdr
, 0, sizeof(nladdr
));
438 nladdr
.nl_family
= AF_NETLINK
;
440 nladdr
.nl_groups
= 0;
446 status
= fread(&buf
, 1, sizeof(*h
), rtnl
);
451 perror("rtnl_from_file: fread");
459 l
= len
- sizeof(*h
);
461 if (l
<0 || len
>sizeof(buf
)) {
462 fprintf(stderr
, "!!!malformed message: len=%d @%lu\n",
467 status
= fread(NLMSG_DATA(h
), 1, NLMSG_ALIGN(l
), rtnl
);
470 perror("rtnl_from_file: fread");
474 fprintf(stderr
, "rtnl-from_file: truncated message\n");
478 err
= handler(&nladdr
, h
, jarg
);
484 int addattr32(struct nlmsghdr
*n
, int maxlen
, int type
, __u32 data
)
486 int len
= RTA_LENGTH(4);
488 if (NLMSG_ALIGN(n
->nlmsg_len
) + len
> maxlen
) {
489 fprintf(stderr
,"addattr32: Error! max allowed bound %d exceeded\n",maxlen
);
493 rta
->rta_type
= type
;
495 memcpy(RTA_DATA(rta
), &data
, 4);
496 n
->nlmsg_len
= NLMSG_ALIGN(n
->nlmsg_len
) + len
;
500 int addattr_l(struct nlmsghdr
*n
, int maxlen
, int type
, const void *data
,
503 int len
= RTA_LENGTH(alen
);
506 if (NLMSG_ALIGN(n
->nlmsg_len
) + RTA_ALIGN(len
) > maxlen
) {
507 fprintf(stderr
, "addattr_l ERROR: message exceeded bound of %d\n",maxlen
);
511 rta
->rta_type
= type
;
513 memcpy(RTA_DATA(rta
), data
, alen
);
514 n
->nlmsg_len
= NLMSG_ALIGN(n
->nlmsg_len
) + RTA_ALIGN(len
);
518 int addraw_l(struct nlmsghdr
*n
, int maxlen
, const void *data
, int len
)
520 if (NLMSG_ALIGN(n
->nlmsg_len
) + NLMSG_ALIGN(len
) > maxlen
) {
521 fprintf(stderr
, "addraw_l ERROR: message exceeded bound of %d\n",maxlen
);
525 memcpy(NLMSG_TAIL(n
), data
, len
);
526 memset((void *) NLMSG_TAIL(n
) + len
, 0, NLMSG_ALIGN(len
) - len
);
527 n
->nlmsg_len
= NLMSG_ALIGN(n
->nlmsg_len
) + NLMSG_ALIGN(len
);
531 int rta_addattr32(struct rtattr
*rta
, int maxlen
, int type
, __u32 data
)
533 int len
= RTA_LENGTH(4);
534 struct rtattr
*subrta
;
536 if (RTA_ALIGN(rta
->rta_len
) + len
> maxlen
) {
537 fprintf(stderr
,"rta_addattr32: Error! max allowed bound %d exceeded\n",maxlen
);
540 subrta
= (struct rtattr
*)(((char*)rta
) + RTA_ALIGN(rta
->rta_len
));
541 subrta
->rta_type
= type
;
542 subrta
->rta_len
= len
;
543 memcpy(RTA_DATA(subrta
), &data
, 4);
544 rta
->rta_len
= NLMSG_ALIGN(rta
->rta_len
) + len
;
548 int rta_addattr_l(struct rtattr
*rta
, int maxlen
, int type
,
549 const void *data
, int alen
)
551 struct rtattr
*subrta
;
552 int len
= RTA_LENGTH(alen
);
554 if (RTA_ALIGN(rta
->rta_len
) + RTA_ALIGN(len
) > maxlen
) {
555 fprintf(stderr
,"rta_addattr_l: Error! max allowed bound %d exceeded\n",maxlen
);
558 subrta
= (struct rtattr
*)(((char*)rta
) + RTA_ALIGN(rta
->rta_len
));
559 subrta
->rta_type
= type
;
560 subrta
->rta_len
= len
;
561 memcpy(RTA_DATA(subrta
), data
, alen
);
562 rta
->rta_len
= NLMSG_ALIGN(rta
->rta_len
) + RTA_ALIGN(len
);
566 int parse_rtattr(struct rtattr
*tb
[], int max
, struct rtattr
*rta
, int len
)
568 memset(tb
, 0, sizeof(struct rtattr
*) * (max
+ 1));
569 while (RTA_OK(rta
, len
)) {
570 if (rta
->rta_type
<= max
)
571 tb
[rta
->rta_type
] = rta
;
572 rta
= RTA_NEXT(rta
,len
);
575 fprintf(stderr
, "!!!Deficit %d, rta_len=%d\n", len
, rta
->rta_len
);
579 int parse_rtattr_byindex(struct rtattr
*tb
[], int max
, struct rtattr
*rta
, int len
)
583 memset(tb
, 0, sizeof(struct rtattr
*) * max
);
584 while (RTA_OK(rta
, len
)) {
585 if (rta
->rta_type
<= max
&& i
< max
)
587 rta
= RTA_NEXT(rta
,len
);
590 fprintf(stderr
, "!!!Deficit %d, rta_len=%d\n", len
, rta
->rta_len
);