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