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>
13 #include <sys/socket.h>
21 #include "libnetlink.h"
24 void rtnl_close(struct rtnl_handle *rth)
29 int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions)
33 memset(rth, 0, sizeof(rth));
35 rth->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
37 perror_msg("Cannot open netlink socket");
41 memset(&rth->local, 0, sizeof(rth->local));
42 rth->local.nl_family = AF_NETLINK;
43 rth->local.nl_groups = subscriptions;
45 if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) {
46 perror_msg("Cannot bind netlink socket");
49 addr_len = sizeof(rth->local);
50 if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) {
51 perror_msg("Cannot getsockname");
54 if (addr_len != sizeof(rth->local)) {
55 error_msg("Wrong address length %d", addr_len);
58 if (rth->local.nl_family != AF_NETLINK) {
59 error_msg("Wrong address family %d", rth->local.nl_family);
62 rth->seq = time(NULL);
66 int rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type)
72 struct sockaddr_nl nladdr;
74 memset(&nladdr, 0, sizeof(nladdr));
75 nladdr.nl_family = AF_NETLINK;
77 req.nlh.nlmsg_len = sizeof(req);
78 req.nlh.nlmsg_type = type;
79 req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
80 req.nlh.nlmsg_pid = 0;
81 req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
82 req.g.rtgen_family = family;
84 return sendto(rth->fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr));
87 int rtnl_send(struct rtnl_handle *rth, char *buf, int len)
89 struct sockaddr_nl nladdr;
91 memset(&nladdr, 0, sizeof(nladdr));
92 nladdr.nl_family = AF_NETLINK;
94 return sendto(rth->fd, buf, len, 0, (struct sockaddr*)&nladdr, sizeof(nladdr));
97 int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
100 struct sockaddr_nl nladdr;
101 struct iovec iov[2] = { { &nlh, sizeof(nlh) }, { req, len } };
102 struct msghdr msg = {
103 (void*)&nladdr, sizeof(nladdr),
109 memset(&nladdr, 0, sizeof(nladdr));
110 nladdr.nl_family = AF_NETLINK;
112 nlh.nlmsg_len = NLMSG_LENGTH(len);
113 nlh.nlmsg_type = type;
114 nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
116 nlh.nlmsg_seq = rth->dump = ++rth->seq;
118 return sendmsg(rth->fd, &msg, 0);
121 int rtnl_dump_filter(struct rtnl_handle *rth,
122 int (*filter)(struct sockaddr_nl *, struct nlmsghdr *n, void *),
124 int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
128 struct sockaddr_nl nladdr;
129 struct iovec iov = { buf, sizeof(buf) };
135 struct msghdr msg = {
136 (void*)&nladdr, sizeof(nladdr),
142 status = recvmsg(rth->fd, &msg, 0);
147 perror_msg("OVERRUN");
151 error_msg("EOF on netlink");
154 if (msg.msg_namelen != sizeof(nladdr)) {
155 error_msg_and_die("sender address length == %d", msg.msg_namelen);
158 h = (struct nlmsghdr*)buf;
159 while (NLMSG_OK(h, status)) {
162 if (h->nlmsg_pid != rth->local.nl_pid ||
163 h->nlmsg_seq != rth->dump) {
165 err = junk(&nladdr, h, arg2);
173 if (h->nlmsg_type == NLMSG_DONE) {
176 if (h->nlmsg_type == NLMSG_ERROR) {
177 struct nlmsgerr *l_err = (struct nlmsgerr*)NLMSG_DATA(h);
178 if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
179 error_msg("ERROR truncated");
181 errno = -l_err->error;
182 perror_msg("RTNETLINK answers");
186 err = filter(&nladdr, h, arg1);
192 h = NLMSG_NEXT(h, status);
194 if (msg.msg_flags & MSG_TRUNC) {
195 error_msg("Message truncated");
199 error_msg_and_die("!!!Remnant of size %d", status);
204 int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
205 unsigned groups, struct nlmsghdr *answer,
206 int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
212 struct sockaddr_nl nladdr;
213 struct iovec iov = { (void*)n, n->nlmsg_len };
215 struct msghdr msg = {
216 (void*)&nladdr, sizeof(nladdr),
222 memset(&nladdr, 0, sizeof(nladdr));
223 nladdr.nl_family = AF_NETLINK;
224 nladdr.nl_pid = peer;
225 nladdr.nl_groups = groups;
227 n->nlmsg_seq = seq = ++rtnl->seq;
228 if (answer == NULL) {
229 n->nlmsg_flags |= NLM_F_ACK;
231 status = sendmsg(rtnl->fd, &msg, 0);
234 perror_msg("Cannot talk to rtnetlink");
241 iov.iov_len = sizeof(buf);
242 status = recvmsg(rtnl->fd, &msg, 0);
245 if (errno == EINTR) {
248 perror_msg("OVERRUN");
252 error_msg("EOF on netlink");
255 if (msg.msg_namelen != sizeof(nladdr)) {
256 error_msg_and_die("sender address length == %d", msg.msg_namelen);
258 for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
260 int len = h->nlmsg_len;
261 int l = len - sizeof(*h);
263 if (l<0 || len>status) {
264 if (msg.msg_flags & MSG_TRUNC) {
265 error_msg("Truncated message");
268 error_msg_and_die("!!!malformed message: len=%d", len);
271 if (h->nlmsg_pid != rtnl->local.nl_pid ||
272 h->nlmsg_seq != seq) {
274 l_err = junk(&nladdr, h, jarg);
282 if (h->nlmsg_type == NLMSG_ERROR) {
283 struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
284 if (l < sizeof(struct nlmsgerr)) {
285 error_msg("ERROR truncated");
290 memcpy(answer, h, h->nlmsg_len);
294 perror_msg("RTNETLINK answers");
299 memcpy(answer, h, h->nlmsg_len);
303 error_msg("Unexpected reply!!!");
305 status -= NLMSG_ALIGN(len);
306 h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
308 if (msg.msg_flags & MSG_TRUNC) {
309 error_msg("Message truncated");
313 error_msg_and_die("!!!Remnant of size %d", status);
318 int rtnl_listen(struct rtnl_handle *rtnl,
319 int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
324 struct sockaddr_nl nladdr;
327 struct msghdr msg = {
328 (void*)&nladdr, sizeof(nladdr),
334 memset(&nladdr, 0, sizeof(nladdr));
335 nladdr.nl_family = AF_NETLINK;
337 nladdr.nl_groups = 0;
343 iov.iov_len = sizeof(buf);
344 status = recvmsg(rtnl->fd, &msg, 0);
349 perror_msg("OVERRUN");
353 error_msg("EOF on netlink");
356 if (msg.msg_namelen != sizeof(nladdr)) {
357 error_msg_and_die("Sender address length == %d", msg.msg_namelen);
359 for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
361 int len = h->nlmsg_len;
362 int l = len - sizeof(*h);
364 if (l<0 || len>status) {
365 if (msg.msg_flags & MSG_TRUNC) {
366 error_msg("Truncated message");
369 error_msg_and_die("!!!malformed message: len=%d", len);
372 err = handler(&nladdr, h, jarg);
377 status -= NLMSG_ALIGN(len);
378 h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
380 if (msg.msg_flags & MSG_TRUNC) {
381 error_msg("Message truncated");
385 error_msg_and_die("!!!Remnant of size %d", status);
390 int rtnl_from_file(FILE *rtnl,
391 int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
395 struct sockaddr_nl nladdr;
397 struct nlmsghdr *h = (void*)buf;
399 memset(&nladdr, 0, sizeof(nladdr));
400 nladdr.nl_family = AF_NETLINK;
402 nladdr.nl_groups = 0;
408 status = fread(&buf, 1, sizeof(*h), rtnl);
413 perror_msg("rtnl_from_file: fread");
421 l = len - sizeof(*h);
423 if (l<0 || len>sizeof(buf)) {
424 error_msg("!!!malformed message: len=%d @%lu",
429 status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl);
432 perror_msg("rtnl_from_file: fread");
436 error_msg("rtnl-from_file: truncated message");
440 err = handler(&nladdr, h, jarg);
446 int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data)
448 int len = RTA_LENGTH(4);
450 if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen)
452 rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len));
453 rta->rta_type = type;
455 memcpy(RTA_DATA(rta), &data, 4);
456 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
460 int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
462 int len = RTA_LENGTH(alen);
465 if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen)
467 rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len));
468 rta->rta_type = type;
470 memcpy(RTA_DATA(rta), data, alen);
471 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
475 int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data)
477 int len = RTA_LENGTH(4);
478 struct rtattr *subrta;
480 if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
483 subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
484 subrta->rta_type = type;
485 subrta->rta_len = len;
486 memcpy(RTA_DATA(subrta), &data, 4);
487 rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
491 int rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data, int alen)
493 struct rtattr *subrta;
494 int len = RTA_LENGTH(alen);
496 if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
499 subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
500 subrta->rta_type = type;
501 subrta->rta_len = len;
502 memcpy(RTA_DATA(subrta), data, alen);
503 rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
508 int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
510 while (RTA_OK(rta, len)) {
511 if (rta->rta_type <= max) {
512 tb[rta->rta_type] = rta;
514 rta = RTA_NEXT(rta,len);
517 error_msg("!!!Deficit %d, rta_len=%d", len, rta->rta_len);