libnetlink.c revision aba5acdfdb347d2c21fc67d613d83d4430ca3937
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{
30aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	close(rth->fd);
31aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger}
32aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
33aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemmingerint rtnl_open(struct rtnl_handle *rth, unsigned subscriptions)
34aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger{
35aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	int addr_len;
36aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
37aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	memset(rth, 0, sizeof(rth));
38aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
39aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	rth->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
40aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	if (rth->fd < 0) {
41aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		perror("Cannot open netlink socket");
42aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		return -1;
43aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	}
44aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
45aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	memset(&rth->local, 0, sizeof(rth->local));
46aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	rth->local.nl_family = AF_NETLINK;
47aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	rth->local.nl_groups = subscriptions;
48aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
49aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) {
50aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		perror("Cannot bind netlink socket");
51aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		return -1;
52aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	}
53aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	addr_len = sizeof(rth->local);
54aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) {
55aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		perror("Cannot getsockname");
56aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		return -1;
57aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	}
58aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	if (addr_len != sizeof(rth->local)) {
59aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		fprintf(stderr, "Wrong address length %d\n", addr_len);
60aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		return -1;
61aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	}
62aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	if (rth->local.nl_family != AF_NETLINK) {
63aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		fprintf(stderr, "Wrong address family %d\n", rth->local.nl_family);
64aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		return -1;
65aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	}
66aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	rth->seq = time(NULL);
67aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	return 0;
68aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger}
69aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
70aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemmingerint rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type)
71aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger{
72aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct {
73aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		struct nlmsghdr nlh;
74aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		struct rtgenmsg g;
75aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	} req;
76aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct sockaddr_nl nladdr;
77aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
78aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	memset(&nladdr, 0, sizeof(nladdr));
79aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	nladdr.nl_family = AF_NETLINK;
80aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
81aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	req.nlh.nlmsg_len = sizeof(req);
82aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	req.nlh.nlmsg_type = type;
83aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
84aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	req.nlh.nlmsg_pid = 0;
85aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
86aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	req.g.rtgen_family = family;
87aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
88aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	return sendto(rth->fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr));
89aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger}
90aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
91aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemmingerint rtnl_send(struct rtnl_handle *rth, char *buf, int len)
92aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger{
93aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct sockaddr_nl nladdr;
94aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
95aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	memset(&nladdr, 0, sizeof(nladdr));
96aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	nladdr.nl_family = AF_NETLINK;
97aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
98aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	return sendto(rth->fd, buf, len, 0, (struct sockaddr*)&nladdr, sizeof(nladdr));
99aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger}
100aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
101aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemmingerint rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
102aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger{
103aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct nlmsghdr nlh;
104aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct sockaddr_nl nladdr;
105aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct iovec iov[2] = { { &nlh, sizeof(nlh) }, { req, len } };
106aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct msghdr msg = {
107aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		(void*)&nladdr, sizeof(nladdr),
108aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		iov,	2,
109aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		NULL,	0,
110aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		0
111aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	};
112aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
113aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	memset(&nladdr, 0, sizeof(nladdr));
114aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	nladdr.nl_family = AF_NETLINK;
115aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
116aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	nlh.nlmsg_len = NLMSG_LENGTH(len);
117aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	nlh.nlmsg_type = type;
118aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
119aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	nlh.nlmsg_pid = 0;
120aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	nlh.nlmsg_seq = rth->dump = ++rth->seq;
121aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
122aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	return sendmsg(rth->fd, &msg, 0);
123aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger}
124aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
125aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemmingerint rtnl_dump_filter(struct rtnl_handle *rth,
126aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		     int (*filter)(struct sockaddr_nl *, struct nlmsghdr *n, void *),
127aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		     void *arg1,
128aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		     int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
129aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		     void *arg2)
130aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger{
131aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	char	buf[8192];
132aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct sockaddr_nl nladdr;
133aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct iovec iov = { buf, sizeof(buf) };
134aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
135aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	while (1) {
136aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		int status;
137aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		struct nlmsghdr *h;
138aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
139aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		struct msghdr msg = {
140aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			(void*)&nladdr, sizeof(nladdr),
141aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			&iov,	1,
142aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			NULL,	0,
143aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			0
144aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		};
145aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
146aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		status = recvmsg(rth->fd, &msg, 0);
147aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
148aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (status < 0) {
149aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			if (errno == EINTR)
150aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				continue;
151aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			perror("OVERRUN");
152aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			continue;
153aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
154aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (status == 0) {
155aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			fprintf(stderr, "EOF on netlink\n");
156aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			return -1;
157aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
158aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (msg.msg_namelen != sizeof(nladdr)) {
159aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			fprintf(stderr, "sender address length == %d\n", msg.msg_namelen);
160aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			exit(1);
161aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
162aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
163aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		h = (struct nlmsghdr*)buf;
164aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		while (NLMSG_OK(h, status)) {
165aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			int err;
166aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
167aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			if (h->nlmsg_pid != rth->local.nl_pid ||
168aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			    h->nlmsg_seq != rth->dump) {
169aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				if (junk) {
170aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger					err = junk(&nladdr, h, arg2);
171aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger					if (err < 0)
172aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger						return err;
173aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				}
174aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				goto skip_it;
175aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			}
176aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
177aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			if (h->nlmsg_type == NLMSG_DONE)
178aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				return 0;
179aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			if (h->nlmsg_type == NLMSG_ERROR) {
180aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
181aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
182aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger					fprintf(stderr, "ERROR truncated\n");
183aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				} else {
184aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger					errno = -err->error;
185aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger					perror("RTNETLINK answers");
186aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				}
187aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				return -1;
188aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			}
189aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			err = filter(&nladdr, h, arg1);
190aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			if (err < 0)
191aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				return err;
192aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
193aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemmingerskip_it:
194aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			h = NLMSG_NEXT(h, status);
195aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
196aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (msg.msg_flags & MSG_TRUNC) {
197aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			fprintf(stderr, "Message truncated\n");
198aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			continue;
199aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
200aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (status) {
201aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			fprintf(stderr, "!!!Remnant of size %d\n", status);
202aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			exit(1);
203aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
204aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	}
205aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger}
206aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
207aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemmingerint rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
208aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	      unsigned groups, struct nlmsghdr *answer,
209aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	      int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
210aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	      void *jarg)
211aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger{
212aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	int status;
213aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	unsigned seq;
214aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct nlmsghdr *h;
215aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct sockaddr_nl nladdr;
216aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct iovec iov = { (void*)n, n->nlmsg_len };
217aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	char   buf[8192];
218aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct msghdr msg = {
219aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		(void*)&nladdr, sizeof(nladdr),
220aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		&iov,	1,
221aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		NULL,	0,
222aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		0
223aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	};
224aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
225aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	memset(&nladdr, 0, sizeof(nladdr));
226aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	nladdr.nl_family = AF_NETLINK;
227aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	nladdr.nl_pid = peer;
228aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	nladdr.nl_groups = groups;
229aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
230aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	n->nlmsg_seq = seq = ++rtnl->seq;
231aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	if (answer == NULL)
232aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		n->nlmsg_flags |= NLM_F_ACK;
233aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
234aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	status = sendmsg(rtnl->fd, &msg, 0);
235aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
236aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	if (status < 0) {
237aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		perror("Cannot talk to rtnetlink");
238aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		return -1;
239aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	}
240aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
241aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	iov.iov_base = buf;
242aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
243aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	while (1) {
244aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		iov.iov_len = sizeof(buf);
245aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		status = recvmsg(rtnl->fd, &msg, 0);
246aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
247aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (status < 0) {
248aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			if (errno == EINTR)
249aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				continue;
250aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			perror("OVERRUN");
251aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			continue;
252aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
253aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (status == 0) {
254aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			fprintf(stderr, "EOF on netlink\n");
255aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			return -1;
256aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
257aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (msg.msg_namelen != sizeof(nladdr)) {
258aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			fprintf(stderr, "sender address length == %d\n", msg.msg_namelen);
259aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			exit(1);
260aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
261aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
262aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			int err;
263aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			int len = h->nlmsg_len;
264aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			int l = len - sizeof(*h);
265aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
266aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			if (l<0 || len>status) {
267aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				if (msg.msg_flags & MSG_TRUNC) {
268aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger					fprintf(stderr, "Truncated message\n");
269aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger					return -1;
270aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				}
271aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				fprintf(stderr, "!!!malformed message: len=%d\n", len);
272aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				exit(1);
273aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			}
274aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
275aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			if (h->nlmsg_pid != rtnl->local.nl_pid ||
276aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			    h->nlmsg_seq != seq) {
277aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				if (junk) {
278aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger					err = junk(&nladdr, h, jarg);
279aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger					if (err < 0)
280aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger						return err;
281aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				}
282aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				continue;
283aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			}
284aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
285aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			if (h->nlmsg_type == NLMSG_ERROR) {
286aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
287aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				if (l < sizeof(struct nlmsgerr)) {
288aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger					fprintf(stderr, "ERROR truncated\n");
289aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				} else {
290aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger					errno = -err->error;
291aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger					if (errno == 0) {
292aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger						if (answer)
293aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger							memcpy(answer, h, h->nlmsg_len);
294aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger						return 0;
295aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger					}
296aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger					perror("RTNETLINK answers");
297aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				}
298aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				return -1;
299aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			}
300aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			if (answer) {
301aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				memcpy(answer, h, h->nlmsg_len);
302aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				return 0;
303aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			}
304aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
305aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			fprintf(stderr, "Unexpected reply!!!\n");
306aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
307aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			status -= NLMSG_ALIGN(len);
308aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
309aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
310aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (msg.msg_flags & MSG_TRUNC) {
311aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			fprintf(stderr, "Message truncated\n");
312aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			continue;
313aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
314aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (status) {
315aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			fprintf(stderr, "!!!Remnant of size %d\n", status);
316aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			exit(1);
317aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
318aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	}
319aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger}
320aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
321aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemmingerint rtnl_listen(struct rtnl_handle *rtnl,
322aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	      int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
323aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	      void *jarg)
324aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger{
325aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	int status;
326aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct nlmsghdr *h;
327aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct sockaddr_nl nladdr;
328aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct iovec iov;
329aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	char   buf[8192];
330aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct msghdr msg = {
331aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		(void*)&nladdr, sizeof(nladdr),
332aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		&iov,	1,
333aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		NULL,	0,
334aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		0
335aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	};
336aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
337aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	memset(&nladdr, 0, sizeof(nladdr));
338aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	nladdr.nl_family = AF_NETLINK;
339aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	nladdr.nl_pid = 0;
340aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	nladdr.nl_groups = 0;
341aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
342aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
343aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	iov.iov_base = buf;
344aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
345aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	while (1) {
346aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		iov.iov_len = sizeof(buf);
347aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		status = recvmsg(rtnl->fd, &msg, 0);
348aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
349aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (status < 0) {
350aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			if (errno == EINTR)
351aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				continue;
352aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			perror("OVERRUN");
353aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			continue;
354aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
355aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (status == 0) {
356aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			fprintf(stderr, "EOF on netlink\n");
357aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			return -1;
358aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
359aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (msg.msg_namelen != sizeof(nladdr)) {
360aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			fprintf(stderr, "Sender address length == %d\n", msg.msg_namelen);
361aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			exit(1);
362aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
363aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
364aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			int err;
365aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			int len = h->nlmsg_len;
366aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			int l = len - sizeof(*h);
367aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
368aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			if (l<0 || len>status) {
369aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				if (msg.msg_flags & MSG_TRUNC) {
370aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger					fprintf(stderr, "Truncated message\n");
371aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger					return -1;
372aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				}
373aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				fprintf(stderr, "!!!malformed message: len=%d\n", len);
374aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				exit(1);
375aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			}
376aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
377aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			err = handler(&nladdr, h, jarg);
378aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			if (err < 0)
379aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				return err;
380aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
381aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			status -= NLMSG_ALIGN(len);
382aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
383aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
384aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (msg.msg_flags & MSG_TRUNC) {
385aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			fprintf(stderr, "Message truncated\n");
386aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			continue;
387aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
388aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (status) {
389aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			fprintf(stderr, "!!!Remnant of size %d\n", status);
390aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			exit(1);
391aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
392aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	}
393aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger}
394aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
395aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemmingerint rtnl_from_file(FILE *rtnl,
396aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	      int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
397aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	      void *jarg)
398aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger{
399aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	int status;
400aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct sockaddr_nl nladdr;
401aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	char   buf[8192];
402aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct nlmsghdr *h = (void*)buf;
403aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
404aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	memset(&nladdr, 0, sizeof(nladdr));
405aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	nladdr.nl_family = AF_NETLINK;
406aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	nladdr.nl_pid = 0;
407aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	nladdr.nl_groups = 0;
408aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
409aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	while (1) {
410aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		int err, len, type;
411aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		int l;
412aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
413aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		status = fread(&buf, 1, sizeof(*h), rtnl);
414aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
415aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (status < 0) {
416aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			if (errno == EINTR)
417aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				continue;
418aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			perror("rtnl_from_file: fread");
419aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			return -1;
420aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
421aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (status == 0)
422aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			return 0;
423aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
424aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		len = h->nlmsg_len;
425aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		type= h->nlmsg_type;
426aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		l = len - sizeof(*h);
427aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
428aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (l<0 || len>sizeof(buf)) {
429aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			fprintf(stderr, "!!!malformed message: len=%d @%lu\n",
430aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				len, ftell(rtnl));
431aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			return -1;
432aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
433aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
434aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl);
435aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
436aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (status < 0) {
437aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			perror("rtnl_from_file: fread");
438aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			return -1;
439aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
440aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (status < l) {
441aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			fprintf(stderr, "rtnl-from_file: truncated message\n");
442aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			return -1;
443aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
444aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
445aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		err = handler(&nladdr, h, jarg);
446aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (err < 0)
447aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			return err;
448aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	}
449aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger}
450aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
451aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemmingerint addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data)
452aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger{
453aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	int len = RTA_LENGTH(4);
454aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct rtattr *rta;
455aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen)
456aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		return -1;
457aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len));
458aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	rta->rta_type = type;
459aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	rta->rta_len = len;
460aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	memcpy(RTA_DATA(rta), &data, 4);
461aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
462aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	return 0;
463aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger}
464aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
465aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemmingerint addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
466aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger{
467aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	int len = RTA_LENGTH(alen);
468aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct rtattr *rta;
469aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
470aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen)
471aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		return -1;
472aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len));
473aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	rta->rta_type = type;
474aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	rta->rta_len = len;
475aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	memcpy(RTA_DATA(rta), data, alen);
476aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
477aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	return 0;
478aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger}
479aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
480aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemmingerint rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data)
481aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger{
482aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	int len = RTA_LENGTH(4);
483aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct rtattr *subrta;
484aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
485aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	if (RTA_ALIGN(rta->rta_len) + len > maxlen)
486aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		return -1;
487aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
488aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	subrta->rta_type = type;
489aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	subrta->rta_len = len;
490aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	memcpy(RTA_DATA(subrta), &data, 4);
491aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
492aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	return 0;
493aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger}
494aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
495aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemmingerint rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data, int alen)
496aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger{
497aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct rtattr *subrta;
498aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	int len = RTA_LENGTH(alen);
499aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
500aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	if (RTA_ALIGN(rta->rta_len) + len > maxlen)
501aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		return -1;
502aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
503aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	subrta->rta_type = type;
504aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	subrta->rta_len = len;
505aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	memcpy(RTA_DATA(subrta), data, alen);
506aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
507aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	return 0;
508aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger}
509aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
510aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
511aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemmingerint parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
512aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger{
513aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	while (RTA_OK(rta, len)) {
514aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (rta->rta_type <= max)
515aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			tb[rta->rta_type] = rta;
516aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		rta = RTA_NEXT(rta,len);
517aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	}
518aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	if (len)
519aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
520aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	return 0;
521aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger}
522