Branch data Line data Source code
1 : : #include <linux/types.h>
2 : : #include <sys/socket.h>
3 : : #include <linux/netlink.h>
4 : : #include <linux/rtnetlink.h>
5 : : #include <string.h>
6 : : #include <unistd.h>
7 : :
8 : : #include "libnetlink.h"
9 : : #include "util.h"
10 : :
11 : 173364 : int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
12 : : {
13 : 173364 : memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
14 [ + + ][ + - ]: 686288 : while (RTA_OK(rta, len)) {
[ + - ]
15 [ + - ][ + - ]: 512924 : if ((rta->rta_type <= max) && (!tb[rta->rta_type]))
16 : 512924 : tb[rta->rta_type] = rta;
17 : 512924 : rta = RTA_NEXT(rta, len);
18 : : }
19 [ - + ]: 173364 : if (len)
20 : 0 : pr_warn("Trimmed RTA: len %d, rta_len %d\n", len, rta->rta_len);
21 : 173364 : return 0;
22 : : }
23 : :
24 : 9259 : static int nlmsg_receive(char *buf, int len, int (*cb)(struct nlmsghdr *, void *), void *arg)
25 : : {
26 : : struct nlmsghdr *hdr;
27 : :
28 [ + + ][ + - ]: 182623 : for (hdr = (struct nlmsghdr *)buf; NLMSG_OK(hdr, len); hdr = NLMSG_NEXT(hdr, len)) {
[ + - ]
29 [ - + ]: 177842 : if (hdr->nlmsg_seq != CR_NLMSG_SEQ)
30 : 0 : continue;
31 [ + + ]: 177842 : if (hdr->nlmsg_type == NLMSG_DONE) {
32 : : int *len = (int *)NLMSG_DATA(hdr);
33 : :
34 [ - + ]: 4264 : if (*len < 0) {
35 : 0 : pr_err("ERROR %d reported by netlink (%s)\n",
36 : : *len, strerror(-*len));
37 : 0 : return *len;
38 : : }
39 : :
40 : : return 0;
41 : : }
42 [ + + ]: 173578 : if (hdr->nlmsg_type == NLMSG_ERROR) {
43 : : struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(hdr);
44 : :
45 [ - + ]: 214 : if (hdr->nlmsg_len - sizeof(*hdr) < sizeof(struct nlmsgerr)) {
46 : 0 : pr_err("ERROR truncated\n");
47 : 0 : return -1;
48 : : }
49 : :
50 [ - + ]: 214 : if (err->error == 0)
51 : : return 0;
52 : :
53 : 0 : pr_warn("ERROR %d reported by netlink\n", err->error);
54 : 0 : return err->error;
55 : : }
56 [ + - ]: 173364 : if (cb(hdr, arg))
57 : : return -1;
58 : : }
59 : :
60 : : return 1;
61 : : }
62 : :
63 : 4478 : int do_rtnl_req(int nl, void *req, int size,
64 : : int (*receive_callback)(struct nlmsghdr *h, void *), void *arg)
65 : : {
66 : : struct msghdr msg;
67 : : struct sockaddr_nl nladdr;
68 : : struct iovec iov;
69 : : static char buf[4096];
70 : : int err;
71 : :
72 : : memset(&msg, 0, sizeof(msg));
73 : 4478 : msg.msg_name = &nladdr;
74 : 4478 : msg.msg_namelen = sizeof(nladdr);
75 : 4478 : msg.msg_iov = &iov;
76 : 4478 : msg.msg_iovlen = 1;
77 : :
78 : : memset(&nladdr, 0, sizeof(nladdr));
79 : 4478 : nladdr.nl_family = AF_NETLINK;
80 : :
81 : 4478 : iov.iov_base = req;
82 : 4478 : iov.iov_len = size;
83 : :
84 [ - + ]: 4478 : if (sendmsg(nl, &msg, 0) < 0) {
85 : 0 : err = -errno;
86 : 0 : pr_perror("Can't send request message");
87 : 0 : goto err;
88 : : }
89 : :
90 : 4478 : iov.iov_base = buf;
91 : 9259 : iov.iov_len = sizeof(buf);
92 : :
93 : : while (1) {
94 : :
95 : : memset(&msg, 0, sizeof(msg));
96 : 9259 : msg.msg_name = &nladdr;
97 : 9259 : msg.msg_namelen = sizeof(nladdr);
98 : 9259 : msg.msg_iov = &iov;
99 : 9259 : msg.msg_iovlen = 1;
100 : :
101 : 9259 : err = recvmsg(nl, &msg, 0);
102 [ - + ]: 9259 : if (err < 0) {
103 [ # # ]: 0 : if (errno == EINTR)
104 : 0 : continue;
105 : : else {
106 : 0 : err = -errno;
107 : 0 : pr_perror("Error receiving nl report");
108 : 0 : goto err;
109 : : }
110 : : }
111 [ + - ]: 9259 : if (err == 0)
112 : : break;
113 : :
114 : 9259 : err = nlmsg_receive(buf, err, receive_callback, arg);
115 [ + - ]: 9259 : if (err < 0)
116 : : goto err;
117 [ + + ]: 9259 : if (err == 0)
118 : : break;
119 : : }
120 : :
121 : : return 0;
122 : :
123 : : err:
124 : 0 : return err;
125 : : }
126 : :
127 : 428 : int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
128 : : int alen)
129 : : {
130 : 428 : int len = RTA_LENGTH(alen);
131 : : struct rtattr *rta;
132 : :
133 [ - + ]: 428 : if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) {
134 : 0 : pr_err("addattr_l ERROR: message exceeded bound of %d\n", maxlen);
135 : 0 : return -1;
136 : : }
137 : :
138 : 428 : rta = NLMSG_TAIL(n);
139 : 428 : rta->rta_type = type;
140 : 428 : rta->rta_len = len;
141 : 428 : memcpy(RTA_DATA(rta), data, alen);
142 : 428 : n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
143 : 428 : return 0;
144 : : }
|