fix systemd unit install path
[external/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(rth));
45
46         rth->fd = socket(AF_NETLINK, SOCK_RAW, 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 = recvmsg(rth->fd, &msg, 0);
175
176                 if (status < 0) {
177                         if (errno == EINTR)
178                                 continue;
179                         perror("OVERRUN");
180                         continue;
181                 }
182
183                 if (status == 0) {
184                         fprintf(stderr, "EOF on netlink\n");
185                         return -1;
186                 }
187
188                 h = (struct nlmsghdr*)buf;
189                 while (NLMSG_OK(h, (unsigned)status)) {
190                         int err;
191
192                         if (nladdr.nl_pid != 0 ||
193                             h->nlmsg_pid != rth->local.nl_pid ||
194                             h->nlmsg_seq != rth->dump) {
195                                 if (junk) {
196                                         err = junk(&nladdr, h, arg2);
197                                         if (err < 0)
198                                                 return err;
199                                 }
200                                 goto skip_it;
201                         }
202
203                         if (h->nlmsg_type == NLMSG_DONE)
204                                 return 0;
205                         if (h->nlmsg_type == NLMSG_ERROR) {
206                                 struct nlmsgerr *msgerr = (struct nlmsgerr*)NLMSG_DATA(h);
207                                 if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
208                                         fprintf(stderr, "ERROR truncated\n");
209                                 } else {
210                                         errno = -msgerr->error;
211                                         perror("RTNETLINK answers");
212                                 }
213                                 return -1;
214                         }
215                         err = filter(&nladdr, h, arg1);
216                         if (err < 0)
217                                 return err;
218
219 skip_it:
220                         h = NLMSG_NEXT(h, status);
221                 }
222                 if (msg.msg_flags & MSG_TRUNC) {
223                         fprintf(stderr, "Message truncated\n");
224                         continue;
225                 }
226                 if (status) {
227                         fprintf(stderr, "!!!Remnant of size %d\n", status);
228                         exit(1);
229                 }
230         }
231 }
232
233 int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
234               unsigned groups, struct nlmsghdr *answer,
235               rtnl_filter_t junk,
236               void *jarg)
237 {
238         int status;
239         unsigned seq;
240         struct nlmsghdr *h;
241         struct sockaddr_nl nladdr;
242         struct iovec iov = {
243                 .iov_base = (void*) n,
244                 .iov_len = n->nlmsg_len
245         };
246         struct msghdr msg = {
247                 .msg_name = &nladdr,
248                 .msg_namelen = sizeof(nladdr),
249                 .msg_iov = &iov,
250                 .msg_iovlen = 1,
251         };
252         char   buf[16384];
253
254         memset(&nladdr, 0, sizeof(nladdr));
255         nladdr.nl_family = AF_NETLINK;
256         nladdr.nl_pid = peer;
257         nladdr.nl_groups = groups;
258
259         n->nlmsg_seq = seq = ++rtnl->seq;
260
261         if (answer == NULL)
262                 n->nlmsg_flags |= NLM_F_ACK;
263
264         status = sendmsg(rtnl->fd, &msg, 0);
265
266         if (status < 0) {
267                 perror("Cannot talk to rtnetlink");
268                 return -1;
269         }
270
271         memset(buf,0,sizeof(buf));
272
273         iov.iov_base = buf;
274
275         while (1) {
276                 iov.iov_len = sizeof(buf);
277                 status = recvmsg(rtnl->fd, &msg, 0);
278
279                 if (status < 0) {
280                         if (errno == EINTR)
281                                 continue;
282                         perror("OVERRUN");
283                         continue;
284                 }
285                 if (status == 0) {
286                         fprintf(stderr, "EOF on netlink\n");
287                         return -1;
288                 }
289                 if (msg.msg_namelen != sizeof(nladdr)) {
290                         fprintf(stderr, "sender address length == %d\n", msg.msg_namelen);
291                         exit(1);
292                 }
293                 for (h = (struct nlmsghdr*)buf; (unsigned)status >= sizeof(*h); ) {
294                         int err;
295                         int len = h->nlmsg_len;
296                         int l = len - sizeof(*h);
297
298                         if (l<0 || len>status) {
299                                 if (msg.msg_flags & MSG_TRUNC) {
300                                         fprintf(stderr, "Truncated message\n");
301                                         return -1;
302                                 }
303                                 fprintf(stderr, "!!!malformed message: len=%d\n", len);
304                                 exit(1);
305                         }
306
307                         if (nladdr.nl_pid != (unsigned)peer ||
308                             h->nlmsg_pid != rtnl->local.nl_pid ||
309                             h->nlmsg_seq != seq) {
310                                 if (junk) {
311                                         err = junk(&nladdr, h, jarg);
312                                         if (err < 0)
313                                                 return err;
314                                 }
315                                 /* Don't forget to skip that message. */
316                                 status -= NLMSG_ALIGN(len);
317                                 h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
318                                 continue;
319                         }
320
321                         if (h->nlmsg_type == NLMSG_ERROR) {
322                                 struct nlmsgerr *msgerr = (struct nlmsgerr*)NLMSG_DATA(h);
323                                 if ((unsigned)l < sizeof(struct nlmsgerr)) {
324                                         fprintf(stderr, "ERROR truncated\n");
325                                 } else {
326                                         errno = -msgerr->error;
327                                         if (errno == 0) {
328                                                 if (answer)
329                                                         memcpy(answer, h, h->nlmsg_len);
330                                                 return 0;
331                                         }
332                                         perror("RTNETLINK1 answers");
333                                 }
334                                 return -1;
335                         }
336                         if (answer) {
337                                 memcpy(answer, h, h->nlmsg_len);
338                                 return 0;
339                         }
340
341                         fprintf(stderr, "Unexpected reply!!!\n");
342
343                         status -= NLMSG_ALIGN(len);
344                         h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
345                 }
346                 if (msg.msg_flags & MSG_TRUNC) {
347                         fprintf(stderr, "Message truncated\n");
348                         continue;
349                 }
350                 if (status) {
351                         fprintf(stderr, "!!!Remnant of size %d\n", status);
352                         exit(1);
353                 }
354         }
355 }
356
357 int rtnl_listen(struct rtnl_handle *rtnl,
358                 rtnl_filter_t handler,
359                 void *jarg)
360 {
361         int status;
362         struct nlmsghdr *h;
363         struct sockaddr_nl nladdr;
364         struct iovec iov;
365         struct msghdr msg = {
366                 .msg_name = &nladdr,
367                 .msg_namelen = sizeof(nladdr),
368                 .msg_iov = &iov,
369                 .msg_iovlen = 1,
370         };
371         char   buf[8192];
372
373         memset(&nladdr, 0, sizeof(nladdr));
374         nladdr.nl_family = AF_NETLINK;
375         nladdr.nl_pid = 0;
376         nladdr.nl_groups = 0;
377
378         iov.iov_base = buf;
379         while (1) {
380                 iov.iov_len = sizeof(buf);
381                 status = recvmsg(rtnl->fd, &msg, 0);
382
383                 if (status < 0) {
384                         if (errno == EINTR)
385                                 continue;
386                         perror("OVERRUN");
387                         continue;
388                 }
389                 if (status == 0) {
390                         fprintf(stderr, "EOF on netlink\n");
391                         return -1;
392                 }
393                 if (msg.msg_namelen != sizeof(nladdr)) {
394                         fprintf(stderr, "Sender address length == %d\n", msg.msg_namelen);
395                         exit(1);
396                 }
397                 for (h = (struct nlmsghdr*)buf; (unsigned)status >= sizeof(*h); ) {
398                         int err;
399                         int len = h->nlmsg_len;
400                         int l = len - sizeof(*h);
401
402                         if (l<0 || len>status) {
403                                 if (msg.msg_flags & MSG_TRUNC) {
404                                         fprintf(stderr, "Truncated message\n");
405                                         return -1;
406                                 }
407                                 fprintf(stderr, "!!!malformed message: len=%d\n", len);
408                                 exit(1);
409                         }
410
411                         err = handler(&nladdr, h, jarg);
412                         if (err < 0)
413                                 return err;
414
415                         status -= NLMSG_ALIGN(len);
416                         h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
417                 }
418                 if (msg.msg_flags & MSG_TRUNC) {
419                         fprintf(stderr, "Message truncated\n");
420                         continue;
421                 }
422                 if (status) {
423                         fprintf(stderr, "!!!Remnant of size %d\n", status);
424                         exit(1);
425                 }
426         }
427 }
428
429 int rtnl_from_file(FILE *rtnl, rtnl_filter_t handler,
430                    void *jarg)
431 {
432         int status;
433         struct sockaddr_nl nladdr;
434         char   buf[8192];
435         struct nlmsghdr *h = (void*)buf;
436
437         memset(&nladdr, 0, sizeof(nladdr));
438         nladdr.nl_family = AF_NETLINK;
439         nladdr.nl_pid = 0;
440         nladdr.nl_groups = 0;
441
442         while (1) {
443                 int err, len;
444                 int l;
445
446                 status = fread(&buf, 1, sizeof(*h), rtnl);
447
448                 if (status < 0) {
449                         if (errno == EINTR)
450                                 continue;
451                         perror("rtnl_from_file: fread");
452                         return -1;
453                 }
454                 if (status == 0)
455                         return 0;
456
457                 len = h->nlmsg_len;
458                 l = len - sizeof(*h);
459
460                 if (l<0 || (unsigned)len>sizeof(buf)) {
461                         fprintf(stderr, "!!!malformed message: len=%d @%lu\n",
462                                 len, ftell(rtnl));
463                         return -1;
464                 }
465
466                 status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl);
467
468                 if (status < 0) {
469                         perror("rtnl_from_file: fread");
470                         return -1;
471                 }
472                 if (status < l) {
473                         fprintf(stderr, "rtnl-from_file: truncated message\n");
474                         return -1;
475                 }
476
477                 err = handler(&nladdr, h, jarg);
478                 if (err < 0)
479                         return err;
480         }
481 }
482
483 int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data)
484 {
485         int len = RTA_LENGTH(4);
486         struct rtattr *rta;
487         if ((int)NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) {
488                 fprintf(stderr,"addattr32: Error! max allowed bound %d exceeded\n",maxlen);
489                 return -1;
490         }
491         rta = NLMSG_TAIL(n);
492         rta->rta_type = type;
493         rta->rta_len = len;
494         memcpy(RTA_DATA(rta), &data, 4);
495         n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
496         return 0;
497 }
498
499 int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
500               int alen)
501 {
502         int len = RTA_LENGTH(alen);
503         struct rtattr *rta;
504
505         if ((int)NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) {
506                 fprintf(stderr, "addattr_l ERROR: message exceeded bound of %d\n",maxlen);
507                 return -1;
508         }
509         rta = NLMSG_TAIL(n);
510         rta->rta_type = type;
511         rta->rta_len = len;
512         memcpy(RTA_DATA(rta), data, alen);
513         n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
514         return 0;
515 }
516
517 int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len)
518 {
519         if ((int)NLMSG_ALIGN(n->nlmsg_len) + (int)NLMSG_ALIGN(len) > maxlen) {
520                 fprintf(stderr, "addraw_l ERROR: message exceeded bound of %d\n",maxlen);
521                 return -1;
522         }
523
524         memcpy(NLMSG_TAIL(n), data, len);
525         memset((void *) NLMSG_TAIL(n) + len, 0, NLMSG_ALIGN(len) - len);
526         n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len);
527         return 0;
528 }
529
530 int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data)
531 {
532         int len = RTA_LENGTH(4);
533         struct rtattr *subrta;
534
535         if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
536                 fprintf(stderr,"rta_addattr32: Error! max allowed bound %d exceeded\n",maxlen);
537                 return -1;
538         }
539         subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
540         subrta->rta_type = type;
541         subrta->rta_len = len;
542         memcpy(RTA_DATA(subrta), &data, 4);
543         rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
544         return 0;
545 }
546
547 int rta_addattr_l(struct rtattr *rta, int maxlen, int type,
548                   const void *data, int alen)
549 {
550         struct rtattr *subrta;
551         int len = RTA_LENGTH(alen);
552
553         if (RTA_ALIGN(rta->rta_len) + RTA_ALIGN(len) > maxlen) {
554                 fprintf(stderr,"rta_addattr_l: Error! max allowed bound %d exceeded\n",maxlen);
555                 return -1;
556         }
557         subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
558         subrta->rta_type = type;
559         subrta->rta_len = len;
560         memcpy(RTA_DATA(subrta), data, alen);
561         rta->rta_len = NLMSG_ALIGN(rta->rta_len) + RTA_ALIGN(len);
562         return 0;
563 }
564
565 int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
566 {
567         memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
568         while (RTA_OK(rta, len)) {
569                 if (rta->rta_type <= max)
570                         tb[rta->rta_type] = rta;
571                 rta = RTA_NEXT(rta,len);
572         }
573         if (len)
574                 fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
575         return 0;
576 }
577
578 int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int len)
579 {
580         int i = 0;
581
582         memset(tb, 0, sizeof(struct rtattr *) * max);
583         while (RTA_OK(rta, len)) {
584                 if (rta->rta_type <= max && i < max)
585                         tb[i++] = rta;
586                 rta = RTA_NEXT(rta,len);
587         }
588         if (len)
589                 fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
590         return i;
591 }