1dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat/*
2dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat * libnetlink.c	RTnetlink service routines.
3dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat *
4dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat *		This program is free software; you can redistribute it and/or
5dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat *		modify it under the terms of the GNU General Public License
6dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat *		as published by the Free Software Foundation; either version
7dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat *		2 of the License, or (at your option) any later version.
8dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat *
9dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat *
11dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat */
12dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
13dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <stdio.h>
14dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <stdlib.h>
15dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <unistd.h>
16dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <syslog.h>
17dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <fcntl.h>
18dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <net/if_arp.h>
19dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <sys/socket.h>
20dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <netinet/in.h>
21dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <string.h>
22dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <errno.h>
23dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <time.h>
24dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <sys/uio.h>
25dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
26dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include "libnetlink.h"
27dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
28dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatint rcvbuf = 1024 * 1024;
29dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
30dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatvoid rtnl_close(struct rtnl_handle *rth)
31dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
32dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (rth->fd >= 0) {
33dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		close(rth->fd);
34dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		rth->fd = -1;
35dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
36dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
37dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
38dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatint rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions,
39dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		      int protocol)
40dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
41dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	socklen_t addr_len;
42dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	int sndbuf = 32768;
43dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
44dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	memset(rth, 0, sizeof(*rth));
45dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
46dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	rth->fd = socket(AF_NETLINK, SOCK_RAW, protocol);
47dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (rth->fd < 0) {
48dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		perror("Cannot open netlink socket");
49dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
50dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
51dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
52dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (setsockopt(rth->fd,SOL_SOCKET,SO_SNDBUF,&sndbuf,sizeof(sndbuf)) < 0) {
53dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		perror("SO_SNDBUF");
54dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
55dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
56dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
57dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (setsockopt(rth->fd,SOL_SOCKET,SO_RCVBUF,&rcvbuf,sizeof(rcvbuf)) < 0) {
58dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		perror("SO_RCVBUF");
59dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
60dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
61dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
62dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	memset(&rth->local, 0, sizeof(rth->local));
63dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	rth->local.nl_family = AF_NETLINK;
64dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	rth->local.nl_groups = subscriptions;
65dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
66dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) {
67dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		perror("Cannot bind netlink socket");
68dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
69dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
70dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	addr_len = sizeof(rth->local);
71dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) {
72dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		perror("Cannot getsockname");
73dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
74dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
75dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (addr_len != sizeof(rth->local)) {
76dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(stderr, "Wrong address length %d\n", addr_len);
77dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
78dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
79dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (rth->local.nl_family != AF_NETLINK) {
80dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(stderr, "Wrong address family %d\n", rth->local.nl_family);
81dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
82dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
83dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	rth->seq = time(NULL);
84dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return 0;
85dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
86dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
87dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatint rtnl_open(struct rtnl_handle *rth, unsigned subscriptions)
88dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
89dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return rtnl_open_byproto(rth, subscriptions, NETLINK_ROUTE);
90dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
91dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
92dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatint rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type)
93dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
94dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct {
95dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		struct nlmsghdr nlh;
96dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		struct rtgenmsg g;
97dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	} req;
98dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
99dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	memset(&req, 0, sizeof(req));
100dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	req.nlh.nlmsg_len = sizeof(req);
101dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	req.nlh.nlmsg_type = type;
102dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
103dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	req.nlh.nlmsg_pid = 0;
104dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
105dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	req.g.rtgen_family = family;
106dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
107dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return send(rth->fd, (void*)&req, sizeof(req), 0);
108dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
109dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
110dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatint rtnl_send(struct rtnl_handle *rth, const char *buf, int len)
111dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
112dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return send(rth->fd, buf, len, 0);
113dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
114dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
115dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatint rtnl_send_check(struct rtnl_handle *rth, const char *buf, int len)
116dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
117dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct nlmsghdr *h;
118dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	int status;
119dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	char resp[1024];
120dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
121dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	status = send(rth->fd, buf, len, 0);
122dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (status < 0)
123dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return status;
124dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
125dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	/* Check for immediate errors */
126dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	status = recv(rth->fd, resp, sizeof(resp), MSG_DONTWAIT|MSG_PEEK);
127dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (status < 0) {
128dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (errno == EAGAIN)
129dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			return 0;
130dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
131dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
132dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
133dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	for (h = (struct nlmsghdr *)resp; NLMSG_OK(h, status);
134dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	     h = NLMSG_NEXT(h, status)) {
135dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (h->nlmsg_type == NLMSG_ERROR) {
136dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
137dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
138dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				fprintf(stderr, "ERROR truncated\n");
139dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			else
140dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				errno = -err->error;
141dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			return -1;
142dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
143dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
144dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
145dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return 0;
146dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
147dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
148dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatint rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
149dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
150dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct nlmsghdr nlh;
151dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct sockaddr_nl nladdr;
152dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct iovec iov[2] = {
153dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		{ .iov_base = &nlh, .iov_len = sizeof(nlh) },
154dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		{ .iov_base = req, .iov_len = len }
155dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	};
156dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct msghdr msg = {
157dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		.msg_name = &nladdr,
158dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		.msg_namelen = 	sizeof(nladdr),
159dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		.msg_iov = iov,
160dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		.msg_iovlen = 2,
161dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	};
162dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
163dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	memset(&nladdr, 0, sizeof(nladdr));
164dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	nladdr.nl_family = AF_NETLINK;
165dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
166dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	nlh.nlmsg_len = NLMSG_LENGTH(len);
167dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	nlh.nlmsg_type = type;
168dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
169dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	nlh.nlmsg_pid = 0;
170dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	nlh.nlmsg_seq = rth->dump = ++rth->seq;
171dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
172dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return sendmsg(rth->fd, &msg, 0);
173dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
174dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
175dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatint rtnl_dump_filter_l(struct rtnl_handle *rth,
176dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		       const struct rtnl_dump_filter_arg *arg)
177dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
178dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct sockaddr_nl nladdr;
179dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct iovec iov;
180dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct msghdr msg = {
181dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		.msg_name = &nladdr,
182dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		.msg_namelen = sizeof(nladdr),
183dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		.msg_iov = &iov,
184dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		.msg_iovlen = 1,
185dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	};
186dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	char buf[16384];
187dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
188dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	iov.iov_base = buf;
189dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	while (1) {
190dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		int status;
191dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		const struct rtnl_dump_filter_arg *a;
192dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
193dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		iov.iov_len = sizeof(buf);
194dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		status = recvmsg(rth->fd, &msg, 0);
195dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
196dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (status < 0) {
197dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (errno == EINTR || errno == EAGAIN)
198dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				continue;
199dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fprintf(stderr, "netlink receive error %s (%d)\n",
200dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				strerror(errno), errno);
201dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			return -1;
202dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
203dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
204dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (status == 0) {
205dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fprintf(stderr, "EOF on netlink\n");
206dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			return -1;
207dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
208dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
209dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		for (a = arg; a->filter; a++) {
210dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			struct nlmsghdr *h = (struct nlmsghdr*)buf;
211dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
212dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			while (NLMSG_OK(h, status)) {
213dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				int err;
214dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
215dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				if (nladdr.nl_pid != 0 ||
216dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				    h->nlmsg_pid != rth->local.nl_pid ||
217dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				    h->nlmsg_seq != rth->dump) {
218dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					if (a->junk) {
219dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat						err = a->junk(&nladdr, h,
220dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat							      a->arg2);
221dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat						if (err < 0)
222dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat							return err;
223dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					}
224dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					goto skip_it;
225dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				}
226dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
227dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				if (h->nlmsg_type == NLMSG_DONE)
228dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					return 0;
229dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				if (h->nlmsg_type == NLMSG_ERROR) {
230dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
231dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
232dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat						fprintf(stderr,
233dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat							"ERROR truncated\n");
234dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					} else {
235dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat						errno = -err->error;
236dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat						perror("RTNETLINK answers");
237dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					}
238dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					return -1;
239dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				}
240dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				err = a->filter(&nladdr, h, a->arg1);
241dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				if (err < 0)
242dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					return err;
243dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
244dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatskip_it:
245dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				h = NLMSG_NEXT(h, status);
246dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
247dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} while (0);
248dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (msg.msg_flags & MSG_TRUNC) {
249dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fprintf(stderr, "Message truncated\n");
250dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			continue;
251dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
252dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (status) {
253dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fprintf(stderr, "!!!Remnant of size %d\n", status);
254dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			exit(1);
255dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
256dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
257dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
258dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
259dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatint rtnl_dump_filter(struct rtnl_handle *rth,
260dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		     rtnl_filter_t filter,
261dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		     void *arg1,
262dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		     rtnl_filter_t junk,
263dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		     void *arg2)
264dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
265dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	const struct rtnl_dump_filter_arg a[2] = {
266dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		{ .filter = filter, .arg1 = arg1, .junk = junk, .arg2 = arg2 },
267dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		{ .filter = NULL,   .arg1 = NULL, .junk = NULL, .arg2 = NULL }
268dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	};
269dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
270dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return rtnl_dump_filter_l(rth, a);
271dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
272dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
273dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatint rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
274dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	      unsigned groups, struct nlmsghdr *answer,
275dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	      rtnl_filter_t junk,
276dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	      void *jarg)
277dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
278dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	int status;
279dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	unsigned seq;
280dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct nlmsghdr *h;
281dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct sockaddr_nl nladdr;
282dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct iovec iov = {
283dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		.iov_base = (void*) n,
284dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		.iov_len = n->nlmsg_len
285dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	};
286dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct msghdr msg = {
287dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		.msg_name = &nladdr,
288dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		.msg_namelen = sizeof(nladdr),
289dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		.msg_iov = &iov,
290dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		.msg_iovlen = 1,
291dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	};
292dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	char   buf[16384];
293dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
294dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	memset(&nladdr, 0, sizeof(nladdr));
295dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	nladdr.nl_family = AF_NETLINK;
296dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	nladdr.nl_pid = peer;
297dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	nladdr.nl_groups = groups;
298dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
299dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	n->nlmsg_seq = seq = ++rtnl->seq;
300dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
301dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (answer == NULL)
302dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		n->nlmsg_flags |= NLM_F_ACK;
303dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
304dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	status = sendmsg(rtnl->fd, &msg, 0);
305dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
306dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (status < 0) {
307dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		perror("Cannot talk to rtnetlink");
308dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
309dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
310dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
311dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	memset(buf,0,sizeof(buf));
312dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
313dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	iov.iov_base = buf;
314dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
315dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	while (1) {
316dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		iov.iov_len = sizeof(buf);
317dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		status = recvmsg(rtnl->fd, &msg, 0);
318dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
319dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (status < 0) {
320dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (errno == EINTR || errno == EAGAIN)
321dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				continue;
322dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fprintf(stderr, "netlink receive error %s (%d)\n",
323dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				strerror(errno), errno);
324dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			return -1;
325dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
326dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (status == 0) {
327dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fprintf(stderr, "EOF on netlink\n");
328dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			return -1;
329dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
330dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (msg.msg_namelen != sizeof(nladdr)) {
331dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fprintf(stderr, "sender address length == %d\n", msg.msg_namelen);
332dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			exit(1);
333dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
334dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
335dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			int err;
336dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			int len = h->nlmsg_len;
337dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			int l = len - sizeof(*h);
338dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
339dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (l<0 || len>status) {
340dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				if (msg.msg_flags & MSG_TRUNC) {
341dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					fprintf(stderr, "Truncated message\n");
342dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					return -1;
343dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				}
344dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				fprintf(stderr, "!!!malformed message: len=%d\n", len);
345dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				exit(1);
346dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
347dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
348dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (nladdr.nl_pid != peer ||
349dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			    h->nlmsg_pid != rtnl->local.nl_pid ||
350dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			    h->nlmsg_seq != seq) {
351dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				if (junk) {
352dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					err = junk(&nladdr, h, jarg);
353dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					if (err < 0)
354dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat						return err;
355dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				}
356dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				/* Don't forget to skip that message. */
357dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				status -= NLMSG_ALIGN(len);
358dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
359dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				continue;
360dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
361dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
362dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (h->nlmsg_type == NLMSG_ERROR) {
363dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
364dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				if (l < sizeof(struct nlmsgerr)) {
365dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					fprintf(stderr, "ERROR truncated\n");
366dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				} else {
367dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					errno = -err->error;
368dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					if (errno == 0) {
369dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat						if (answer)
370dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat							memcpy(answer, h, h->nlmsg_len);
371dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat						return 0;
372dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					}
373dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					perror("RTNETLINK answers");
374dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				}
375dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				return -1;
376dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
377dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (answer) {
378dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				memcpy(answer, h, h->nlmsg_len);
379dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				return 0;
380dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
381dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
382dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fprintf(stderr, "Unexpected reply!!!\n");
383dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
384dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			status -= NLMSG_ALIGN(len);
385dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
386dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
387dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (msg.msg_flags & MSG_TRUNC) {
388dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fprintf(stderr, "Message truncated\n");
389dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			continue;
390dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
391dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (status) {
392dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fprintf(stderr, "!!!Remnant of size %d\n", status);
393dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			exit(1);
394dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
395dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
396dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
397dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
398dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatint rtnl_listen(struct rtnl_handle *rtnl,
399dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		rtnl_filter_t handler,
400dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		void *jarg)
401dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
402dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	int status;
403dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct nlmsghdr *h;
404dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct sockaddr_nl nladdr;
405dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct iovec iov;
406dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct msghdr msg = {
407dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		.msg_name = &nladdr,
408dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		.msg_namelen = sizeof(nladdr),
409dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		.msg_iov = &iov,
410dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		.msg_iovlen = 1,
411dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	};
412dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	char   buf[8192];
413dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
414dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	memset(&nladdr, 0, sizeof(nladdr));
415dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	nladdr.nl_family = AF_NETLINK;
416dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	nladdr.nl_pid = 0;
417dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	nladdr.nl_groups = 0;
418dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
419dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	iov.iov_base = buf;
420dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	while (1) {
421dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		iov.iov_len = sizeof(buf);
422dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		status = recvmsg(rtnl->fd, &msg, 0);
423dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
424dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (status < 0) {
425dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (errno == EINTR || errno == EAGAIN)
426dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				continue;
427dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fprintf(stderr, "netlink receive error %s (%d)\n",
428dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				strerror(errno), errno);
429dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (errno == ENOBUFS)
430dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				continue;
431dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			return -1;
432dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
433dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (status == 0) {
434dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fprintf(stderr, "EOF on netlink\n");
435dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			return -1;
436dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
437dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (msg.msg_namelen != sizeof(nladdr)) {
438dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fprintf(stderr, "Sender address length == %d\n", msg.msg_namelen);
439dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			exit(1);
440dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
441dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
442dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			int err;
443dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			int len = h->nlmsg_len;
444dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			int l = len - sizeof(*h);
445dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
446dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (l<0 || len>status) {
447dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				if (msg.msg_flags & MSG_TRUNC) {
448dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					fprintf(stderr, "Truncated message\n");
449dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					return -1;
450dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				}
451dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				fprintf(stderr, "!!!malformed message: len=%d\n", len);
452dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				exit(1);
453dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
454dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
455dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			err = handler(&nladdr, h, jarg);
456dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (err < 0)
457dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				return err;
458dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
459dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			status -= NLMSG_ALIGN(len);
460dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
461dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
462dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (msg.msg_flags & MSG_TRUNC) {
463dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fprintf(stderr, "Message truncated\n");
464dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			continue;
465dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
466dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (status) {
467dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fprintf(stderr, "!!!Remnant of size %d\n", status);
468dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			exit(1);
469dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
470dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
471dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
472dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
473dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatint rtnl_from_file(FILE *rtnl, rtnl_filter_t handler,
474dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		   void *jarg)
475dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
476dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	int status;
477dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct sockaddr_nl nladdr;
478dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	char   buf[8192];
479dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct nlmsghdr *h = (void*)buf;
480dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
481dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	memset(&nladdr, 0, sizeof(nladdr));
482dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	nladdr.nl_family = AF_NETLINK;
483dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	nladdr.nl_pid = 0;
484dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	nladdr.nl_groups = 0;
485dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
486dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	while (1) {
487dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		int err, len, type;
488dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		int l;
489dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
490dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		status = fread(&buf, 1, sizeof(*h), rtnl);
491dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
492dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (status < 0) {
493dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (errno == EINTR)
494dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				continue;
495dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			perror("rtnl_from_file: fread");
496dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			return -1;
497dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
498dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (status == 0)
499dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			return 0;
500dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
501dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		len = h->nlmsg_len;
502dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		type= h->nlmsg_type;
503dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		l = len - sizeof(*h);
504dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
505dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (l<0 || len>sizeof(buf)) {
506dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fprintf(stderr, "!!!malformed message: len=%d @%lu\n",
507dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				len, ftell(rtnl));
508dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			return -1;
509dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
510dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
511dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl);
512dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
513dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (status < 0) {
514dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			perror("rtnl_from_file: fread");
515dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			return -1;
516dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
517dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (status < l) {
518dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fprintf(stderr, "rtnl-from_file: truncated message\n");
519dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			return -1;
520dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
521dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
522dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		err = handler(&nladdr, h, jarg);
523dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (err < 0)
524dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			return err;
525dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
526dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
527dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
528dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatint addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data)
529dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
530dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	int len = RTA_LENGTH(4);
531dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct rtattr *rta;
532dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) {
533dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(stderr,"addattr32: Error! max allowed bound %d exceeded\n",maxlen);
534dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
535dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
536dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	rta = NLMSG_TAIL(n);
537dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	rta->rta_type = type;
538dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	rta->rta_len = len;
539dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	memcpy(RTA_DATA(rta), &data, 4);
540dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
541dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return 0;
542dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
543dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
544dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatint addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
545dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	      int alen)
546dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
547dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	int len = RTA_LENGTH(alen);
548dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct rtattr *rta;
549dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
550dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) {
551dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(stderr, "addattr_l ERROR: message exceeded bound of %d\n",maxlen);
552dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
553dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
554dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	rta = NLMSG_TAIL(n);
555dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	rta->rta_type = type;
556dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	rta->rta_len = len;
557dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	memcpy(RTA_DATA(rta), data, alen);
558dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
559dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return 0;
560dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
561dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
562dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatint addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len)
563dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
564dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len) > maxlen) {
565dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(stderr, "addraw_l ERROR: message exceeded bound of %d\n",maxlen);
566dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
567dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
568dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
569dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	memcpy(NLMSG_TAIL(n), data, len);
570dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	memset((void *) NLMSG_TAIL(n) + len, 0, NLMSG_ALIGN(len) - len);
571dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len);
572dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return 0;
573dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
574dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
575dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstruct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type)
576dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
577dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct rtattr *nest = NLMSG_TAIL(n);
578dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
579dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	addattr_l(n, maxlen, type, NULL, 0);
580dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return nest;
581dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
582dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
583dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatint addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest)
584dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
585dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	nest->rta_len = (void *)NLMSG_TAIL(n) - (void *)nest;
586dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return n->nlmsg_len;
587dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
588dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
589dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstruct rtattr *addattr_nest_compat(struct nlmsghdr *n, int maxlen, int type,
590dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				   const void *data, int len)
591dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
592dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct rtattr *start = NLMSG_TAIL(n);
593dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
594dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	addattr_l(n, maxlen, type, data, len);
595dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	addattr_nest(n, maxlen, type);
596dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return start;
597dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
598dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
599dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatint addattr_nest_compat_end(struct nlmsghdr *n, struct rtattr *start)
600dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
601dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct rtattr *nest = (void *)start + NLMSG_ALIGN(start->rta_len);
602dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
603dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	start->rta_len = (void *)NLMSG_TAIL(n) - (void *)start;
604dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	addattr_nest_end(n, nest);
605dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return n->nlmsg_len;
606dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
607dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
608dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatint rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data)
609dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
610dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	int len = RTA_LENGTH(4);
611dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct rtattr *subrta;
612dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
613dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
614dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(stderr,"rta_addattr32: Error! max allowed bound %d exceeded\n",maxlen);
615dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
616dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
617dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
618dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	subrta->rta_type = type;
619dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	subrta->rta_len = len;
620dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	memcpy(RTA_DATA(subrta), &data, 4);
621dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
622dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return 0;
623dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
624dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
625dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatint rta_addattr_l(struct rtattr *rta, int maxlen, int type,
626dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		  const void *data, int alen)
627dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
628dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct rtattr *subrta;
629dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	int len = RTA_LENGTH(alen);
630dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
631dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (RTA_ALIGN(rta->rta_len) + RTA_ALIGN(len) > maxlen) {
632dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(stderr,"rta_addattr_l: Error! max allowed bound %d exceeded\n",maxlen);
633dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
634dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
635dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
636dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	subrta->rta_type = type;
637dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	subrta->rta_len = len;
638dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	memcpy(RTA_DATA(subrta), data, alen);
639dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	rta->rta_len = NLMSG_ALIGN(rta->rta_len) + RTA_ALIGN(len);
640dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return 0;
641dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
642dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
643dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatint parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
644dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
645dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
646dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	while (RTA_OK(rta, len)) {
6471a441f49ec87ef74b978d7ae17da2a9b2ca6e811Dmitry Shmidt		if ((rta->rta_type <= max) && (!tb[rta->rta_type]))
648dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			tb[rta->rta_type] = rta;
649dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		rta = RTA_NEXT(rta,len);
650dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
651dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (len)
652dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
653dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return 0;
654dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
655dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
656dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatint parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int len)
657dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
658dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	int i = 0;
659dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
660dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	memset(tb, 0, sizeof(struct rtattr *) * max);
661dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	while (RTA_OK(rta, len)) {
662dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (rta->rta_type <= max && i < max)
663dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			tb[i++] = rta;
664dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		rta = RTA_NEXT(rta,len);
665dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
666dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (len)
667dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
668dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return i;
669dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
670dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
671dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatint __parse_rtattr_nested_compat(struct rtattr *tb[], int max, struct rtattr *rta,
672dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			         int len)
673dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
674dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (RTA_PAYLOAD(rta) < len)
675dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
676dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (RTA_PAYLOAD(rta) >= RTA_ALIGN(len) + sizeof(struct rtattr)) {
677dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		rta = RTA_DATA(rta) + RTA_ALIGN(len);
678dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return parse_rtattr_nested(tb, max, rta);
679dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
680dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
681dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return 0;
682dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
683