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