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