libnetlink.c revision b16621cafd599499fdbaa79236266d72a53106bb
1aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger/*
2aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger * libnetlink.c	RTnetlink service routines.
3aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger *
4aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger *		This program is free software; you can redistribute it and/or
5aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger *		modify it under the terms of the GNU General Public License
6aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger *		as published by the Free Software Foundation; either version
7aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger *		2 of the License, or (at your option) any later version.
8aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger *
9aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger *
11aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger */
12aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
13aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger#include <stdio.h>
14aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger#include <stdlib.h>
15aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger#include <unistd.h>
16aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger#include <syslog.h>
17aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger#include <fcntl.h>
18aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger#include <net/if_arp.h>
19aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger#include <sys/socket.h>
20aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger#include <netinet/in.h>
21aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger#include <string.h>
22aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger#include <errno.h>
23aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger#include <time.h>
24aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger#include <sys/uio.h>
25aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
26aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger#include "libnetlink.h"
27aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
28aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemmingervoid rtnl_close(struct rtnl_handle *rth)
29aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger{
303bfa73ff99291d872f6d0e0284ee416e880088b6Stephen Hemminger	if (rth->fd >= 0) {
313bfa73ff99291d872f6d0e0284ee416e880088b6Stephen Hemminger		close(rth->fd);
323bfa73ff99291d872f6d0e0284ee416e880088b6Stephen Hemminger		rth->fd = -1;
333bfa73ff99291d872f6d0e0284ee416e880088b6Stephen Hemminger	}
34aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger}
35aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
368ed63ab1f1283b2c63355fb7c1e80abead4b9399shemmingerint rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions,
378ed63ab1f1283b2c63355fb7c1e80abead4b9399shemminger		      int protocol)
38aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger{
39f332d169246447bd5e258ac03d5ee840a70adb1eshemminger	socklen_t addr_len;
40007d3a3e9f0747039a772198293fd7f45a025f80osdl.net!shemminger	int sndbuf = 32768;
41007d3a3e9f0747039a772198293fd7f45a025f80osdl.net!shemminger	int rcvbuf = 32768;
42aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
43b16621cafd599499fdbaa79236266d72a53106bbStephen Hemminger	memset(rth, 0, sizeof(*rth));
44aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
45c7699875bee00fbcd057fc62c30d6560b044e007net[shemminger]!shemminger	rth->fd = socket(AF_NETLINK, SOCK_RAW, protocol);
46aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	if (rth->fd < 0) {
47aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		perror("Cannot open netlink socket");
48aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		return -1;
49aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	}
50aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
51007d3a3e9f0747039a772198293fd7f45a025f80osdl.net!shemminger	if (setsockopt(rth->fd,SOL_SOCKET,SO_SNDBUF,&sndbuf,sizeof(sndbuf)) < 0) {
52007d3a3e9f0747039a772198293fd7f45a025f80osdl.net!shemminger		perror("SO_SNDBUF");
53007d3a3e9f0747039a772198293fd7f45a025f80osdl.net!shemminger		return -1;
54007d3a3e9f0747039a772198293fd7f45a025f80osdl.net!shemminger	}
55007d3a3e9f0747039a772198293fd7f45a025f80osdl.net!shemminger
56007d3a3e9f0747039a772198293fd7f45a025f80osdl.net!shemminger	if (setsockopt(rth->fd,SOL_SOCKET,SO_RCVBUF,&rcvbuf,sizeof(rcvbuf)) < 0) {
57007d3a3e9f0747039a772198293fd7f45a025f80osdl.net!shemminger		perror("SO_RCVBUF");
58007d3a3e9f0747039a772198293fd7f45a025f80osdl.net!shemminger		return -1;
59007d3a3e9f0747039a772198293fd7f45a025f80osdl.net!shemminger	}
60007d3a3e9f0747039a772198293fd7f45a025f80osdl.net!shemminger
61aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	memset(&rth->local, 0, sizeof(rth->local));
62aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	rth->local.nl_family = AF_NETLINK;
63aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	rth->local.nl_groups = subscriptions;
64aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
65aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) {
66aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		perror("Cannot bind netlink socket");
67aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		return -1;
68aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	}
69aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	addr_len = sizeof(rth->local);
70aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) {
71aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		perror("Cannot getsockname");
72aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		return -1;
73aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	}
74aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	if (addr_len != sizeof(rth->local)) {
75aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		fprintf(stderr, "Wrong address length %d\n", addr_len);
76aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		return -1;
77aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	}
78aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	if (rth->local.nl_family != AF_NETLINK) {
79aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		fprintf(stderr, "Wrong address family %d\n", rth->local.nl_family);
80aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		return -1;
81aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	}
82aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	rth->seq = time(NULL);
83aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	return 0;
84aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger}
85aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
86c7699875bee00fbcd057fc62c30d6560b044e007net[shemminger]!shemmingerint rtnl_open(struct rtnl_handle *rth, unsigned subscriptions)
87c7699875bee00fbcd057fc62c30d6560b044e007net[shemminger]!shemminger{
88c7699875bee00fbcd057fc62c30d6560b044e007net[shemminger]!shemminger	return rtnl_open_byproto(rth, subscriptions, NETLINK_ROUTE);
89c7699875bee00fbcd057fc62c30d6560b044e007net[shemminger]!shemminger}
90c7699875bee00fbcd057fc62c30d6560b044e007net[shemminger]!shemminger
91aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemmingerint rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type)
92aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger{
93aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct {
94aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		struct nlmsghdr nlh;
95aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		struct rtgenmsg g;
96aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	} req;
97aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct sockaddr_nl nladdr;
98aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
99aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	memset(&nladdr, 0, sizeof(nladdr));
100aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	nladdr.nl_family = AF_NETLINK;
101aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
1028ed63ab1f1283b2c63355fb7c1e80abead4b9399shemminger	memset(&req, 0, sizeof(req));
103aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	req.nlh.nlmsg_len = sizeof(req);
104aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	req.nlh.nlmsg_type = type;
105aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
106aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	req.nlh.nlmsg_pid = 0;
107aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
108aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	req.g.rtgen_family = family;
109aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
1108ed63ab1f1283b2c63355fb7c1e80abead4b9399shemminger	return sendto(rth->fd, (void*)&req, sizeof(req), 0,
1118ed63ab1f1283b2c63355fb7c1e80abead4b9399shemminger		      (struct sockaddr*)&nladdr, sizeof(nladdr));
112aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger}
113aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
1146dc9f016347441fbf94cf851c054b0f45ba32c1cosdl.net!shemmingerint rtnl_send(struct rtnl_handle *rth, const char *buf, int len)
115aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger{
116aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct sockaddr_nl nladdr;
117aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
118aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	memset(&nladdr, 0, sizeof(nladdr));
119aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	nladdr.nl_family = AF_NETLINK;
120aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
121aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	return sendto(rth->fd, buf, len, 0, (struct sockaddr*)&nladdr, sizeof(nladdr));
122aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger}
123aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
124aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemmingerint rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
125aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger{
126aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct nlmsghdr nlh;
127aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct sockaddr_nl nladdr;
1288ed63ab1f1283b2c63355fb7c1e80abead4b9399shemminger	struct iovec iov[2] = {
1298ed63ab1f1283b2c63355fb7c1e80abead4b9399shemminger		{ .iov_base = &nlh, .iov_len = sizeof(nlh) },
1308ed63ab1f1283b2c63355fb7c1e80abead4b9399shemminger		{ .iov_base = req, .iov_len = len }
1318ed63ab1f1283b2c63355fb7c1e80abead4b9399shemminger	};
132aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct msghdr msg = {
1338ed63ab1f1283b2c63355fb7c1e80abead4b9399shemminger		.msg_name = &nladdr,
1348ed63ab1f1283b2c63355fb7c1e80abead4b9399shemminger		.msg_namelen = 	sizeof(nladdr),
1358ed63ab1f1283b2c63355fb7c1e80abead4b9399shemminger		.msg_iov = iov,
1368ed63ab1f1283b2c63355fb7c1e80abead4b9399shemminger		.msg_iovlen = 2,
137aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	};
138aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
139aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	memset(&nladdr, 0, sizeof(nladdr));
140aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	nladdr.nl_family = AF_NETLINK;
141aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
142aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	nlh.nlmsg_len = NLMSG_LENGTH(len);
143aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	nlh.nlmsg_type = type;
144aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
145aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	nlh.nlmsg_pid = 0;
146aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	nlh.nlmsg_seq = rth->dump = ++rth->seq;
147aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
148aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	return sendmsg(rth->fd, &msg, 0);
149aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger}
150aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
151aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemmingerint rtnl_dump_filter(struct rtnl_handle *rth,
1526dc9f016347441fbf94cf851c054b0f45ba32c1cosdl.net!shemminger		     rtnl_filter_t filter,
153aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		     void *arg1,
1546dc9f016347441fbf94cf851c054b0f45ba32c1cosdl.net!shemminger		     rtnl_filter_t junk,
155aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		     void *arg2)
156aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger{
157aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct sockaddr_nl nladdr;
1588ed63ab1f1283b2c63355fb7c1e80abead4b9399shemminger	struct iovec iov;
1598ed63ab1f1283b2c63355fb7c1e80abead4b9399shemminger	struct msghdr msg = {
1608ed63ab1f1283b2c63355fb7c1e80abead4b9399shemminger		.msg_name = &nladdr,
1618ed63ab1f1283b2c63355fb7c1e80abead4b9399shemminger		.msg_namelen = sizeof(nladdr),
1628ed63ab1f1283b2c63355fb7c1e80abead4b9399shemminger		.msg_iov = &iov,
1638ed63ab1f1283b2c63355fb7c1e80abead4b9399shemminger		.msg_iovlen = 1,
1648ed63ab1f1283b2c63355fb7c1e80abead4b9399shemminger	};
1658ed63ab1f1283b2c63355fb7c1e80abead4b9399shemminger	char buf[16384];
166aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
1678ed63ab1f1283b2c63355fb7c1e80abead4b9399shemminger	iov.iov_base = buf;
168aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	while (1) {
169aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		int status;
170aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		struct nlmsghdr *h;
171aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
1728ed63ab1f1283b2c63355fb7c1e80abead4b9399shemminger		iov.iov_len = sizeof(buf);
173aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		status = recvmsg(rth->fd, &msg, 0);
174aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
175aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (status < 0) {
176aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			if (errno == EINTR)
177aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				continue;
178aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			perror("OVERRUN");
179aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			continue;
180aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
1818ed63ab1f1283b2c63355fb7c1e80abead4b9399shemminger
182aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (status == 0) {
183aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			fprintf(stderr, "EOF on netlink\n");
184aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			return -1;
185aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
186aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
187aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		h = (struct nlmsghdr*)buf;
188aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		while (NLMSG_OK(h, status)) {
189aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			int err;
190aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
19110f57ef1ab9b4fca639cb2383bc04616fafba5eforg[shemminger]!shemminger			if (nladdr.nl_pid != 0 ||
19210f57ef1ab9b4fca639cb2383bc04616fafba5eforg[shemminger]!shemminger			    h->nlmsg_pid != rth->local.nl_pid ||
193aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			    h->nlmsg_seq != rth->dump) {
194aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				if (junk) {
195aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger					err = junk(&nladdr, h, arg2);
196aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger					if (err < 0)
197aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger						return err;
198aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				}
199aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				goto skip_it;
200aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			}
201aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
202aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			if (h->nlmsg_type == NLMSG_DONE)
203aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				return 0;
204aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			if (h->nlmsg_type == NLMSG_ERROR) {
205aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
206aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
207aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger					fprintf(stderr, "ERROR truncated\n");
208aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				} else {
209aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger					errno = -err->error;
210aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger					perror("RTNETLINK answers");
211aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				}
212aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				return -1;
213aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			}
214aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			err = filter(&nladdr, h, arg1);
215aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			if (err < 0)
216aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				return err;
217aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
218aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemmingerskip_it:
219aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			h = NLMSG_NEXT(h, status);
220aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
221aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (msg.msg_flags & MSG_TRUNC) {
222aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			fprintf(stderr, "Message truncated\n");
223aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			continue;
224aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
225aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (status) {
226aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			fprintf(stderr, "!!!Remnant of size %d\n", status);
227aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			exit(1);
228aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
229aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	}
230aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger}
231aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
232aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemmingerint rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
233aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	      unsigned groups, struct nlmsghdr *answer,
2346dc9f016347441fbf94cf851c054b0f45ba32c1cosdl.net!shemminger	      rtnl_filter_t junk,
235aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	      void *jarg)
236aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger{
237aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	int status;
238aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	unsigned seq;
239aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct nlmsghdr *h;
240aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct sockaddr_nl nladdr;
241fb2297599de1fb7447a050e16e0179f739460473shemminger	struct iovec iov = {
242fb2297599de1fb7447a050e16e0179f739460473shemminger		.iov_base = (void*) n,
243fb2297599de1fb7447a050e16e0179f739460473shemminger		.iov_len = n->nlmsg_len
244fb2297599de1fb7447a050e16e0179f739460473shemminger	};
245aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct msghdr msg = {
2468ed63ab1f1283b2c63355fb7c1e80abead4b9399shemminger		.msg_name = &nladdr,
2478ed63ab1f1283b2c63355fb7c1e80abead4b9399shemminger		.msg_namelen = sizeof(nladdr),
2488ed63ab1f1283b2c63355fb7c1e80abead4b9399shemminger		.msg_iov = &iov,
2498ed63ab1f1283b2c63355fb7c1e80abead4b9399shemminger		.msg_iovlen = 1,
250aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	};
2518ed63ab1f1283b2c63355fb7c1e80abead4b9399shemminger	char   buf[16384];
252aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
253aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	memset(&nladdr, 0, sizeof(nladdr));
254aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	nladdr.nl_family = AF_NETLINK;
255aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	nladdr.nl_pid = peer;
256aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	nladdr.nl_groups = groups;
257aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
258aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	n->nlmsg_seq = seq = ++rtnl->seq;
259007d3a3e9f0747039a772198293fd7f45a025f80osdl.net!shemminger
260aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	if (answer == NULL)
261aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		n->nlmsg_flags |= NLM_F_ACK;
262aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
263aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	status = sendmsg(rtnl->fd, &msg, 0);
264aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
265aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	if (status < 0) {
266aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		perror("Cannot talk to rtnetlink");
267aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		return -1;
268aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	}
269aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
270007d3a3e9f0747039a772198293fd7f45a025f80osdl.net!shemminger	memset(buf,0,sizeof(buf));
271007d3a3e9f0747039a772198293fd7f45a025f80osdl.net!shemminger
272aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	iov.iov_base = buf;
273aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
274aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	while (1) {
275aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		iov.iov_len = sizeof(buf);
276aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		status = recvmsg(rtnl->fd, &msg, 0);
277aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
278aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (status < 0) {
279aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			if (errno == EINTR)
280aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				continue;
281aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			perror("OVERRUN");
282aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			continue;
283aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
284aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (status == 0) {
285aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			fprintf(stderr, "EOF on netlink\n");
286aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			return -1;
287aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
288aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (msg.msg_namelen != sizeof(nladdr)) {
289aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			fprintf(stderr, "sender address length == %d\n", msg.msg_namelen);
290aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			exit(1);
291aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
292aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
293aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			int err;
294aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			int len = h->nlmsg_len;
295aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			int l = len - sizeof(*h);
296aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
297aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			if (l<0 || len>status) {
298aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				if (msg.msg_flags & MSG_TRUNC) {
299aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger					fprintf(stderr, "Truncated message\n");
300aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger					return -1;
301aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				}
302aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				fprintf(stderr, "!!!malformed message: len=%d\n", len);
303aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				exit(1);
304aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			}
305aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
30610f57ef1ab9b4fca639cb2383bc04616fafba5eforg[shemminger]!shemminger			if (nladdr.nl_pid != peer ||
30710f57ef1ab9b4fca639cb2383bc04616fafba5eforg[shemminger]!shemminger			    h->nlmsg_pid != rtnl->local.nl_pid ||
308aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			    h->nlmsg_seq != seq) {
309aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				if (junk) {
310aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger					err = junk(&nladdr, h, jarg);
311aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger					if (err < 0)
312aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger						return err;
313aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				}
3144cca16f20e92a97399d5814fc810af66ce0581d8shemminger				/* Don't forget to skip that message. */
3154cca16f20e92a97399d5814fc810af66ce0581d8shemminger				status -= NLMSG_ALIGN(len);
3164cca16f20e92a97399d5814fc810af66ce0581d8shemminger				h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
317aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				continue;
318aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			}
319aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
320aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			if (h->nlmsg_type == NLMSG_ERROR) {
321aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
322aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				if (l < sizeof(struct nlmsgerr)) {
323aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger					fprintf(stderr, "ERROR truncated\n");
324aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				} else {
325aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger					errno = -err->error;
326aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger					if (errno == 0) {
327aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger						if (answer)
328aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger							memcpy(answer, h, h->nlmsg_len);
329aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger						return 0;
330aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger					}
331aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger					perror("RTNETLINK answers");
332aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				}
333aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				return -1;
334aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			}
335aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			if (answer) {
336aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				memcpy(answer, h, h->nlmsg_len);
337aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				return 0;
338aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			}
339aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
340aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			fprintf(stderr, "Unexpected reply!!!\n");
341aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
342aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			status -= NLMSG_ALIGN(len);
343aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
344aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
345aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (msg.msg_flags & MSG_TRUNC) {
346aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			fprintf(stderr, "Message truncated\n");
347aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			continue;
348aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
349aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (status) {
350aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			fprintf(stderr, "!!!Remnant of size %d\n", status);
351aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			exit(1);
352aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
353aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	}
354aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger}
355aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
3568ed63ab1f1283b2c63355fb7c1e80abead4b9399shemmingerint rtnl_listen(struct rtnl_handle *rtnl,
3576dc9f016347441fbf94cf851c054b0f45ba32c1cosdl.net!shemminger		rtnl_filter_t handler,
3586dc9f016347441fbf94cf851c054b0f45ba32c1cosdl.net!shemminger		void *jarg)
359aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger{
360aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	int status;
361aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct nlmsghdr *h;
362aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct sockaddr_nl nladdr;
363aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct iovec iov;
364aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct msghdr msg = {
3658ed63ab1f1283b2c63355fb7c1e80abead4b9399shemminger		.msg_name = &nladdr,
3668ed63ab1f1283b2c63355fb7c1e80abead4b9399shemminger		.msg_namelen = sizeof(nladdr),
3678ed63ab1f1283b2c63355fb7c1e80abead4b9399shemminger		.msg_iov = &iov,
3688ed63ab1f1283b2c63355fb7c1e80abead4b9399shemminger		.msg_iovlen = 1,
369aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	};
3708ed63ab1f1283b2c63355fb7c1e80abead4b9399shemminger	char   buf[8192];
371aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
372aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	memset(&nladdr, 0, sizeof(nladdr));
373aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	nladdr.nl_family = AF_NETLINK;
374aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	nladdr.nl_pid = 0;
375aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	nladdr.nl_groups = 0;
376aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
377aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	iov.iov_base = buf;
378aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	while (1) {
379aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		iov.iov_len = sizeof(buf);
380aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		status = recvmsg(rtnl->fd, &msg, 0);
381aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
382aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (status < 0) {
383aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			if (errno == EINTR)
384aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				continue;
385aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			perror("OVERRUN");
386aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			continue;
387aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
388aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (status == 0) {
389aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			fprintf(stderr, "EOF on netlink\n");
390aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			return -1;
391aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
392aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (msg.msg_namelen != sizeof(nladdr)) {
393aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			fprintf(stderr, "Sender address length == %d\n", msg.msg_namelen);
394aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			exit(1);
395aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
396aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
397aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			int err;
398aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			int len = h->nlmsg_len;
399aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			int l = len - sizeof(*h);
400aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
401aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			if (l<0 || len>status) {
402aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				if (msg.msg_flags & MSG_TRUNC) {
403aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger					fprintf(stderr, "Truncated message\n");
404aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger					return -1;
405aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				}
406aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				fprintf(stderr, "!!!malformed message: len=%d\n", len);
407aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				exit(1);
408aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			}
409aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
410aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			err = handler(&nladdr, h, jarg);
411aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			if (err < 0)
412aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				return err;
413aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
414aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			status -= NLMSG_ALIGN(len);
415aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
416aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
417aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (msg.msg_flags & MSG_TRUNC) {
418aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			fprintf(stderr, "Message truncated\n");
419aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			continue;
420aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
421aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (status) {
422aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			fprintf(stderr, "!!!Remnant of size %d\n", status);
423aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			exit(1);
424aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
425aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	}
426aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger}
427aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
4286dc9f016347441fbf94cf851c054b0f45ba32c1cosdl.net!shemmingerint rtnl_from_file(FILE *rtnl, rtnl_filter_t handler,
4296dc9f016347441fbf94cf851c054b0f45ba32c1cosdl.net!shemminger		   void *jarg)
430aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger{
431aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	int status;
432aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct sockaddr_nl nladdr;
433aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	char   buf[8192];
434aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct nlmsghdr *h = (void*)buf;
435aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
436aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	memset(&nladdr, 0, sizeof(nladdr));
437aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	nladdr.nl_family = AF_NETLINK;
438aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	nladdr.nl_pid = 0;
439aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	nladdr.nl_groups = 0;
440aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
441aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	while (1) {
442aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		int err, len, type;
443aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		int l;
444aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
445aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		status = fread(&buf, 1, sizeof(*h), rtnl);
446aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
447aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (status < 0) {
448aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			if (errno == EINTR)
449aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				continue;
450aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			perror("rtnl_from_file: fread");
451aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			return -1;
452aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
453aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (status == 0)
454aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			return 0;
455aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
456aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		len = h->nlmsg_len;
457aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		type= h->nlmsg_type;
458aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		l = len - sizeof(*h);
459aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
460aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (l<0 || len>sizeof(buf)) {
461aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			fprintf(stderr, "!!!malformed message: len=%d @%lu\n",
462aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				len, ftell(rtnl));
463aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			return -1;
464aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
465aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
466aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl);
467aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
468aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (status < 0) {
469aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			perror("rtnl_from_file: fread");
470aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			return -1;
471aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
472aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (status < l) {
473aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			fprintf(stderr, "rtnl-from_file: truncated message\n");
474aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			return -1;
475aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
476aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
477aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		err = handler(&nladdr, h, jarg);
478aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (err < 0)
479aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			return err;
480aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	}
481aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger}
482aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
483aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemmingerint addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data)
484aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger{
485aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	int len = RTA_LENGTH(4);
486aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct rtattr *rta;
487007d3a3e9f0747039a772198293fd7f45a025f80osdl.net!shemminger	if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) {
488007d3a3e9f0747039a772198293fd7f45a025f80osdl.net!shemminger		fprintf(stderr,"addattr32: Error! max allowed bound %d exceeded\n",maxlen);
489aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		return -1;
490007d3a3e9f0747039a772198293fd7f45a025f80osdl.net!shemminger	}
49107f9436201eba2f75e6c480f5b16316b3bf977fcn);	rta = NLMSG_TAIL(n);
492aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	rta->rta_type = type;
493aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	rta->rta_len = len;
494aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	memcpy(RTA_DATA(rta), &data, 4);
495aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
496aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	return 0;
497aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger}
498aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
4998ed63ab1f1283b2c63355fb7c1e80abead4b9399shemmingerint addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
5006dc9f016347441fbf94cf851c054b0f45ba32c1cosdl.net!shemminger	      int alen)
501aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger{
502aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	int len = RTA_LENGTH(alen);
503aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct rtattr *rta;
504aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
5053dabdbb3da5ab7e9df8bf561602d681db26d8982net[shemminger]!shemminger	if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) {
506007d3a3e9f0747039a772198293fd7f45a025f80osdl.net!shemminger		fprintf(stderr, "addattr_l ERROR: message exceeded bound of %d\n",maxlen);
507aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		return -1;
508007d3a3e9f0747039a772198293fd7f45a025f80osdl.net!shemminger	}
50907f9436201eba2f75e6c480f5b16316b3bf977fcn);	rta = NLMSG_TAIL(n);
510aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	rta->rta_type = type;
511aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	rta->rta_len = len;
512aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	memcpy(RTA_DATA(rta), data, alen);
5133dabdbb3da5ab7e9df8bf561602d681db26d8982net[shemminger]!shemminger	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
514aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	return 0;
515aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger}
516aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
51707f9436201eba2f75e6c480f5b16316b3bf977fcstruct nlmsghdr *n, int maxlen, const void *data, int len)int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len)
51807f9436201eba2f75e6c480f5b16316b3bf977fcNLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len) > maxlen) {{
51907f9436201eba2f75e6c480f5b16316b3bf977fcstderr, "addraw_l ERROR: message exceeded bound of %d\n",maxlen);	if (NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len) > maxlen) {
52007f9436201eba2f75e6c480f5b16316b3bf977fcNLMSG_TAIL(n), data, len);		fprintf(stderr, "addraw_l ERROR: message exceeded bound of %d\n",maxlen);
52107f9436201eba2f75e6c480f5b16316b3bf977fc(void *) NLMSG_TAIL(n) + len,		return -1;
52207f9436201eba2f75e6c480f5b16316b3bf977fcn->nlmsg_len) + NLMSG_ALIGN(len);	}
523aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
524aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	memcpy(NLMSG_TAIL(n), data, len);
525aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	memset((void *) NLMSG_TAIL(n) + len, 0, NLMSG_ALIGN(len) - len);
526aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len);
527aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	return 0;
528007d3a3e9f0747039a772198293fd7f45a025f80osdl.net!shemminger}
529007d3a3e9f0747039a772198293fd7f45a025f80osdl.net!shemminger
530aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemmingerint rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data)
531007d3a3e9f0747039a772198293fd7f45a025f80osdl.net!shemminger{
532aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	int len = RTA_LENGTH(4);
533aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct rtattr *subrta;
534aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
535aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
536aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		fprintf(stderr,"rta_addattr32: Error! max allowed bound %d exceeded\n",maxlen);
537aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		return -1;
538aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	}
539aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
5408ed63ab1f1283b2c63355fb7c1e80abead4b9399shemminger	subrta->rta_type = type;
5416dc9f016347441fbf94cf851c054b0f45ba32c1cosdl.net!shemminger	subrta->rta_len = len;
542aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	memcpy(RTA_DATA(subrta), &data, 4);
543aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
544aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	return 0;
545aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger}
5463dabdbb3da5ab7e9df8bf561602d681db26d8982net[shemminger]!shemminger
547007d3a3e9f0747039a772198293fd7f45a025f80osdl.net!shemmingerint rta_addattr_l(struct rtattr *rta, int maxlen, int type,
548aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		  const void *data, int alen)
549007d3a3e9f0747039a772198293fd7f45a025f80osdl.net!shemminger{
550aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct rtattr *subrta;
551aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	int len = RTA_LENGTH(alen);
552aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
553aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	if (RTA_ALIGN(rta->rta_len) + RTA_ALIGN(len) > maxlen) {
5543dabdbb3da5ab7e9df8bf561602d681db26d8982net[shemminger]!shemminger		fprintf(stderr,"rta_addattr_l: Error! max allowed bound %d exceeded\n",maxlen);
555aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		return -1;
556aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	}
557aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
558aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	subrta->rta_type = type;
559aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	subrta->rta_len = len;
560175e2440df5be09b0a4c134cad958a49f7bfb9d9osdl.net!shemminger	memcpy(RTA_DATA(subrta), data, alen);
561aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	rta->rta_len = NLMSG_ALIGN(rta->rta_len) + RTA_ALIGN(len);
562aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	return 0;
563aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger}
564aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
565aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemmingerint parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
566aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger{
567aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
568aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	while (RTA_OK(rta, len)) {
569aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (rta->rta_type <= max)
570c7699875bee00fbcd057fc62c30d6560b044e007net[shemminger]!shemminger			tb[rta->rta_type] = rta;
571c7699875bee00fbcd057fc62c30d6560b044e007net[shemminger]!shemminger		rta = RTA_NEXT(rta,len);
572c7699875bee00fbcd057fc62c30d6560b044e007net[shemminger]!shemminger	}
573c7699875bee00fbcd057fc62c30d6560b044e007net[shemminger]!shemminger	if (len)
574175e2440df5be09b0a4c134cad958a49f7bfb9d9osdl.net!shemminger		fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
575175e2440df5be09b0a4c134cad958a49f7bfb9d9osdl.net!shemminger	return 0;
576c7699875bee00fbcd057fc62c30d6560b044e007net[shemminger]!shemminger}
577175e2440df5be09b0a4c134cad958a49f7bfb9d9osdl.net!shemminger
578c7699875bee00fbcd057fc62c30d6560b044e007net[shemminger]!shemmingerint parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int len)
579c7699875bee00fbcd057fc62c30d6560b044e007net[shemminger]!shemminger{
580c7699875bee00fbcd057fc62c30d6560b044e007net[shemminger]!shemminger	int i = 0;
581c7699875bee00fbcd057fc62c30d6560b044e007net[shemminger]!shemminger
582c7699875bee00fbcd057fc62c30d6560b044e007net[shemminger]!shemminger	memset(tb, 0, sizeof(struct rtattr *) * max);
583c7699875bee00fbcd057fc62c30d6560b044e007net[shemminger]!shemminger	while (RTA_OK(rta, len)) {
584c7699875bee00fbcd057fc62c30d6560b044e007net[shemminger]!shemminger		if (rta->rta_type <= max && i < max)
585			tb[i++] = rta;
586		rta = RTA_NEXT(rta,len);
587	}
588	if (len)
589		fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
590	return i;
591}
592