#include "libnetlink.h"
+int rcvbuf = 1024 * 1024;
+
void rtnl_close(struct rtnl_handle *rth)
{
if (rth->fd >= 0) {
{
socklen_t addr_len;
int sndbuf = 32768;
- int rcvbuf = 32768;
memset(rth, 0, sizeof(*rth));
struct nlmsghdr nlh;
struct rtgenmsg g;
} req;
- struct sockaddr_nl nladdr;
-
- memset(&nladdr, 0, sizeof(nladdr));
- nladdr.nl_family = AF_NETLINK;
memset(&req, 0, sizeof(req));
req.nlh.nlmsg_len = sizeof(req);
req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
req.g.rtgen_family = family;
- return sendto(rth->fd, (void*)&req, sizeof(req), 0,
- (struct sockaddr*)&nladdr, sizeof(nladdr));
+ return send(rth->fd, (void*)&req, sizeof(req), 0);
}
-int rtnl_send(struct rtnl_handle *rth, const char *buf, int len)
+int rtnl_send(struct rtnl_handle *rth, const void *buf, int len)
+{
+ return send(rth->fd, buf, len, 0);
+}
+
+int rtnl_send_check(struct rtnl_handle *rth, const void *buf, int len)
{
- struct sockaddr_nl nladdr;
struct nlmsghdr *h;
int status;
char resp[1024];
- memset(&nladdr, 0, sizeof(nladdr));
- nladdr.nl_family = AF_NETLINK;
-
- status = sendto(rth->fd, buf, len, 0,
- (struct sockaddr*)&nladdr, sizeof(nladdr));
+ status = send(rth->fd, buf, len, 0);
if (status < 0)
return status;
- /* Check for errors */
- status = recv(rth->fd, resp, sizeof(resp), MSG_DONTWAIT);
+ /* Check for immediate errors */
+ status = recv(rth->fd, resp, sizeof(resp), MSG_DONTWAIT|MSG_PEEK);
if (status < 0) {
if (errno == EAGAIN)
return 0;
fprintf(stderr, "ERROR truncated\n");
else
errno = -err->error;
+ return -1;
}
- return -1;
}
return 0;
int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
{
struct nlmsghdr nlh;
- struct sockaddr_nl nladdr;
+ struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
struct iovec iov[2] = {
{ .iov_base = &nlh, .iov_len = sizeof(nlh) },
{ .iov_base = req, .iov_len = len }
.msg_iovlen = 2,
};
- memset(&nladdr, 0, sizeof(nladdr));
- nladdr.nl_family = AF_NETLINK;
-
nlh.nlmsg_len = NLMSG_LENGTH(len);
nlh.nlmsg_type = type;
nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
return sendmsg(rth->fd, &msg, 0);
}
-int rtnl_dump_filter(struct rtnl_handle *rth,
- rtnl_filter_t filter,
- void *arg1,
- rtnl_filter_t junk,
- void *arg2)
+int rtnl_dump_filter_l(struct rtnl_handle *rth,
+ const struct rtnl_dump_filter_arg *arg)
{
struct sockaddr_nl nladdr;
struct iovec iov;
iov.iov_base = buf;
while (1) {
int status;
- struct nlmsghdr *h;
+ const struct rtnl_dump_filter_arg *a;
+ int found_done = 0;
+ int msglen = 0;
iov.iov_len = sizeof(buf);
status = recvmsg(rth->fd, &msg, 0);
return -1;
}
- h = (struct nlmsghdr*)buf;
- while (NLMSG_OK(h, status)) {
- int err;
-
- if (nladdr.nl_pid != 0 ||
- h->nlmsg_pid != rth->local.nl_pid ||
- h->nlmsg_seq != rth->dump) {
- if (junk) {
- err = junk(&nladdr, h, arg2);
- if (err < 0)
- return err;
+ for (a = arg; a->filter; a++) {
+ struct nlmsghdr *h = (struct nlmsghdr*)buf;
+ msglen = status;
+
+ while (NLMSG_OK(h, msglen)) {
+ int err;
+
+ if (nladdr.nl_pid != 0 ||
+ h->nlmsg_pid != rth->local.nl_pid ||
+ h->nlmsg_seq != rth->dump) {
+ if (a->junk) {
+ err = a->junk(&nladdr, h,
+ a->arg2);
+ if (err < 0)
+ return err;
+ }
+ goto skip_it;
}
- goto skip_it;
- }
- if (h->nlmsg_type == NLMSG_DONE)
- return 0;
- if (h->nlmsg_type == NLMSG_ERROR) {
- struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
- if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
- fprintf(stderr, "ERROR truncated\n");
- } else {
- errno = -err->error;
- perror("RTNETLINK answers");
+ if (h->nlmsg_type == NLMSG_DONE) {
+ found_done = 1;
+ break; /* process next filter */
}
- return -1;
- }
- err = filter(&nladdr, h, arg1);
- if (err < 0)
- return err;
+ if (h->nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
+ if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
+ fprintf(stderr,
+ "ERROR truncated\n");
+ } else {
+ errno = -err->error;
+ perror("RTNETLINK answers");
+ }
+ return -1;
+ }
+ err = a->filter(&nladdr, h, a->arg1);
+ if (err < 0)
+ return err;
skip_it:
- h = NLMSG_NEXT(h, status);
+ h = NLMSG_NEXT(h, msglen);
+ }
}
+
+ if (found_done)
+ return 0;
+
if (msg.msg_flags & MSG_TRUNC) {
fprintf(stderr, "Message truncated\n");
continue;
}
- if (status) {
- fprintf(stderr, "!!!Remnant of size %d\n", status);
+ if (msglen) {
+ fprintf(stderr, "!!!Remnant of size %d\n", msglen);
exit(1);
}
}
}
+int rtnl_dump_filter(struct rtnl_handle *rth,
+ rtnl_filter_t filter,
+ void *arg1,
+ rtnl_filter_t junk,
+ void *arg2)
+{
+ const struct rtnl_dump_filter_arg a[2] = {
+ { .filter = filter, .arg1 = arg1, .junk = junk, .arg2 = arg2 },
+ { .filter = NULL, .arg1 = NULL, .junk = NULL, .arg2 = NULL }
+ };
+
+ return rtnl_dump_filter_l(rth, a);
+}
+
int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
unsigned groups, struct nlmsghdr *answer,
rtnl_filter_t junk,
continue;
fprintf(stderr, "netlink receive error %s (%d)\n",
strerror(errno), errno);
+ if (errno == ENOBUFS)
+ continue;
return -1;
}
if (status == 0) {
nladdr.nl_groups = 0;
while (1) {
- int err, len, type;
+ int err, len;
int l;
status = fread(&buf, 1, sizeof(*h), rtnl);
return 0;
len = h->nlmsg_len;
- type= h->nlmsg_type;
l = len - sizeof(*h);
if (l<0 || len>sizeof(buf)) {
{
memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
while (RTA_OK(rta, len)) {
- if (rta->rta_type <= max)
+ if ((rta->rta_type <= max) && (!tb[rta->rta_type]))
tb[rta->rta_type] = rta;
rta = RTA_NEXT(rta,len);
}