Annotation of /trunk/mkinitrd-magellan/busybox/networking/libiproute/libnetlink.c
Parent Directory | Revision Log
Revision 1123 -
(hide annotations)
(download)
Wed Aug 18 21:56:57 2010 UTC (13 years, 9 months ago) by niro
File MIME type: text/plain
File size: 9867 byte(s)
Wed Aug 18 21:56:57 2010 UTC (13 years, 9 months ago) by niro
File MIME type: text/plain
File size: 9867 byte(s)
-updated to busybox-1.17.1
1 | niro | 532 | /* 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 | niro | 816 | #include "libbb.h" |
18 | niro | 532 | #include "libnetlink.h" |
19 | |||
20 | niro | 816 | void FAST_FUNC rtnl_close(struct rtnl_handle *rth) |
21 | niro | 532 | { |
22 | close(rth->fd); | ||
23 | } | ||
24 | |||
25 | niro | 816 | int FAST_FUNC xrtnl_open(struct rtnl_handle *rth/*, unsigned subscriptions*/) |
26 | niro | 532 | { |
27 | socklen_t addr_len; | ||
28 | |||
29 | niro | 984 | memset(rth, 0, sizeof(*rth)); |
30 | niro | 816 | rth->fd = xsocket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); |
31 | niro | 532 | rth->local.nl_family = AF_NETLINK; |
32 | niro | 816 | /*rth->local.nl_groups = subscriptions;*/ |
33 | niro | 532 | |
34 | niro | 816 | xbind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)); |
35 | niro | 532 | addr_len = sizeof(rth->local); |
36 | niro | 984 | getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len); |
37 | |||
38 | /* too much paranoia | ||
39 | niro | 816 | 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 | niro | 984 | */ |
46 | niro | 532 | rth->seq = time(NULL); |
47 | return 0; | ||
48 | } | ||
49 | |||
50 | niro | 816 | int FAST_FUNC xrtnl_wilddump_request(struct rtnl_handle *rth, int family, int type) |
51 | niro | 532 | { |
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 | niro | 816 | return xsendto(rth->fd, (void*)&req, sizeof(req), |
69 | (struct sockaddr*)&nladdr, sizeof(nladdr)); | ||
70 | niro | 532 | } |
71 | |||
72 | niro | 816 | int FAST_FUNC rtnl_send(struct rtnl_handle *rth, char *buf, int len) |
73 | niro | 532 | { |
74 | struct sockaddr_nl nladdr; | ||
75 | |||
76 | memset(&nladdr, 0, sizeof(nladdr)); | ||
77 | nladdr.nl_family = AF_NETLINK; | ||
78 | |||
79 | niro | 816 | return xsendto(rth->fd, buf, len, (struct sockaddr*)&nladdr, sizeof(nladdr)); |
80 | niro | 532 | } |
81 | |||
82 | niro | 816 | int FAST_FUNC rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len) |
83 | niro | 532 | { |
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 | niro | 816 | static int rtnl_dump_filter(struct rtnl_handle *rth, |
107 | niro | 984 | int (*filter)(const struct sockaddr_nl *, struct nlmsghdr *n, void *) FAST_FUNC, |
108 | niro | 816 | void *arg1/*, |
109 | niro | 532 | int (*junk)(struct sockaddr_nl *, struct nlmsghdr *n, void *), |
110 | niro | 816 | void *arg2*/) |
111 | niro | 532 | { |
112 | niro | 816 | int retval = -1; |
113 | char *buf = xmalloc(8*1024); /* avoid big stack buffer */ | ||
114 | niro | 532 | struct sockaddr_nl nladdr; |
115 | niro | 816 | struct iovec iov = { buf, 8*1024 }; |
116 | niro | 532 | |
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 | niro | 816 | goto ret; |
139 | niro | 532 | } |
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 | niro | 1123 | h->nlmsg_seq != rth->dump |
151 | ) { | ||
152 | niro | 816 | // if (junk) { |
153 | // err = junk(&nladdr, h, arg2); | ||
154 | // if (err < 0) { | ||
155 | // retval = err; | ||
156 | // goto ret; | ||
157 | // } | ||
158 | // } | ||
159 | niro | 532 | goto skip_it; |
160 | } | ||
161 | |||
162 | if (h->nlmsg_type == NLMSG_DONE) { | ||
163 | niro | 816 | goto ret_0; |
164 | niro | 532 | } |
165 | if (h->nlmsg_type == NLMSG_ERROR) { | ||
166 | struct nlmsgerr *l_err = (struct nlmsgerr*)NLMSG_DATA(h); | ||
167 | if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) { | ||
168 | bb_error_msg("ERROR truncated"); | ||
169 | } else { | ||
170 | errno = -l_err->error; | ||
171 | bb_perror_msg("RTNETLINK answers"); | ||
172 | } | ||
173 | niro | 816 | goto ret; |
174 | niro | 532 | } |
175 | err = filter(&nladdr, h, arg1); | ||
176 | if (err < 0) { | ||
177 | niro | 816 | retval = err; |
178 | goto ret; | ||
179 | niro | 532 | } |
180 | |||
181 | niro | 816 | skip_it: |
182 | niro | 532 | h = NLMSG_NEXT(h, status); |
183 | } | ||
184 | if (msg.msg_flags & MSG_TRUNC) { | ||
185 | bb_error_msg("message truncated"); | ||
186 | continue; | ||
187 | } | ||
188 | if (status) { | ||
189 | bb_error_msg_and_die("remnant of size %d!", status); | ||
190 | } | ||
191 | niro | 816 | } /* while (1) */ |
192 | ret_0: | ||
193 | retval++; /* = 0 */ | ||
194 | ret: | ||
195 | free(buf); | ||
196 | return retval; | ||
197 | niro | 532 | } |
198 | |||
199 | niro | 816 | int FAST_FUNC xrtnl_dump_filter(struct rtnl_handle *rth, |
200 | niro | 984 | int (*filter)(const struct sockaddr_nl *, struct nlmsghdr *, void *) FAST_FUNC, |
201 | niro | 816 | void *arg1) |
202 | { | ||
203 | int ret = rtnl_dump_filter(rth, filter, arg1/*, NULL, NULL*/); | ||
204 | if (ret < 0) | ||
205 | bb_error_msg_and_die("dump terminated"); | ||
206 | return ret; | ||
207 | } | ||
208 | |||
209 | int FAST_FUNC rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, | ||
210 | niro | 984 | pid_t peer, unsigned groups, |
211 | struct nlmsghdr *answer, | ||
212 | int (*junk)(struct sockaddr_nl *, struct nlmsghdr *, void *), | ||
213 | void *jarg) | ||
214 | niro | 532 | { |
215 | niro | 816 | /* bbox doesn't use parameters no. 3, 4, 6, 7, they are stubbed out */ |
216 | #define peer 0 | ||
217 | #define groups 0 | ||
218 | #define junk NULL | ||
219 | #define jarg NULL | ||
220 | int retval = -1; | ||
221 | niro | 532 | int status; |
222 | unsigned seq; | ||
223 | struct nlmsghdr *h; | ||
224 | struct sockaddr_nl nladdr; | ||
225 | struct iovec iov = { (void*)n, n->nlmsg_len }; | ||
226 | niro | 816 | char *buf = xmalloc(8*1024); /* avoid big stack buffer */ |
227 | niro | 532 | struct msghdr msg = { |
228 | (void*)&nladdr, sizeof(nladdr), | ||
229 | &iov, 1, | ||
230 | NULL, 0, | ||
231 | 0 | ||
232 | }; | ||
233 | |||
234 | memset(&nladdr, 0, sizeof(nladdr)); | ||
235 | nladdr.nl_family = AF_NETLINK; | ||
236 | niro | 816 | // nladdr.nl_pid = peer; |
237 | // nladdr.nl_groups = groups; | ||
238 | niro | 532 | |
239 | n->nlmsg_seq = seq = ++rtnl->seq; | ||
240 | if (answer == NULL) { | ||
241 | n->nlmsg_flags |= NLM_F_ACK; | ||
242 | } | ||
243 | status = sendmsg(rtnl->fd, &msg, 0); | ||
244 | |||
245 | if (status < 0) { | ||
246 | niro | 984 | bb_perror_msg("can't talk to rtnetlink"); |
247 | niro | 816 | goto ret; |
248 | niro | 532 | } |
249 | |||
250 | iov.iov_base = buf; | ||
251 | |||
252 | while (1) { | ||
253 | niro | 816 | iov.iov_len = 8*1024; |
254 | niro | 532 | status = recvmsg(rtnl->fd, &msg, 0); |
255 | |||
256 | if (status < 0) { | ||
257 | if (errno == EINTR) { | ||
258 | continue; | ||
259 | } | ||
260 | bb_perror_msg("OVERRUN"); | ||
261 | continue; | ||
262 | } | ||
263 | if (status == 0) { | ||
264 | bb_error_msg("EOF on netlink"); | ||
265 | niro | 816 | goto ret; |
266 | niro | 532 | } |
267 | if (msg.msg_namelen != sizeof(nladdr)) { | ||
268 | bb_error_msg_and_die("sender address length == %d", msg.msg_namelen); | ||
269 | } | ||
270 | niro | 816 | for (h = (struct nlmsghdr*)buf; status >= (int)sizeof(*h); ) { |
271 | // int l_err; | ||
272 | niro | 532 | int len = h->nlmsg_len; |
273 | int l = len - sizeof(*h); | ||
274 | |||
275 | niro | 816 | if (l < 0 || len > status) { |
276 | niro | 532 | if (msg.msg_flags & MSG_TRUNC) { |
277 | bb_error_msg("truncated message"); | ||
278 | niro | 816 | goto ret; |
279 | niro | 532 | } |
280 | bb_error_msg_and_die("malformed message: len=%d!", len); | ||
281 | } | ||
282 | |||
283 | if (nladdr.nl_pid != peer || | ||
284 | h->nlmsg_pid != rtnl->local.nl_pid || | ||
285 | niro | 1123 | h->nlmsg_seq != seq |
286 | ) { | ||
287 | niro | 816 | // if (junk) { |
288 | // l_err = junk(&nladdr, h, jarg); | ||
289 | // if (l_err < 0) { | ||
290 | // retval = l_err; | ||
291 | // goto ret; | ||
292 | // } | ||
293 | // } | ||
294 | niro | 532 | continue; |
295 | } | ||
296 | |||
297 | if (h->nlmsg_type == NLMSG_ERROR) { | ||
298 | struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); | ||
299 | niro | 816 | if (l < (int)sizeof(struct nlmsgerr)) { |
300 | niro | 532 | bb_error_msg("ERROR truncated"); |
301 | } else { | ||
302 | niro | 816 | errno = - err->error; |
303 | niro | 532 | if (errno == 0) { |
304 | if (answer) { | ||
305 | memcpy(answer, h, h->nlmsg_len); | ||
306 | } | ||
307 | niro | 816 | goto ret_0; |
308 | niro | 532 | } |
309 | bb_perror_msg("RTNETLINK answers"); | ||
310 | } | ||
311 | niro | 816 | goto ret; |
312 | niro | 532 | } |
313 | if (answer) { | ||
314 | memcpy(answer, h, h->nlmsg_len); | ||
315 | niro | 816 | goto ret_0; |
316 | niro | 532 | } |
317 | |||
318 | bb_error_msg("unexpected reply!"); | ||
319 | |||
320 | status -= NLMSG_ALIGN(len); | ||
321 | h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); | ||
322 | } | ||
323 | if (msg.msg_flags & MSG_TRUNC) { | ||
324 | bb_error_msg("message truncated"); | ||
325 | continue; | ||
326 | } | ||
327 | if (status) { | ||
328 | bb_error_msg_and_die("remnant of size %d!", status); | ||
329 | } | ||
330 | niro | 816 | } /* while (1) */ |
331 | ret_0: | ||
332 | retval++; /* = 0 */ | ||
333 | ret: | ||
334 | free(buf); | ||
335 | return retval; | ||
336 | niro | 532 | } |
337 | |||
338 | niro | 816 | int FAST_FUNC addattr32(struct nlmsghdr *n, int maxlen, int type, uint32_t data) |
339 | niro | 532 | { |
340 | int len = RTA_LENGTH(4); | ||
341 | struct rtattr *rta; | ||
342 | niro | 816 | if ((int)(NLMSG_ALIGN(n->nlmsg_len) + len) > maxlen) |
343 | niro | 532 | return -1; |
344 | rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len)); | ||
345 | rta->rta_type = type; | ||
346 | rta->rta_len = len; | ||
347 | niro | 984 | move_to_unaligned32(RTA_DATA(rta), data); |
348 | niro | 532 | n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len; |
349 | return 0; | ||
350 | } | ||
351 | |||
352 | niro | 816 | int FAST_FUNC addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen) |
353 | niro | 532 | { |
354 | int len = RTA_LENGTH(alen); | ||
355 | struct rtattr *rta; | ||
356 | |||
357 | niro | 816 | if ((int)(NLMSG_ALIGN(n->nlmsg_len) + len) > maxlen) |
358 | niro | 532 | return -1; |
359 | rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len)); | ||
360 | rta->rta_type = type; | ||
361 | rta->rta_len = len; | ||
362 | memcpy(RTA_DATA(rta), data, alen); | ||
363 | n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len; | ||
364 | return 0; | ||
365 | } | ||
366 | |||
367 | niro | 816 | int FAST_FUNC rta_addattr32(struct rtattr *rta, int maxlen, int type, uint32_t data) |
368 | niro | 532 | { |
369 | int len = RTA_LENGTH(4); | ||
370 | struct rtattr *subrta; | ||
371 | |||
372 | if (RTA_ALIGN(rta->rta_len) + len > maxlen) { | ||
373 | return -1; | ||
374 | } | ||
375 | subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len)); | ||
376 | subrta->rta_type = type; | ||
377 | subrta->rta_len = len; | ||
378 | niro | 984 | move_to_unaligned32(RTA_DATA(subrta), data); |
379 | niro | 532 | rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len; |
380 | return 0; | ||
381 | } | ||
382 | |||
383 | niro | 816 | int FAST_FUNC rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data, int alen) |
384 | niro | 532 | { |
385 | struct rtattr *subrta; | ||
386 | int len = RTA_LENGTH(alen); | ||
387 | |||
388 | if (RTA_ALIGN(rta->rta_len) + len > maxlen) { | ||
389 | return -1; | ||
390 | } | ||
391 | subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len)); | ||
392 | subrta->rta_type = type; | ||
393 | subrta->rta_len = len; | ||
394 | memcpy(RTA_DATA(subrta), data, alen); | ||
395 | rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len; | ||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | |||
400 | niro | 816 | int FAST_FUNC parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) |
401 | niro | 532 | { |
402 | while (RTA_OK(rta, len)) { | ||
403 | if (rta->rta_type <= max) { | ||
404 | tb[rta->rta_type] = rta; | ||
405 | } | ||
406 | rta = RTA_NEXT(rta,len); | ||
407 | } | ||
408 | if (len) { | ||
409 | bb_error_msg("deficit %d, rta_len=%d!", len, rta->rta_len); | ||
410 | } | ||
411 | return 0; | ||
412 | } |