blob: 0adcbf3f6e38960bfd093e8eae8c8ab0364903f3 [file] [log] [blame]
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001/*
2 * libnetlink.c RTnetlink service routines.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10 *
11 */
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <unistd.h>
16#include <syslog.h>
17#include <fcntl.h>
18#include <net/if_arp.h>
19#include <sys/socket.h>
20#include <netinet/in.h>
21#include <string.h>
22#include <errno.h>
23#include <time.h>
24#include <sys/uio.h>
25
26#include "libnetlink.h"
27
Nicolas Dichtel449b8242015-05-20 16:20:00 +020028#ifndef SOL_NETLINK
29#define SOL_NETLINK 270
30#endif
31
Stephen Hemmingerc079e122015-05-27 12:26:14 -070032#ifndef MIN
33#define MIN(a, b) ((a) < (b) ? (a) : (b))
34#endif
35
Patrick McHardy7f031912009-10-28 20:50:48 +010036int rcvbuf = 1024 * 1024;
37
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000038void rtnl_close(struct rtnl_handle *rth)
39{
Stephen Hemminger3bfa73f2006-09-26 10:41:57 -070040 if (rth->fd >= 0) {
41 close(rth->fd);
42 rth->fd = -1;
43 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000044}
45
shemminger8ed63ab2005-09-21 19:33:17 +000046int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions,
47 int protocol)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000048{
shemmingerf332d162005-07-05 22:37:15 +000049 socklen_t addr_len;
osdl.net!shemminger007d3a32004-08-13 23:54:55 +000050 int sndbuf = 32768;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000051
Stephen Hemmingerb16621c2007-05-10 19:33:21 -070052 memset(rth, 0, sizeof(*rth));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000053
vadimk8a4025f2014-12-04 12:32:58 +020054 rth->proto = protocol;
Andrey Vaginbcb9d402013-06-04 12:01:14 +040055 rth->fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, protocol);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000056 if (rth->fd < 0) {
57 perror("Cannot open netlink socket");
58 return -1;
59 }
60
osdl.net!shemminger007d3a32004-08-13 23:54:55 +000061 if (setsockopt(rth->fd,SOL_SOCKET,SO_SNDBUF,&sndbuf,sizeof(sndbuf)) < 0) {
62 perror("SO_SNDBUF");
63 return -1;
64 }
65
66 if (setsockopt(rth->fd,SOL_SOCKET,SO_RCVBUF,&rcvbuf,sizeof(rcvbuf)) < 0) {
67 perror("SO_RCVBUF");
68 return -1;
69 }
70
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000071 memset(&rth->local, 0, sizeof(rth->local));
72 rth->local.nl_family = AF_NETLINK;
73 rth->local.nl_groups = subscriptions;
74
75 if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) {
76 perror("Cannot bind netlink socket");
77 return -1;
78 }
79 addr_len = sizeof(rth->local);
80 if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) {
81 perror("Cannot getsockname");
82 return -1;
83 }
84 if (addr_len != sizeof(rth->local)) {
85 fprintf(stderr, "Wrong address length %d\n", addr_len);
86 return -1;
87 }
88 if (rth->local.nl_family != AF_NETLINK) {
89 fprintf(stderr, "Wrong address family %d\n", rth->local.nl_family);
90 return -1;
91 }
92 rth->seq = time(NULL);
93 return 0;
94}
95
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +000096int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions)
97{
98 return rtnl_open_byproto(rth, subscriptions, NETLINK_ROUTE);
99}
100
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000101int rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type)
102{
Vlad Yasevich9eff0e52013-02-28 10:04:05 +0000103 return rtnl_wilddump_req_filter(rth, family, type, RTEXT_FILTER_VF);
104}
105
106int rtnl_wilddump_req_filter(struct rtnl_handle *rth, int family, int type,
107 __u32 filt_mask)
108{
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000109 struct {
110 struct nlmsghdr nlh;
Alexander Duyck63338dc2013-04-25 12:07:10 +0000111 struct ifinfomsg ifm;
Lutz Jaenicke257422f2012-08-30 05:01:34 +0000112 /* attribute has to be NLMSG aligned */
113 struct rtattr ext_req __attribute__ ((aligned(NLMSG_ALIGNTO)));
Rose, Gregory Vbd886eb2012-02-21 10:43:09 +0000114 __u32 ext_filter_mask;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000115 } req;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000116
shemminger8ed63ab2005-09-21 19:33:17 +0000117 memset(&req, 0, sizeof(req));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000118 req.nlh.nlmsg_len = sizeof(req);
119 req.nlh.nlmsg_type = type;
Masatake YAMATOaa38c3e2012-01-19 14:16:12 -0800120 req.nlh.nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000121 req.nlh.nlmsg_pid = 0;
122 req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
Alexander Duyck63338dc2013-04-25 12:07:10 +0000123 req.ifm.ifi_family = family;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000124
Rose, Gregory Vbd886eb2012-02-21 10:43:09 +0000125 req.ext_req.rta_type = IFLA_EXT_MASK;
126 req.ext_req.rta_len = RTA_LENGTH(sizeof(__u32));
Vlad Yasevich9eff0e52013-02-28 10:04:05 +0000127 req.ext_filter_mask = filt_mask;
Rose, Gregory Vbd886eb2012-02-21 10:43:09 +0000128
Stephen Hemmingerf31a37f2008-01-31 21:38:58 -0800129 return send(rth->fd, (void*)&req, sizeof(req), 0);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000130}
131
David Ahernb0a4ce62016-05-11 06:51:58 -0700132int rtnl_wilddump_req_filter_fn(struct rtnl_handle *rth, int family, int type,
133 req_filter_fn_t filter_fn)
134{
135 struct {
136 struct nlmsghdr nlh;
137 struct ifinfomsg ifm;
138 char buf[1024];
139 } req;
140 int err;
141
142 if (!filter_fn)
143 return -EINVAL;
144
145 memset(&req, 0, sizeof(req));
146 req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
147 req.nlh.nlmsg_type = type;
148 req.nlh.nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST;
149 req.nlh.nlmsg_pid = 0;
150 req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
151 req.ifm.ifi_family = family;
152
153 err = filter_fn(&req.nlh, sizeof(req));
154 if (err)
155 return err;
156
157 return send(rth->fd, (void*)&req, sizeof(req), 0);
158}
159
Stephen Hemminger6cf83982011-12-23 10:40:04 -0800160int rtnl_send(struct rtnl_handle *rth, const void *buf, int len)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000161{
Stephen Hemmingerf31a37f2008-01-31 21:38:58 -0800162 return send(rth->fd, buf, len, 0);
163}
164
Stephen Hemminger6cf83982011-12-23 10:40:04 -0800165int rtnl_send_check(struct rtnl_handle *rth, const void *buf, int len)
Stephen Hemmingerf31a37f2008-01-31 21:38:58 -0800166{
Stephen Hemminger54bb35c2008-01-26 11:09:42 -0800167 struct nlmsghdr *h;
168 int status;
169 char resp[1024];
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000170
Stephen Hemmingerf31a37f2008-01-31 21:38:58 -0800171 status = send(rth->fd, buf, len, 0);
Stephen Hemminger54bb35c2008-01-26 11:09:42 -0800172 if (status < 0)
173 return status;
174
Stephen Hemminger2d8240f2009-07-13 10:15:23 -0700175 /* Check for immediate errors */
176 status = recv(rth->fd, resp, sizeof(resp), MSG_DONTWAIT|MSG_PEEK);
Stephen Hemminger54bb35c2008-01-26 11:09:42 -0800177 if (status < 0) {
178 if (errno == EAGAIN)
179 return 0;
180 return -1;
181 }
182
183 for (h = (struct nlmsghdr *)resp; NLMSG_OK(h, status);
184 h = NLMSG_NEXT(h, status)) {
185 if (h->nlmsg_type == NLMSG_ERROR) {
186 struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
187 if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
188 fprintf(stderr, "ERROR truncated\n");
Stephen Hemmingere9e93652016-03-27 10:47:46 -0700189 else
Stephen Hemminger54bb35c2008-01-26 11:09:42 -0800190 errno = -err->error;
Sven Anders24f38182009-11-10 09:07:26 -0800191 return -1;
Stephen Hemminger54bb35c2008-01-26 11:09:42 -0800192 }
Stephen Hemminger54bb35c2008-01-26 11:09:42 -0800193 }
194
195 return 0;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000196}
197
198int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
199{
200 struct nlmsghdr nlh;
Stephen Hemminger6cf83982011-12-23 10:40:04 -0800201 struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
shemminger8ed63ab2005-09-21 19:33:17 +0000202 struct iovec iov[2] = {
203 { .iov_base = &nlh, .iov_len = sizeof(nlh) },
204 { .iov_base = req, .iov_len = len }
205 };
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000206 struct msghdr msg = {
shemminger8ed63ab2005-09-21 19:33:17 +0000207 .msg_name = &nladdr,
208 .msg_namelen = sizeof(nladdr),
209 .msg_iov = iov,
210 .msg_iovlen = 2,
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000211 };
212
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000213 nlh.nlmsg_len = NLMSG_LENGTH(len);
214 nlh.nlmsg_type = type;
Masatake YAMATOaa38c3e2012-01-19 14:16:12 -0800215 nlh.nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000216 nlh.nlmsg_pid = 0;
217 nlh.nlmsg_seq = rth->dump = ++rth->seq;
218
219 return sendmsg(rth->fd, &msg, 0);
220}
221
David Ahern0d238ca2015-10-02 09:42:27 -0700222int rtnl_dump_request_n(struct rtnl_handle *rth, struct nlmsghdr *n)
223{
224 struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
225 struct iovec iov = {
226 .iov_base = (void*) n,
227 .iov_len = n->nlmsg_len
228 };
229 struct msghdr msg = {
230 .msg_name = &nladdr,
231 .msg_namelen = sizeof(nladdr),
232 .msg_iov = &iov,
233 .msg_iovlen = 1,
234 };
235
236 n->nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST;
237 n->nlmsg_pid = 0;
238 n->nlmsg_seq = rth->dump = ++rth->seq;
239
240 return sendmsg(rth->fd, &msg, 0);
241}
242
Simon Hormanb49240e2009-12-03 12:08:27 +1100243int rtnl_dump_filter_l(struct rtnl_handle *rth,
244 const struct rtnl_dump_filter_arg *arg)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000245{
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000246 struct sockaddr_nl nladdr;
shemminger8ed63ab2005-09-21 19:33:17 +0000247 struct iovec iov;
248 struct msghdr msg = {
249 .msg_name = &nladdr,
250 .msg_namelen = sizeof(nladdr),
251 .msg_iov = &iov,
252 .msg_iovlen = 1,
253 };
Phil Sutter72b365e2016-03-04 19:57:28 +0100254 char buf[32768];
Nicolas Dichtel16f02e12013-03-22 06:34:02 +0000255 int dump_intr = 0;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000256
shemminger8ed63ab2005-09-21 19:33:17 +0000257 iov.iov_base = buf;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000258 while (1) {
259 int status;
Simon Hormanb49240e2009-12-03 12:08:27 +1100260 const struct rtnl_dump_filter_arg *a;
Ben Greear3bc1c4f2010-08-16 10:00:08 -0700261 int found_done = 0;
262 int msglen = 0;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000263
shemminger8ed63ab2005-09-21 19:33:17 +0000264 iov.iov_len = sizeof(buf);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000265 status = recvmsg(rth->fd, &msg, 0);
266
267 if (status < 0) {
Stephen Hemmingeraa8032e2008-01-25 15:39:09 -0800268 if (errno == EINTR || errno == EAGAIN)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000269 continue;
Stephen Hemmingeraa8032e2008-01-25 15:39:09 -0800270 fprintf(stderr, "netlink receive error %s (%d)\n",
271 strerror(errno), errno);
272 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000273 }
shemminger8ed63ab2005-09-21 19:33:17 +0000274
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000275 if (status == 0) {
276 fprintf(stderr, "EOF on netlink\n");
277 return -1;
278 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000279
Vadim Kochan486ccd92014-12-26 04:26:27 +0200280 if (rth->dump_fp)
281 fwrite(buf, 1, NLMSG_ALIGN(status), rth->dump_fp);
282
Simon Hormanb49240e2009-12-03 12:08:27 +1100283 for (a = arg; a->filter; a++) {
284 struct nlmsghdr *h = (struct nlmsghdr*)buf;
Ben Greear3bc1c4f2010-08-16 10:00:08 -0700285 msglen = status;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000286
Ben Greear3bc1c4f2010-08-16 10:00:08 -0700287 while (NLMSG_OK(h, msglen)) {
Vadim Kochan486ccd92014-12-26 04:26:27 +0200288 int err = 0;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000289
Phil Sutter8e728802015-11-24 15:31:01 +0100290 h->nlmsg_flags &= ~a->nc_flags;
291
Simon Hormanb49240e2009-12-03 12:08:27 +1100292 if (nladdr.nl_pid != 0 ||
293 h->nlmsg_pid != rth->local.nl_pid ||
Stephen Hemmingercd70f3f2011-12-28 10:37:12 -0800294 h->nlmsg_seq != rth->dump)
Simon Hormanb49240e2009-12-03 12:08:27 +1100295 goto skip_it;
Simon Hormanb49240e2009-12-03 12:08:27 +1100296
Nicolas Dichtel16f02e12013-03-22 06:34:02 +0000297 if (h->nlmsg_flags & NLM_F_DUMP_INTR)
298 dump_intr = 1;
299
Ben Greear3bc1c4f2010-08-16 10:00:08 -0700300 if (h->nlmsg_type == NLMSG_DONE) {
301 found_done = 1;
302 break; /* process next filter */
303 }
Simon Hormanb49240e2009-12-03 12:08:27 +1100304 if (h->nlmsg_type == NLMSG_ERROR) {
305 struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
306 if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
307 fprintf(stderr,
308 "ERROR truncated\n");
309 } else {
310 errno = -err->error;
vadimk8a4025f2014-12-04 12:32:58 +0200311 if (rth->proto == NETLINK_SOCK_DIAG &&
Vadim Kochan486ccd92014-12-26 04:26:27 +0200312 (errno == ENOENT ||
313 errno == EOPNOTSUPP))
vadimk8a4025f2014-12-04 12:32:58 +0200314 return -1;
315
Simon Hormanb49240e2009-12-03 12:08:27 +1100316 perror("RTNETLINK answers");
317 }
318 return -1;
319 }
Vadim Kochan486ccd92014-12-26 04:26:27 +0200320
321 if (!rth->dump_fp) {
322 err = a->filter(&nladdr, h, a->arg1);
323 if (err < 0)
324 return err;
325 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000326
327skip_it:
Ben Greear3bc1c4f2010-08-16 10:00:08 -0700328 h = NLMSG_NEXT(h, msglen);
Simon Hormanb49240e2009-12-03 12:08:27 +1100329 }
Ben Greear3bc1c4f2010-08-16 10:00:08 -0700330 }
331
Nicolas Dichtel16f02e12013-03-22 06:34:02 +0000332 if (found_done) {
333 if (dump_intr)
334 fprintf(stderr,
335 "Dump was interrupted and may be inconsistent.\n");
Ben Greear3bc1c4f2010-08-16 10:00:08 -0700336 return 0;
Nicolas Dichtel16f02e12013-03-22 06:34:02 +0000337 }
Ben Greear3bc1c4f2010-08-16 10:00:08 -0700338
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000339 if (msg.msg_flags & MSG_TRUNC) {
340 fprintf(stderr, "Message truncated\n");
341 continue;
342 }
Ben Greear3bc1c4f2010-08-16 10:00:08 -0700343 if (msglen) {
344 fprintf(stderr, "!!!Remnant of size %d\n", msglen);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000345 exit(1);
346 }
347 }
348}
349
Phil Sutter8e728802015-11-24 15:31:01 +0100350int rtnl_dump_filter_nc(struct rtnl_handle *rth,
Simon Hormanb49240e2009-12-03 12:08:27 +1100351 rtnl_filter_t filter,
Phil Sutter8e728802015-11-24 15:31:01 +0100352 void *arg1, __u16 nc_flags)
Simon Hormanb49240e2009-12-03 12:08:27 +1100353{
354 const struct rtnl_dump_filter_arg a[2] = {
Phil Sutter8e728802015-11-24 15:31:01 +0100355 { .filter = filter, .arg1 = arg1, .nc_flags = nc_flags, },
356 { .filter = NULL, .arg1 = NULL, .nc_flags = 0, },
Simon Hormanb49240e2009-12-03 12:08:27 +1100357 };
358
359 return rtnl_dump_filter_l(rth, a);
360}
361
Stephen Hemmingerc079e122015-05-27 12:26:14 -0700362int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
Nicolas Dichteled108cf2015-12-03 17:13:48 +0100363 struct nlmsghdr *answer, size_t maxlen)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000364{
365 int status;
366 unsigned seq;
367 struct nlmsghdr *h;
368 struct sockaddr_nl nladdr;
shemmingerfb229752005-10-04 23:15:32 +0000369 struct iovec iov = {
370 .iov_base = (void*) n,
371 .iov_len = n->nlmsg_len
372 };
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000373 struct msghdr msg = {
shemminger8ed63ab2005-09-21 19:33:17 +0000374 .msg_name = &nladdr,
375 .msg_namelen = sizeof(nladdr),
376 .msg_iov = &iov,
377 .msg_iovlen = 1,
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000378 };
Stephen Hemmingerc079e122015-05-27 12:26:14 -0700379 char buf[32768];
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000380
381 memset(&nladdr, 0, sizeof(nladdr));
382 nladdr.nl_family = AF_NETLINK;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000383
384 n->nlmsg_seq = seq = ++rtnl->seq;
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000385
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000386 if (answer == NULL)
387 n->nlmsg_flags |= NLM_F_ACK;
388
389 status = sendmsg(rtnl->fd, &msg, 0);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000390 if (status < 0) {
391 perror("Cannot talk to rtnetlink");
392 return -1;
393 }
394
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000395 memset(buf,0,sizeof(buf));
396
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000397 iov.iov_base = buf;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000398 while (1) {
399 iov.iov_len = sizeof(buf);
400 status = recvmsg(rtnl->fd, &msg, 0);
401
402 if (status < 0) {
Stephen Hemmingeraa8032e2008-01-25 15:39:09 -0800403 if (errno == EINTR || errno == EAGAIN)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000404 continue;
Stephen Hemmingeraa8032e2008-01-25 15:39:09 -0800405 fprintf(stderr, "netlink receive error %s (%d)\n",
406 strerror(errno), errno);
407 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000408 }
409 if (status == 0) {
410 fprintf(stderr, "EOF on netlink\n");
411 return -1;
412 }
413 if (msg.msg_namelen != sizeof(nladdr)) {
414 fprintf(stderr, "sender address length == %d\n", msg.msg_namelen);
415 exit(1);
416 }
417 for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000418 int len = h->nlmsg_len;
419 int l = len - sizeof(*h);
420
Stephen Hemmingercd70f3f2011-12-28 10:37:12 -0800421 if (l < 0 || len>status) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000422 if (msg.msg_flags & MSG_TRUNC) {
423 fprintf(stderr, "Truncated message\n");
424 return -1;
425 }
426 fprintf(stderr, "!!!malformed message: len=%d\n", len);
427 exit(1);
428 }
429
Stephen Hemmingerc079e122015-05-27 12:26:14 -0700430 if (nladdr.nl_pid != 0 ||
org[shemminger]!shemminger10f57ef2004-06-07 22:04:04 +0000431 h->nlmsg_pid != rtnl->local.nl_pid ||
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000432 h->nlmsg_seq != seq) {
shemminger4cca16f2006-03-10 23:31:46 +0000433 /* Don't forget to skip that message. */
434 status -= NLMSG_ALIGN(len);
435 h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000436 continue;
437 }
438
439 if (h->nlmsg_type == NLMSG_ERROR) {
440 struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
441 if (l < sizeof(struct nlmsgerr)) {
442 fprintf(stderr, "ERROR truncated\n");
Stephen Hemmingerc079e122015-05-27 12:26:14 -0700443 } else if (!err->error) {
444 if (answer)
445 memcpy(answer, h,
Nicolas Dichteled108cf2015-12-03 17:13:48 +0100446 MIN(maxlen, h->nlmsg_len));
Stephen Hemmingerc079e122015-05-27 12:26:14 -0700447 return 0;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000448 }
Stephen Hemmingerc079e122015-05-27 12:26:14 -0700449
Lorenzo Colitti57fdf2d2016-01-08 17:32:36 +0900450 if (rtnl->proto != NETLINK_SOCK_DIAG)
451 fprintf(stderr,
452 "RTNETLINK answers: %s\n",
453 strerror(-err->error));
Stephen Hemmingerc079e122015-05-27 12:26:14 -0700454 errno = -err->error;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000455 return -1;
456 }
Stephen Hemmingerc079e122015-05-27 12:26:14 -0700457
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000458 if (answer) {
Stephen Hemmingerc079e122015-05-27 12:26:14 -0700459 memcpy(answer, h,
Nicolas Dichteled108cf2015-12-03 17:13:48 +0100460 MIN(maxlen, h->nlmsg_len));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000461 return 0;
462 }
463
464 fprintf(stderr, "Unexpected reply!!!\n");
465
466 status -= NLMSG_ALIGN(len);
467 h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
468 }
Stephen Hemmingerc079e122015-05-27 12:26:14 -0700469
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000470 if (msg.msg_flags & MSG_TRUNC) {
471 fprintf(stderr, "Message truncated\n");
472 continue;
473 }
Stephen Hemmingerc079e122015-05-27 12:26:14 -0700474
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000475 if (status) {
476 fprintf(stderr, "!!!Remnant of size %d\n", status);
477 exit(1);
478 }
479 }
480}
481
Nicolas Dichtel449b8242015-05-20 16:20:00 +0200482int rtnl_listen_all_nsid(struct rtnl_handle *rth)
483{
484 unsigned int on = 1;
485
486 if (setsockopt(rth->fd, SOL_NETLINK, NETLINK_LISTEN_ALL_NSID, &on,
487 sizeof(on)) < 0) {
488 perror("NETLINK_LISTEN_ALL_NSID");
489 return -1;
490 }
491 rth->flags |= RTNL_HANDLE_F_LISTEN_ALL_NSID;
492 return 0;
493}
494
shemminger8ed63ab2005-09-21 19:33:17 +0000495int rtnl_listen(struct rtnl_handle *rtnl,
Nicolas Dichtel0628cdd2015-05-20 16:19:58 +0200496 rtnl_listen_filter_t handler,
osdl.net!shemminger6dc9f012004-08-31 17:45:21 +0000497 void *jarg)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000498{
499 int status;
500 struct nlmsghdr *h;
501 struct sockaddr_nl nladdr;
502 struct iovec iov;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000503 struct msghdr msg = {
shemminger8ed63ab2005-09-21 19:33:17 +0000504 .msg_name = &nladdr,
505 .msg_namelen = sizeof(nladdr),
506 .msg_iov = &iov,
507 .msg_iovlen = 1,
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000508 };
Eric Dumazete5572122014-10-11 09:43:13 -0700509 char buf[16384];
Nicolas Dichtel449b8242015-05-20 16:20:00 +0200510 char cmsgbuf[BUFSIZ];
511
512 if (rtnl->flags & RTNL_HANDLE_F_LISTEN_ALL_NSID) {
513 msg.msg_control = &cmsgbuf;
514 msg.msg_controllen = sizeof(cmsgbuf);
515 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000516
517 memset(&nladdr, 0, sizeof(nladdr));
518 nladdr.nl_family = AF_NETLINK;
519 nladdr.nl_pid = 0;
520 nladdr.nl_groups = 0;
521
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000522 iov.iov_base = buf;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000523 while (1) {
Nicolas Dichtel449b8242015-05-20 16:20:00 +0200524 struct rtnl_ctrl_data ctrl;
525 struct cmsghdr *cmsg;
526
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000527 iov.iov_len = sizeof(buf);
528 status = recvmsg(rtnl->fd, &msg, 0);
529
530 if (status < 0) {
Stephen Hemmingeraa8032e2008-01-25 15:39:09 -0800531 if (errno == EINTR || errno == EAGAIN)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000532 continue;
Stephen Hemmingeraa8032e2008-01-25 15:39:09 -0800533 fprintf(stderr, "netlink receive error %s (%d)\n",
534 strerror(errno), errno);
Patrick McHardy7f031912009-10-28 20:50:48 +0100535 if (errno == ENOBUFS)
536 continue;
Stephen Hemmingeraa8032e2008-01-25 15:39:09 -0800537 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000538 }
539 if (status == 0) {
540 fprintf(stderr, "EOF on netlink\n");
541 return -1;
542 }
543 if (msg.msg_namelen != sizeof(nladdr)) {
544 fprintf(stderr, "Sender address length == %d\n", msg.msg_namelen);
545 exit(1);
546 }
Nicolas Dichtel449b8242015-05-20 16:20:00 +0200547
548 if (rtnl->flags & RTNL_HANDLE_F_LISTEN_ALL_NSID) {
549 memset(&ctrl, 0, sizeof(ctrl));
550 ctrl.nsid = -1;
551 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg;
552 cmsg = CMSG_NXTHDR(&msg, cmsg))
553 if (cmsg->cmsg_level == SOL_NETLINK &&
554 cmsg->cmsg_type == NETLINK_LISTEN_ALL_NSID &&
555 cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
556 int *data = (int *)CMSG_DATA(cmsg);
557
558 ctrl.nsid = *data;
559 }
560 }
561
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000562 for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
563 int err;
564 int len = h->nlmsg_len;
565 int l = len - sizeof(*h);
566
567 if (l<0 || len>status) {
568 if (msg.msg_flags & MSG_TRUNC) {
569 fprintf(stderr, "Truncated message\n");
570 return -1;
571 }
572 fprintf(stderr, "!!!malformed message: len=%d\n", len);
573 exit(1);
574 }
575
Nicolas Dichtel449b8242015-05-20 16:20:00 +0200576 err = handler(&nladdr, &ctrl, h, jarg);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000577 if (err < 0)
578 return err;
579
580 status -= NLMSG_ALIGN(len);
581 h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
582 }
583 if (msg.msg_flags & MSG_TRUNC) {
584 fprintf(stderr, "Message truncated\n");
585 continue;
586 }
587 if (status) {
588 fprintf(stderr, "!!!Remnant of size %d\n", status);
589 exit(1);
590 }
591 }
592}
593
Nicolas Dichtel0628cdd2015-05-20 16:19:58 +0200594int rtnl_from_file(FILE *rtnl, rtnl_listen_filter_t handler,
osdl.net!shemminger6dc9f012004-08-31 17:45:21 +0000595 void *jarg)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000596{
597 int status;
598 struct sockaddr_nl nladdr;
Eric Dumazete5572122014-10-11 09:43:13 -0700599 char buf[16384];
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000600 struct nlmsghdr *h = (void*)buf;
601
602 memset(&nladdr, 0, sizeof(nladdr));
603 nladdr.nl_family = AF_NETLINK;
604 nladdr.nl_pid = 0;
605 nladdr.nl_groups = 0;
606
607 while (1) {
Stephen Hemminger2dd9f8e2011-06-20 14:34:46 -0700608 int err, len;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000609 int l;
610
611 status = fread(&buf, 1, sizeof(*h), rtnl);
612
613 if (status < 0) {
614 if (errno == EINTR)
615 continue;
616 perror("rtnl_from_file: fread");
617 return -1;
618 }
619 if (status == 0)
620 return 0;
621
622 len = h->nlmsg_len;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000623 l = len - sizeof(*h);
624
625 if (l<0 || len>sizeof(buf)) {
626 fprintf(stderr, "!!!malformed message: len=%d @%lu\n",
627 len, ftell(rtnl));
628 return -1;
629 }
630
631 status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl);
632
633 if (status < 0) {
634 perror("rtnl_from_file: fread");
635 return -1;
636 }
637 if (status < l) {
638 fprintf(stderr, "rtnl-from_file: truncated message\n");
639 return -1;
640 }
641
Nicolas Dichtel0628cdd2015-05-20 16:19:58 +0200642 err = handler(&nladdr, NULL, h, jarg);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000643 if (err < 0)
644 return err;
645 }
646}
647
Stephen Hemminger2aa3dd22011-12-23 10:43:54 -0800648int addattr(struct nlmsghdr *n, int maxlen, int type)
649{
650 return addattr_l(n, maxlen, type, NULL, 0);
651}
652
653int addattr8(struct nlmsghdr *n, int maxlen, int type, __u8 data)
654{
655 return addattr_l(n, maxlen, type, &data, sizeof(__u8));
656}
657
658int addattr16(struct nlmsghdr *n, int maxlen, int type, __u16 data)
659{
660 return addattr_l(n, maxlen, type, &data, sizeof(__u16));
661}
662
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000663int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data)
664{
Stephen Hemminger2aa3dd22011-12-23 10:43:54 -0800665 return addattr_l(n, maxlen, type, &data, sizeof(__u32));
666}
667
668int addattr64(struct nlmsghdr *n, int maxlen, int type, __u64 data)
669{
670 return addattr_l(n, maxlen, type, &data, sizeof(__u64));
671}
672
673int addattrstrz(struct nlmsghdr *n, int maxlen, int type, const char *str)
674{
675 return addattr_l(n, maxlen, type, str, strlen(str)+1);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000676}
677
shemminger8ed63ab2005-09-21 19:33:17 +0000678int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
osdl.net!shemminger6dc9f012004-08-31 17:45:21 +0000679 int alen)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000680{
681 int len = RTA_LENGTH(alen);
682 struct rtattr *rta;
683
net[shemminger]!shemminger3dabdbb2005-03-30 18:18:12 +0000684 if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) {
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000685 fprintf(stderr, "addattr_l ERROR: message exceeded bound of %d\n",maxlen);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000686 return -1;
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000687 }
6!tgraf07f94362005-01-18 13:58:49 +0000688 rta = NLMSG_TAIL(n);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000689 rta->rta_type = type;
690 rta->rta_len = len;
691 memcpy(RTA_DATA(rta), data, alen);
net[shemminger]!shemminger3dabdbb2005-03-30 18:18:12 +0000692 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000693 return 0;
694}
695
6!tgraf07f94362005-01-18 13:58:49 +0000696int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len)
697{
698 if (NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len) > maxlen) {
699 fprintf(stderr, "addraw_l ERROR: message exceeded bound of %d\n",maxlen);
700 return -1;
701 }
702
703 memcpy(NLMSG_TAIL(n), data, len);
704 memset((void *) NLMSG_TAIL(n) + len, 0, NLMSG_ALIGN(len) - len);
705 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len);
706 return 0;
707}
708
Patrick McHardy2f90c9c2007-08-14 11:21:19 -0700709struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type)
710{
711 struct rtattr *nest = NLMSG_TAIL(n);
712
713 addattr_l(n, maxlen, type, NULL, 0);
714 return nest;
715}
716
717int addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest)
718{
719 nest->rta_len = (void *)NLMSG_TAIL(n) - (void *)nest;
720 return n->nlmsg_len;
721}
722
723struct rtattr *addattr_nest_compat(struct nlmsghdr *n, int maxlen, int type,
724 const void *data, int len)
725{
726 struct rtattr *start = NLMSG_TAIL(n);
727
728 addattr_l(n, maxlen, type, data, len);
729 addattr_nest(n, maxlen, type);
730 return start;
731}
732
733int addattr_nest_compat_end(struct nlmsghdr *n, struct rtattr *start)
734{
735 struct rtattr *nest = (void *)start + NLMSG_ALIGN(start->rta_len);
736
737 start->rta_len = (void *)NLMSG_TAIL(n) - (void *)start;
738 addattr_nest_end(n, nest);
739 return n->nlmsg_len;
740}
741
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000742int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data)
743{
744 int len = RTA_LENGTH(4);
745 struct rtattr *subrta;
746
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000747 if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
748 fprintf(stderr,"rta_addattr32: Error! max allowed bound %d exceeded\n",maxlen);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000749 return -1;
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000750 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000751 subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
752 subrta->rta_type = type;
753 subrta->rta_len = len;
754 memcpy(RTA_DATA(subrta), &data, 4);
755 rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
756 return 0;
757}
758
shemminger8ed63ab2005-09-21 19:33:17 +0000759int rta_addattr_l(struct rtattr *rta, int maxlen, int type,
osdl.net!shemminger6dc9f012004-08-31 17:45:21 +0000760 const void *data, int alen)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000761{
762 struct rtattr *subrta;
763 int len = RTA_LENGTH(alen);
764
net[shemminger]!shemminger3dabdbb2005-03-30 18:18:12 +0000765 if (RTA_ALIGN(rta->rta_len) + RTA_ALIGN(len) > maxlen) {
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000766 fprintf(stderr,"rta_addattr_l: Error! max allowed bound %d exceeded\n",maxlen);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000767 return -1;
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000768 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000769 subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
770 subrta->rta_type = type;
771 subrta->rta_len = len;
772 memcpy(RTA_DATA(subrta), data, alen);
net[shemminger]!shemminger3dabdbb2005-03-30 18:18:12 +0000773 rta->rta_len = NLMSG_ALIGN(rta->rta_len) + RTA_ALIGN(len);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000774 return 0;
775}
776
Roopa Prabhu303cc9c2015-10-15 13:13:38 +0200777int rta_addattr8(struct rtattr *rta, int maxlen, int type, __u8 data)
778{
779 return rta_addattr_l(rta, maxlen, type, &data, sizeof(__u8));
780}
781
782int rta_addattr16(struct rtattr *rta, int maxlen, int type, __u16 data)
783{
784 return rta_addattr_l(rta, maxlen, type, &data, sizeof(__u16));
785}
786
787int rta_addattr64(struct rtattr *rta, int maxlen, int type, __u64 data)
788{
789 return rta_addattr_l(rta, maxlen, type, &data, sizeof(__u64));
790}
791
792struct rtattr *rta_nest(struct rtattr *rta, int maxlen, int type)
793{
794 struct rtattr *nest = RTA_TAIL(rta);
795
796 rta_addattr_l(rta, maxlen, type, NULL, 0);
797
798 return nest;
799}
800
801int rta_nest_end(struct rtattr *rta, struct rtattr *nest)
802{
803 nest->rta_len = (void *)RTA_TAIL(rta) - (void *)nest;
804
805 return rta->rta_len;
806}
807
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000808int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
809{
Vlad Yasevichb1b7ce02013-03-15 10:01:28 -0700810 return parse_rtattr_flags(tb, max, rta, len, 0);
811}
812
813int parse_rtattr_flags(struct rtattr *tb[], int max, struct rtattr *rta,
814 int len, unsigned short flags)
815{
816 unsigned short type;
817
osdl.net!shemminger175e2442005-02-07 18:17:38 +0000818 memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000819 while (RTA_OK(rta, len)) {
Vlad Yasevichb1b7ce02013-03-15 10:01:28 -0700820 type = rta->rta_type & ~flags;
821 if ((type <= max) && (!tb[type]))
822 tb[type] = rta;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000823 rta = RTA_NEXT(rta,len);
824 }
825 if (len)
826 fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
827 return 0;
828}
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000829
830int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int len)
831{
832 int i = 0;
osdl.net!shemminger175e2442005-02-07 18:17:38 +0000833
834 memset(tb, 0, sizeof(struct rtattr *) * max);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000835 while (RTA_OK(rta, len)) {
osdl.net!shemminger175e2442005-02-07 18:17:38 +0000836 if (rta->rta_type <= max && i < max)
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000837 tb[i++] = rta;
838 rta = RTA_NEXT(rta,len);
839 }
840 if (len)
841 fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
842 return i;
843}
Patrick McHardy2f90c9c2007-08-14 11:21:19 -0700844
Jiri Pirkodecbb432015-01-06 17:23:45 +0100845struct rtattr *parse_rtattr_one(int type, struct rtattr *rta, int len)
846{
847 while (RTA_OK(rta, len)) {
848 if (rta->rta_type == type)
849 return rta;
850 rta = RTA_NEXT(rta, len);
851 }
852 if (len)
853 fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
854 return NULL;
855}
856
Patrick McHardy2f90c9c2007-08-14 11:21:19 -0700857int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, struct rtattr *rta,
858 int len)
859{
860 if (RTA_PAYLOAD(rta) < len)
861 return -1;
862 if (RTA_PAYLOAD(rta) >= RTA_ALIGN(len) + sizeof(struct rtattr)) {
863 rta = RTA_DATA(rta) + RTA_ALIGN(len);
864 return parse_rtattr_nested(tb, max, rta);
865 }
Stephen Hemminger037c6352007-12-10 11:34:40 -0800866 memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
Patrick McHardy2f90c9c2007-08-14 11:21:19 -0700867 return 0;
868}