source: MondoRescue/branches/3.3/mindi-busybox/networking/libiproute/libnetlink.c@ 3909

Last change on this file since 3909 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

File size: 9.9 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU General Public License
5 * as published by the Free Software Foundation; either version
6 * 2 of the License, or (at your option) any later version.
7 *
8 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
9 */
10
11#include <sys/socket.h>
12#include <sys/uio.h>
13
14#include "libbb.h"
15#include "libnetlink.h"
16
17void FAST_FUNC xrtnl_open(struct rtnl_handle *rth/*, unsigned subscriptions*/)
18{
19 socklen_t addr_len;
20
21 memset(rth, 0, sizeof(*rth));
22 rth->fd = xsocket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
23 rth->local.nl_family = AF_NETLINK;
24 /*rth->local.nl_groups = subscriptions;*/
25
26 xbind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local));
27 addr_len = sizeof(rth->local);
28 getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len);
29
30/* too much paranoia
31 if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0)
32 bb_perror_msg_and_die("getsockname");
33 if (addr_len != sizeof(rth->local))
34 bb_error_msg_and_die("wrong address length %d", addr_len);
35 if (rth->local.nl_family != AF_NETLINK)
36 bb_error_msg_and_die("wrong address family %d", rth->local.nl_family);
37*/
38 rth->seq = time(NULL);
39}
40
41int FAST_FUNC xrtnl_wilddump_request(struct rtnl_handle *rth, int family, int type)
42{
43 struct {
44 struct nlmsghdr nlh;
45 struct rtgenmsg g;
46 } req;
47
48 req.nlh.nlmsg_len = sizeof(req);
49 req.nlh.nlmsg_type = type;
50 req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
51 req.nlh.nlmsg_pid = 0;
52 req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
53 req.g.rtgen_family = family;
54
55 return rtnl_send(rth, (void*)&req, sizeof(req));
56}
57
58//TODO: pass rth->fd instead of full rth?
59int FAST_FUNC rtnl_send(struct rtnl_handle *rth, char *buf, int len)
60{
61 struct sockaddr_nl nladdr;
62
63 memset(&nladdr, 0, sizeof(nladdr));
64 nladdr.nl_family = AF_NETLINK;
65
66 return xsendto(rth->fd, buf, len, (struct sockaddr*)&nladdr, sizeof(nladdr));
67}
68
69int FAST_FUNC rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
70{
71 struct nlmsghdr nlh;
72 struct sockaddr_nl nladdr;
73 struct iovec iov[2] = { { &nlh, sizeof(nlh) }, { req, len } };
74 /* Use designated initializers, struct layout is non-portable */
75 struct msghdr msg = {
76 .msg_name = (void*)&nladdr,
77 .msg_namelen = sizeof(nladdr),
78 .msg_iov = iov,
79 .msg_iovlen = 2,
80 .msg_control = NULL,
81 .msg_controllen = 0,
82 .msg_flags = 0
83 };
84
85 memset(&nladdr, 0, sizeof(nladdr));
86 nladdr.nl_family = AF_NETLINK;
87
88 nlh.nlmsg_len = NLMSG_LENGTH(len);
89 nlh.nlmsg_type = type;
90 nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
91 nlh.nlmsg_pid = 0;
92 nlh.nlmsg_seq = rth->dump = ++rth->seq;
93
94 return sendmsg(rth->fd, &msg, 0);
95}
96
97static int rtnl_dump_filter(struct rtnl_handle *rth,
98 int (*filter)(const struct sockaddr_nl *, struct nlmsghdr *n, void *) FAST_FUNC,
99 void *arg1/*,
100 int (*junk)(struct sockaddr_nl *, struct nlmsghdr *n, void *),
101 void *arg2*/)
102{
103 int retval = -1;
104 char *buf = xmalloc(8*1024); /* avoid big stack buffer */
105 struct sockaddr_nl nladdr;
106 struct iovec iov = { buf, 8*1024 };
107
108 while (1) {
109 int status;
110 struct nlmsghdr *h;
111 /* Use designated initializers, struct layout is non-portable */
112 struct msghdr msg = {
113 .msg_name = (void*)&nladdr,
114 .msg_namelen = sizeof(nladdr),
115 .msg_iov = &iov,
116 .msg_iovlen = 1,
117 .msg_control = NULL,
118 .msg_controllen = 0,
119 .msg_flags = 0
120 };
121
122 status = recvmsg(rth->fd, &msg, 0);
123
124 if (status < 0) {
125 if (errno == EINTR)
126 continue;
127 bb_perror_msg("OVERRUN");
128 continue;
129 }
130 if (status == 0) {
131 bb_error_msg("EOF on netlink");
132 goto ret;
133 }
134 if (msg.msg_namelen != sizeof(nladdr)) {
135 bb_error_msg_and_die("sender address length == %d", msg.msg_namelen);
136 }
137
138 h = (struct nlmsghdr*)buf;
139 while (NLMSG_OK(h, status)) {
140 int err;
141
142 if (nladdr.nl_pid != 0 ||
143 h->nlmsg_pid != rth->local.nl_pid ||
144 h->nlmsg_seq != rth->dump
145 ) {
146// if (junk) {
147// err = junk(&nladdr, h, arg2);
148// if (err < 0) {
149// retval = err;
150// goto ret;
151// }
152// }
153 goto skip_it;
154 }
155
156 if (h->nlmsg_type == NLMSG_DONE) {
157 goto ret_0;
158 }
159 if (h->nlmsg_type == NLMSG_ERROR) {
160 struct nlmsgerr *l_err = (struct nlmsgerr*)NLMSG_DATA(h);
161 if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
162 bb_error_msg("ERROR truncated");
163 } else {
164 errno = -l_err->error;
165 bb_perror_msg("RTNETLINK answers");
166 }
167 goto ret;
168 }
169 err = filter(&nladdr, h, arg1);
170 if (err < 0) {
171 retval = err;
172 goto ret;
173 }
174
175 skip_it:
176 h = NLMSG_NEXT(h, status);
177 }
178 if (msg.msg_flags & MSG_TRUNC) {
179 bb_error_msg("message truncated");
180 continue;
181 }
182 if (status) {
183 bb_error_msg_and_die("remnant of size %d!", status);
184 }
185 } /* while (1) */
186 ret_0:
187 retval++; /* = 0 */
188 ret:
189 free(buf);
190 return retval;
191}
192
193int FAST_FUNC xrtnl_dump_filter(struct rtnl_handle *rth,
194 int (*filter)(const struct sockaddr_nl *, struct nlmsghdr *, void *) FAST_FUNC,
195 void *arg1)
196{
197 int ret = rtnl_dump_filter(rth, filter, arg1/*, NULL, NULL*/);
198 if (ret < 0)
199 bb_error_msg_and_die("dump terminated");
200 return ret;
201}
202
203int FAST_FUNC rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
204 pid_t peer, unsigned groups,
205 struct nlmsghdr *answer,
206 int (*junk)(struct sockaddr_nl *, struct nlmsghdr *, void *),
207 void *jarg)
208{
209/* bbox doesn't use parameters no. 3, 4, 6, 7, they are stubbed out */
210#define peer 0
211#define groups 0
212#define junk NULL
213#define jarg NULL
214 int retval = -1;
215 int status;
216 unsigned seq;
217 struct nlmsghdr *h;
218 struct sockaddr_nl nladdr;
219 struct iovec iov = { (void*)n, n->nlmsg_len };
220 char *buf = xmalloc(8*1024); /* avoid big stack buffer */
221 /* Use designated initializers, struct layout is non-portable */
222 struct msghdr msg = {
223 .msg_name = (void*)&nladdr,
224 .msg_namelen = sizeof(nladdr),
225 .msg_iov = &iov,
226 .msg_iovlen = 1,
227 .msg_control = NULL,
228 .msg_controllen = 0,
229 .msg_flags = 0
230 };
231
232 memset(&nladdr, 0, sizeof(nladdr));
233 nladdr.nl_family = AF_NETLINK;
234// nladdr.nl_pid = peer;
235// nladdr.nl_groups = groups;
236
237 n->nlmsg_seq = seq = ++rtnl->seq;
238 if (answer == NULL) {
239 n->nlmsg_flags |= NLM_F_ACK;
240 }
241 status = sendmsg(rtnl->fd, &msg, 0);
242
243 if (status < 0) {
244 bb_perror_msg("can't talk to rtnetlink");
245 goto ret;
246 }
247
248 iov.iov_base = buf;
249
250 while (1) {
251 iov.iov_len = 8*1024;
252 status = recvmsg(rtnl->fd, &msg, 0);
253
254 if (status < 0) {
255 if (errno == EINTR) {
256 continue;
257 }
258 bb_perror_msg("OVERRUN");
259 continue;
260 }
261 if (status == 0) {
262 bb_error_msg("EOF on netlink");
263 goto ret;
264 }
265 if (msg.msg_namelen != sizeof(nladdr)) {
266 bb_error_msg_and_die("sender address length == %d", msg.msg_namelen);
267 }
268 for (h = (struct nlmsghdr*)buf; status >= (int)sizeof(*h); ) {
269// int l_err;
270 int len = h->nlmsg_len;
271 int l = len - sizeof(*h);
272
273 if (l < 0 || len > status) {
274 if (msg.msg_flags & MSG_TRUNC) {
275 bb_error_msg("truncated message");
276 goto ret;
277 }
278 bb_error_msg_and_die("malformed message: len=%d!", len);
279 }
280
281 if (nladdr.nl_pid != peer ||
282 h->nlmsg_pid != rtnl->local.nl_pid ||
283 h->nlmsg_seq != seq
284 ) {
285// if (junk) {
286// l_err = junk(&nladdr, h, jarg);
287// if (l_err < 0) {
288// retval = l_err;
289// goto ret;
290// }
291// }
292 continue;
293 }
294
295 if (h->nlmsg_type == NLMSG_ERROR) {
296 struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
297 if (l < (int)sizeof(struct nlmsgerr)) {
298 bb_error_msg("ERROR truncated");
299 } else {
300 errno = - err->error;
301 if (errno == 0) {
302 if (answer) {
303 memcpy(answer, h, h->nlmsg_len);
304 }
305 goto ret_0;
306 }
307 bb_perror_msg("RTNETLINK answers");
308 }
309 goto ret;
310 }
311 if (answer) {
312 memcpy(answer, h, h->nlmsg_len);
313 goto ret_0;
314 }
315
316 bb_error_msg("unexpected reply!");
317
318 status -= NLMSG_ALIGN(len);
319 h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
320 }
321 if (msg.msg_flags & MSG_TRUNC) {
322 bb_error_msg("message truncated");
323 continue;
324 }
325 if (status) {
326 bb_error_msg_and_die("remnant of size %d!", status);
327 }
328 } /* while (1) */
329 ret_0:
330 retval++; /* = 0 */
331 ret:
332 free(buf);
333 return retval;
334}
335
336int FAST_FUNC addattr32(struct nlmsghdr *n, int maxlen, int type, uint32_t data)
337{
338 int len = RTA_LENGTH(4);
339 struct rtattr *rta;
340
341 if ((int)(NLMSG_ALIGN(n->nlmsg_len) + len) > maxlen) {
342 return -1;
343 }
344 rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len));
345 rta->rta_type = type;
346 rta->rta_len = len;
347 move_to_unaligned32(RTA_DATA(rta), data);
348 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
349 return 0;
350}
351
352int FAST_FUNC addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
353{
354 int len = RTA_LENGTH(alen);
355 struct rtattr *rta;
356
357 if ((int)(NLMSG_ALIGN(n->nlmsg_len) + len) > maxlen) {
358 return -1;
359 }
360 rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len));
361 rta->rta_type = type;
362 rta->rta_len = len;
363 memcpy(RTA_DATA(rta), data, alen);
364 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
365 return 0;
366}
367
368int FAST_FUNC rta_addattr32(struct rtattr *rta, int maxlen, int type, uint32_t data)
369{
370 int len = RTA_LENGTH(4);
371 struct rtattr *subrta;
372
373 if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
374 return -1;
375 }
376 subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
377 subrta->rta_type = type;
378 subrta->rta_len = len;
379 move_to_unaligned32(RTA_DATA(subrta), data);
380 rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
381 return 0;
382}
383
384int FAST_FUNC rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data, int alen)
385{
386 struct rtattr *subrta;
387 int len = RTA_LENGTH(alen);
388
389 if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
390 return -1;
391 }
392 subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
393 subrta->rta_type = type;
394 subrta->rta_len = len;
395 memcpy(RTA_DATA(subrta), data, alen);
396 rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
397 return 0;
398}
399
400
401void FAST_FUNC parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
402{
403 while (RTA_OK(rta, len)) {
404 if (rta->rta_type <= max) {
405 tb[rta->rta_type] = rta;
406 }
407 rta = RTA_NEXT(rta, len);
408 }
409 if (len) {
410 bb_error_msg("deficit %d, rta_len=%d!", len, rta->rta_len);
411 }
412}
Note: See TracBrowser for help on using the repository browser.