]> rtime.felk.cvut.cz Git - lisovros/iproute2_canprio.git/blob - lib/libnetlink.c
When assigning an ip address to an ethernet adapter, the newest
[lisovros/iproute2_canprio.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                                 continue;
312                         }
313
314                         if (h->nlmsg_type == NLMSG_ERROR) {
315                                 struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
316                                 if (l < sizeof(struct nlmsgerr)) {
317                                         fprintf(stderr, "ERROR truncated\n");
318                                 } else {
319                                         errno = -err->error;
320                                         if (errno == 0) {
321                                                 if (answer)
322                                                         memcpy(answer, h, h->nlmsg_len);
323                                                 return 0;
324                                         }
325                                         perror("RTNETLINK answers");
326                                 }
327                                 return -1;
328                         }
329                         if (answer) {
330                                 memcpy(answer, h, h->nlmsg_len);
331                                 return 0;
332                         }
333
334                         fprintf(stderr, "Unexpected reply!!!\n");
335
336                         status -= NLMSG_ALIGN(len);
337                         h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
338                 }
339                 if (msg.msg_flags & MSG_TRUNC) {
340                         fprintf(stderr, "Message truncated\n");
341                         continue;
342                 }
343                 if (status) {
344                         fprintf(stderr, "!!!Remnant of size %d\n", status);
345                         exit(1);
346                 }
347         }
348 }
349
350 int rtnl_listen(struct rtnl_handle *rtnl,
351                 rtnl_filter_t handler,
352                 void *jarg)
353 {
354         int status;
355         struct nlmsghdr *h;
356         struct sockaddr_nl nladdr;
357         struct iovec iov;
358         struct msghdr msg = {
359                 .msg_name = &nladdr,
360                 .msg_namelen = sizeof(nladdr),
361                 .msg_iov = &iov,
362                 .msg_iovlen = 1,
363         };
364         char   buf[8192];
365
366         memset(&nladdr, 0, sizeof(nladdr));
367         nladdr.nl_family = AF_NETLINK;
368         nladdr.nl_pid = 0;
369         nladdr.nl_groups = 0;
370
371         iov.iov_base = buf;
372         while (1) {
373                 iov.iov_len = sizeof(buf);
374                 status = recvmsg(rtnl->fd, &msg, 0);
375
376                 if (status < 0) {
377                         if (errno == EINTR)
378                                 continue;
379                         perror("OVERRUN");
380                         continue;
381                 }
382                 if (status == 0) {
383                         fprintf(stderr, "EOF on netlink\n");
384                         return -1;
385                 }
386                 if (msg.msg_namelen != sizeof(nladdr)) {
387                         fprintf(stderr, "Sender address length == %d\n", msg.msg_namelen);
388                         exit(1);
389                 }
390                 for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
391                         int err;
392                         int len = h->nlmsg_len;
393                         int l = len - sizeof(*h);
394
395                         if (l<0 || len>status) {
396                                 if (msg.msg_flags & MSG_TRUNC) {
397                                         fprintf(stderr, "Truncated message\n");
398                                         return -1;
399                                 }
400                                 fprintf(stderr, "!!!malformed message: len=%d\n", len);
401                                 exit(1);
402                         }
403
404                         err = handler(&nladdr, h, jarg);
405                         if (err < 0)
406                                 return err;
407
408                         status -= NLMSG_ALIGN(len);
409                         h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
410                 }
411                 if (msg.msg_flags & MSG_TRUNC) {
412                         fprintf(stderr, "Message truncated\n");
413                         continue;
414                 }
415                 if (status) {
416                         fprintf(stderr, "!!!Remnant of size %d\n", status);
417                         exit(1);
418                 }
419         }
420 }
421
422 int rtnl_from_file(FILE *rtnl, rtnl_filter_t handler,
423                    void *jarg)
424 {
425         int status;
426         struct sockaddr_nl nladdr;
427         char   buf[8192];
428         struct nlmsghdr *h = (void*)buf;
429
430         memset(&nladdr, 0, sizeof(nladdr));
431         nladdr.nl_family = AF_NETLINK;
432         nladdr.nl_pid = 0;
433         nladdr.nl_groups = 0;
434
435         while (1) {
436                 int err, len, type;
437                 int l;
438
439                 status = fread(&buf, 1, sizeof(*h), rtnl);
440
441                 if (status < 0) {
442                         if (errno == EINTR)
443                                 continue;
444                         perror("rtnl_from_file: fread");
445                         return -1;
446                 }
447                 if (status == 0)
448                         return 0;
449
450                 len = h->nlmsg_len;
451                 type= h->nlmsg_type;
452                 l = len - sizeof(*h);
453
454                 if (l<0 || len>sizeof(buf)) {
455                         fprintf(stderr, "!!!malformed message: len=%d @%lu\n",
456                                 len, ftell(rtnl));
457                         return -1;
458                 }
459
460                 status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl);
461
462                 if (status < 0) {
463                         perror("rtnl_from_file: fread");
464                         return -1;
465                 }
466                 if (status < l) {
467                         fprintf(stderr, "rtnl-from_file: truncated message\n");
468                         return -1;
469                 }
470
471                 err = handler(&nladdr, h, jarg);
472                 if (err < 0)
473                         return err;
474         }
475 }
476
477 int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data)
478 {
479         int len = RTA_LENGTH(4);
480         struct rtattr *rta;
481         if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) {
482                 fprintf(stderr,"addattr32: Error! max allowed bound %d exceeded\n",maxlen);
483                 return -1;
484         }
485         rta = NLMSG_TAIL(n);
486         rta->rta_type = type;
487         rta->rta_len = len;
488         memcpy(RTA_DATA(rta), &data, 4);
489         n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
490         return 0;
491 }
492
493 int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
494               int alen)
495 {
496         int len = RTA_LENGTH(alen);
497         struct rtattr *rta;
498
499         if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) {
500                 fprintf(stderr, "addattr_l ERROR: message exceeded bound of %d\n",maxlen);
501                 return -1;
502         }
503         rta = NLMSG_TAIL(n);
504         rta->rta_type = type;
505         rta->rta_len = len;
506         memcpy(RTA_DATA(rta), data, alen);
507         n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
508         return 0;
509 }
510
511 int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len)
512 {
513         if (NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len) > maxlen) {
514                 fprintf(stderr, "addraw_l ERROR: message exceeded bound of %d\n",maxlen);
515                 return -1;
516         }
517
518         memcpy(NLMSG_TAIL(n), data, len);
519         memset((void *) NLMSG_TAIL(n) + len, 0, NLMSG_ALIGN(len) - len);
520         n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len);
521         return 0;
522 }
523
524 int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data)
525 {
526         int len = RTA_LENGTH(4);
527         struct rtattr *subrta;
528
529         if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
530                 fprintf(stderr,"rta_addattr32: Error! max allowed bound %d exceeded\n",maxlen);
531                 return -1;
532         }
533         subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
534         subrta->rta_type = type;
535         subrta->rta_len = len;
536         memcpy(RTA_DATA(subrta), &data, 4);
537         rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
538         return 0;
539 }
540
541 int rta_addattr_l(struct rtattr *rta, int maxlen, int type,
542                   const void *data, int alen)
543 {
544         struct rtattr *subrta;
545         int len = RTA_LENGTH(alen);
546
547         if (RTA_ALIGN(rta->rta_len) + RTA_ALIGN(len) > maxlen) {
548                 fprintf(stderr,"rta_addattr_l: Error! max allowed bound %d exceeded\n",maxlen);
549                 return -1;
550         }
551         subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
552         subrta->rta_type = type;
553         subrta->rta_len = len;
554         memcpy(RTA_DATA(subrta), data, alen);
555         rta->rta_len = NLMSG_ALIGN(rta->rta_len) + RTA_ALIGN(len);
556         return 0;
557 }
558
559 int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
560 {
561         memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
562         while (RTA_OK(rta, len)) {
563                 if (rta->rta_type <= max)
564                         tb[rta->rta_type] = rta;
565                 rta = RTA_NEXT(rta,len);
566         }
567         if (len)
568                 fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
569         return 0;
570 }
571
572 int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int len)
573 {
574         int i = 0;
575
576         memset(tb, 0, sizeof(struct rtattr *) * max);
577         while (RTA_OK(rta, len)) {
578                 if (rta->rta_type <= max && i < max)
579                         tb[i++] = rta;
580                 rta = RTA_NEXT(rta,len);
581         }
582         if (len)
583                 fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
584         return i;
585 }