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