Line | Count | Source (jump to first uncovered line) |
1 | | /* Simple LPGLed rtnetlink library */ |
2 | | #include <sys/socket.h> |
3 | | #include <linux/rtnetlink.h> |
4 | | #include <linux/netlink.h> |
5 | | #include <netinet/in.h> |
6 | | #include <errno.h> |
7 | | #include <unistd.h> |
8 | | #define hidden __attribute__((visibility("hidden"))) |
9 | | #include "rtnetlink.h" |
10 | | |
11 | | hidden void *rta_put(struct nlmsghdr *m, int type, int len) |
12 | 2 | { |
13 | 2 | struct rtattr *rta = (void *)m + NLMSG_ALIGN(m->nlmsg_len); |
14 | 2 | int rtalen = RTA_LENGTH(len); |
15 | | |
16 | 2 | rta->rta_type = type; |
17 | 2 | rta->rta_len = rtalen; |
18 | 2 | m->nlmsg_len = NLMSG_ALIGN(m->nlmsg_len) + RTA_ALIGN(rtalen); |
19 | 2 | return RTA_DATA(rta); |
20 | 2 | } |
21 | | |
22 | | hidden struct rtattr *rta_get(struct nlmsghdr *m, struct rtattr *p, int offset) |
23 | 6 | { |
24 | 6 | struct rtattr *rta; |
25 | | |
26 | 6 | if (p) { |
27 | 4 | rta = RTA_NEXT(p, m->nlmsg_len); |
28 | 4 | if (!RTA_OK(rta, m->nlmsg_len)) |
29 | 0 | return NULL; |
30 | 4 | } else { |
31 | 2 | rta = (void *)m + NLMSG_ALIGN(offset); |
32 | 2 | } |
33 | 6 | return rta; |
34 | 6 | } |
35 | | |
36 | | hidden int |
37 | | rta_put_address(struct nlmsghdr *msg, int type, struct sockaddr *adr) |
38 | 2 | { |
39 | 2 | switch (adr->sa_family) { |
40 | 2 | case AF_INET: { |
41 | 2 | struct in_addr *i = rta_put(msg, type, 4); |
42 | 2 | *i = ((struct sockaddr_in *)adr)->sin_addr; |
43 | 2 | break; |
44 | 0 | } |
45 | 0 | case AF_INET6: { |
46 | 0 | struct in6_addr *i6 = rta_put(msg, type, 16); |
47 | 0 | *i6 = ((struct sockaddr_in6 *)adr)->sin6_addr; |
48 | 0 | break; |
49 | 0 | } |
50 | 0 | default: |
51 | 0 | return -1; |
52 | 2 | } |
53 | 2 | return 0; |
54 | 2 | } |
55 | | |
56 | | /* Assumes no truncation. Make the buffer large enough. */ |
57 | | hidden int |
58 | | rtnetlink_request(struct nlmsghdr *msg, int buflen, struct sockaddr_nl *adr) |
59 | 2 | { |
60 | 2 | int rsk; |
61 | 2 | int n; |
62 | 2 | int e; |
63 | | |
64 | | /* Use a private socket to avoid having to keep state |
65 | | for a sequence number. */ |
66 | 2 | rsk = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); |
67 | 2 | if (rsk < 0) |
68 | 0 | return -1; |
69 | 2 | n = sendto(rsk, msg, msg->nlmsg_len, 0, (struct sockaddr *)adr, |
70 | 2 | sizeof(struct sockaddr_nl)); |
71 | 2 | if (n >= 0) { |
72 | 2 | socklen_t adrlen = sizeof(struct sockaddr_nl); |
73 | 2 | n = recvfrom(rsk, msg, buflen, 0, (struct sockaddr *)adr, |
74 | 2 | &adrlen); |
75 | 2 | } |
76 | 2 | e = errno; |
77 | 2 | close(rsk); |
78 | 2 | errno = e; |
79 | 2 | if (n < 0) |
80 | 0 | return -1; |
81 | | /* Assume we only get a single reply back. This is (hopefully?) |
82 | | safe because it's a single use socket. */ |
83 | 2 | if (msg->nlmsg_type == NLMSG_ERROR) { |
84 | 0 | struct nlmsgerr *err = NLMSG_DATA(msg); |
85 | 0 | errno = -err->error; |
86 | 0 | return -1; |
87 | 0 | } |
88 | 2 | return 0; |
89 | 2 | } |