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