Magellan Linux

Annotation of /trunk/mkinitrd-magellan/busybox/networking/libiproute/libnetlink.c

Parent Directory Parent Directory | Revision Log 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)
-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     }