diff options
-rw-r--r-- | networking/Config.src | 13 | ||||
-rw-r--r-- | networking/ip.c | 19 | ||||
-rw-r--r-- | networking/libiproute/Kbuild.src | 8 | ||||
-rw-r--r-- | networking/libiproute/ip_common.h | 2 | ||||
-rw-r--r-- | networking/libiproute/ipneigh.c | 354 | ||||
-rw-r--r-- | networking/libiproute/iproute.c | 26 | ||||
-rw-r--r-- | networking/libiproute/utils.c | 22 | ||||
-rw-r--r-- | networking/libiproute/utils.h | 2 |
8 files changed, 420 insertions, 26 deletions
diff --git a/networking/Config.src b/networking/Config.src index 43ccbf385..8c7417f86 100644 --- a/networking/Config.src +++ b/networking/Config.src | |||
@@ -554,6 +554,13 @@ config FEATURE_IP_RULE | |||
554 | help | 554 | help |
555 | Add support for rule commands to "ip". | 555 | Add support for rule commands to "ip". |
556 | 556 | ||
557 | config FEATURE_IP_NEIGH | ||
558 | bool "ip neighbor" | ||
559 | default y | ||
560 | depends on IP | ||
561 | help | ||
562 | Add support for neighbor commands to "ip". | ||
563 | |||
557 | config FEATURE_IP_SHORT_FORMS | 564 | config FEATURE_IP_SHORT_FORMS |
558 | bool "Support short forms of ip commands" | 565 | bool "Support short forms of ip commands" |
559 | default y | 566 | default y |
@@ -565,6 +572,7 @@ config FEATURE_IP_SHORT_FORMS | |||
565 | ip route -> iproute | 572 | ip route -> iproute |
566 | ip tunnel -> iptunnel | 573 | ip tunnel -> iptunnel |
567 | ip rule -> iprule | 574 | ip rule -> iprule |
575 | ip neigh -> ipneigh | ||
568 | 576 | ||
569 | Say N unless you desparately need the short form of the ip | 577 | Say N unless you desparately need the short form of the ip |
570 | object commands. | 578 | object commands. |
@@ -604,6 +612,11 @@ config IPRULE | |||
604 | default y | 612 | default y |
605 | depends on FEATURE_IP_SHORT_FORMS && FEATURE_IP_RULE | 613 | depends on FEATURE_IP_SHORT_FORMS && FEATURE_IP_RULE |
606 | 614 | ||
615 | config IPNEIGH | ||
616 | bool | ||
617 | default y | ||
618 | depends on FEATURE_IP_SHORT_FORMS && FEATURE_IP_NEIGH | ||
619 | |||
607 | config IPCALC | 620 | config IPCALC |
608 | bool "ipcalc" | 621 | bool "ipcalc" |
609 | default y | 622 | default y |
diff --git a/networking/ip.c b/networking/ip.c index d35345c36..ddfe74e9c 100644 --- a/networking/ip.c +++ b/networking/ip.c | |||
@@ -16,6 +16,7 @@ | |||
16 | //usage: IF_FEATURE_IP_ROUTE("route | ") | 16 | //usage: IF_FEATURE_IP_ROUTE("route | ") |
17 | //usage: IF_FEATURE_IP_LINK("link | ") | 17 | //usage: IF_FEATURE_IP_LINK("link | ") |
18 | //usage: IF_FEATURE_IP_TUNNEL("tunnel | ") | 18 | //usage: IF_FEATURE_IP_TUNNEL("tunnel | ") |
19 | //usage: IF_FEATURE_IP_NEIGH("neigh | ") | ||
19 | //usage: IF_FEATURE_IP_RULE("rule") | 20 | //usage: IF_FEATURE_IP_RULE("rule") |
20 | //usage: "} {COMMAND}" | 21 | //usage: "} {COMMAND}" |
21 | //usage:#define ip_full_usage "\n\n" | 22 | //usage:#define ip_full_usage "\n\n" |
@@ -25,6 +26,7 @@ | |||
25 | //usage: IF_FEATURE_IP_ROUTE("route | ") | 26 | //usage: IF_FEATURE_IP_ROUTE("route | ") |
26 | //usage: IF_FEATURE_IP_LINK("link | ") | 27 | //usage: IF_FEATURE_IP_LINK("link | ") |
27 | //usage: IF_FEATURE_IP_TUNNEL("tunnel | ") | 28 | //usage: IF_FEATURE_IP_TUNNEL("tunnel | ") |
29 | //usage: IF_FEATURE_IP_NEIGH("neigh | ") | ||
28 | //usage: IF_FEATURE_IP_RULE("rule") | 30 | //usage: IF_FEATURE_IP_RULE("rule") |
29 | //usage: "}\n" | 31 | //usage: "}\n" |
30 | //usage: "OPTIONS := { -f[amily] { inet | inet6 | link } | -o[neline] }" | 32 | //usage: "OPTIONS := { -f[amily] { inet | inet6 | link } | -o[neline] }" |
@@ -80,6 +82,11 @@ | |||
80 | //usage: " [mode { ipip | gre | sit }] [remote ADDR] [local ADDR]\n" | 82 | //usage: " [mode { ipip | gre | sit }] [remote ADDR] [local ADDR]\n" |
81 | //usage: " [[i|o]seq] [[i|o]key KEY] [[i|o]csum]\n" | 83 | //usage: " [[i|o]seq] [[i|o]key KEY] [[i|o]csum]\n" |
82 | //usage: " [ttl TTL] [tos TOS] [[no]pmtudisc] [dev PHYS_DEV]" | 84 | //usage: " [ttl TTL] [tos TOS] [[no]pmtudisc] [dev PHYS_DEV]" |
85 | //usage: | ||
86 | //usage:#define ipneigh_trivial_usage | ||
87 | //usage: "{ show | flush} [ to PREFIX ] [ dev DEV ] [ nud STATE ]" | ||
88 | //usage:#define ipneigh_full_usage "\n\n" | ||
89 | //usage: "ipneigh { show | flush} [ to PREFIX ] [ dev DEV ] [ nud STATE ]" | ||
83 | 90 | ||
84 | #include "libbb.h" | 91 | #include "libbb.h" |
85 | 92 | ||
@@ -90,7 +97,8 @@ | |||
90 | || ENABLE_FEATURE_IP_ROUTE \ | 97 | || ENABLE_FEATURE_IP_ROUTE \ |
91 | || ENABLE_FEATURE_IP_LINK \ | 98 | || ENABLE_FEATURE_IP_LINK \ |
92 | || ENABLE_FEATURE_IP_TUNNEL \ | 99 | || ENABLE_FEATURE_IP_TUNNEL \ |
93 | || ENABLE_FEATURE_IP_RULE | 100 | || ENABLE_FEATURE_IP_RULE \ |
101 | || ENABLE_FEATURE_IP_NEIGH | ||
94 | 102 | ||
95 | static int FAST_FUNC ip_print_help(char **argv UNUSED_PARAM) | 103 | static int FAST_FUNC ip_print_help(char **argv UNUSED_PARAM) |
96 | { | 104 | { |
@@ -140,6 +148,13 @@ int iptunnel_main(int argc UNUSED_PARAM, char **argv) | |||
140 | return ip_do(do_iptunnel, argv); | 148 | return ip_do(do_iptunnel, argv); |
141 | } | 149 | } |
142 | #endif | 150 | #endif |
151 | #if ENABLE_FEATURE_IP_NEIGH | ||
152 | int ipneigh_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
153 | int ipneigh_main(int argc UNUSED_PARAM, char **argv) | ||
154 | { | ||
155 | return ip_do(do_ipneigh, argv); | ||
156 | } | ||
157 | #endif | ||
143 | 158 | ||
144 | 159 | ||
145 | int ip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 160 | int ip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
@@ -153,6 +168,7 @@ int ip_main(int argc UNUSED_PARAM, char **argv) | |||
153 | IF_FEATURE_IP_TUNNEL("tunnel\0") | 168 | IF_FEATURE_IP_TUNNEL("tunnel\0") |
154 | IF_FEATURE_IP_TUNNEL("tunl\0") | 169 | IF_FEATURE_IP_TUNNEL("tunl\0") |
155 | IF_FEATURE_IP_RULE("rule\0") | 170 | IF_FEATURE_IP_RULE("rule\0") |
171 | IF_FEATURE_IP_NEIGH("neigh\0") | ||
156 | ; | 172 | ; |
157 | static const ip_func_ptr_t ip_func_ptrs[] = { | 173 | static const ip_func_ptr_t ip_func_ptrs[] = { |
158 | ip_print_help, | 174 | ip_print_help, |
@@ -163,6 +179,7 @@ int ip_main(int argc UNUSED_PARAM, char **argv) | |||
163 | IF_FEATURE_IP_TUNNEL(do_iptunnel,) | 179 | IF_FEATURE_IP_TUNNEL(do_iptunnel,) |
164 | IF_FEATURE_IP_TUNNEL(do_iptunnel,) | 180 | IF_FEATURE_IP_TUNNEL(do_iptunnel,) |
165 | IF_FEATURE_IP_RULE(do_iprule,) | 181 | IF_FEATURE_IP_RULE(do_iprule,) |
182 | IF_FEATURE_IP_NEIGH(do_ipneigh,) | ||
166 | }; | 183 | }; |
167 | ip_func_ptr_t ip_func; | 184 | ip_func_ptr_t ip_func; |
168 | int key; | 185 | int key; |
diff --git a/networking/libiproute/Kbuild.src b/networking/libiproute/Kbuild.src index 7c78f3c6a..c20e2fee8 100644 --- a/networking/libiproute/Kbuild.src +++ b/networking/libiproute/Kbuild.src | |||
@@ -64,3 +64,11 @@ lib-$(CONFIG_FEATURE_IP_RULE) += \ | |||
64 | iprule.o \ | 64 | iprule.o \ |
65 | rt_names.o \ | 65 | rt_names.o \ |
66 | utils.o | 66 | utils.o |
67 | |||
68 | lib-$(CONFIG_FEATURE_IP_NEIGH) += \ | ||
69 | ip_parse_common_args.o \ | ||
70 | ipneigh.o \ | ||
71 | libnetlink.o \ | ||
72 | ll_map.o \ | ||
73 | rt_names.o \ | ||
74 | utils.o | ||
diff --git a/networking/libiproute/ip_common.h b/networking/libiproute/ip_common.h index 30c7e595b..40171bed9 100644 --- a/networking/libiproute/ip_common.h +++ b/networking/libiproute/ip_common.h | |||
@@ -24,7 +24,7 @@ int FAST_FUNC ipaddr_list_or_flush(char **argv, int flush); | |||
24 | int FAST_FUNC do_ipaddr(char **argv); | 24 | int FAST_FUNC do_ipaddr(char **argv); |
25 | int FAST_FUNC do_iproute(char **argv); | 25 | int FAST_FUNC do_iproute(char **argv); |
26 | int FAST_FUNC do_iprule(char **argv); | 26 | int FAST_FUNC do_iprule(char **argv); |
27 | //int FAST_FUNC do_ipneigh(char **argv); | 27 | int FAST_FUNC do_ipneigh(char **argv); |
28 | int FAST_FUNC do_iptunnel(char **argv); | 28 | int FAST_FUNC do_iptunnel(char **argv); |
29 | int FAST_FUNC do_iplink(char **argv); | 29 | int FAST_FUNC do_iplink(char **argv); |
30 | //int FAST_FUNC do_ipmonitor(char **argv); | 30 | //int FAST_FUNC do_ipmonitor(char **argv); |
diff --git a/networking/libiproute/ipneigh.c b/networking/libiproute/ipneigh.c new file mode 100644 index 000000000..03a15d845 --- /dev/null +++ b/networking/libiproute/ipneigh.c | |||
@@ -0,0 +1,354 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. | ||
4 | * | ||
5 | * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> | ||
6 | * | ||
7 | * Ported to Busybox by: Curt Brune <curt@cumulusnetworks.com> | ||
8 | */ | ||
9 | |||
10 | #include "ip_common.h" /* #include "libbb.h" is inside */ | ||
11 | #include "rt_names.h" | ||
12 | #include "utils.h" | ||
13 | #include <linux/neighbour.h> | ||
14 | #include <net/if_arp.h> | ||
15 | |||
16 | //static int xshow_stats = 3; | ||
17 | enum { xshow_stats = 3 }; | ||
18 | |||
19 | static inline uint32_t rta_getattr_u32(const struct rtattr *rta) | ||
20 | { | ||
21 | return *(uint32_t *)RTA_DATA(rta); | ||
22 | } | ||
23 | |||
24 | #ifndef RTAX_RTTVAR | ||
25 | #define RTAX_RTTVAR RTAX_HOPS | ||
26 | #endif | ||
27 | |||
28 | |||
29 | struct filter_t { | ||
30 | int family; | ||
31 | int index; | ||
32 | int state; | ||
33 | int unused_only; | ||
34 | inet_prefix pfx; | ||
35 | int flushed; | ||
36 | char *flushb; | ||
37 | int flushp; | ||
38 | int flushe; | ||
39 | struct rtnl_handle *rth; | ||
40 | } FIX_ALIASING; | ||
41 | typedef struct filter_t filter_t; | ||
42 | |||
43 | #define G_filter (*(filter_t*)&bb_common_bufsiz1) | ||
44 | |||
45 | static int flush_update(void) | ||
46 | { | ||
47 | if (rtnl_send(G_filter.rth, G_filter.flushb, G_filter.flushp) < 0) { | ||
48 | bb_perror_msg("can't send flush request"); | ||
49 | return -1; | ||
50 | } | ||
51 | G_filter.flushp = 0; | ||
52 | return 0; | ||
53 | } | ||
54 | |||
55 | static unsigned nud_state_a2n(char *arg) | ||
56 | { | ||
57 | static const char keywords[] ALIGN1 = | ||
58 | /* "ip neigh show/flush" parameters: */ | ||
59 | "permanent\0" "reachable\0" "noarp\0" "none\0" | ||
60 | "stale\0" "incomplete\0" "delay\0" "probe\0" | ||
61 | "failed\0" | ||
62 | ; | ||
63 | static uint8_t nuds[] = { | ||
64 | NUD_PERMANENT,NUD_REACHABLE, NUD_NOARP,NUD_NONE, | ||
65 | NUD_STALE, NUD_INCOMPLETE,NUD_DELAY,NUD_PROBE, | ||
66 | NUD_FAILED | ||
67 | }; | ||
68 | int id; | ||
69 | |||
70 | BUILD_BUG_ON( | ||
71 | (NUD_PERMANENT|NUD_REACHABLE| NUD_NOARP|NUD_NONE| | ||
72 | NUD_STALE| NUD_INCOMPLETE|NUD_DELAY|NUD_PROBE| | ||
73 | NUD_FAILED) > 0xff | ||
74 | ); | ||
75 | |||
76 | id = index_in_substrings(keywords, arg); | ||
77 | if (id < 0) | ||
78 | bb_error_msg_and_die(bb_msg_invalid_arg, arg, "nud state"); | ||
79 | return nuds[id]; | ||
80 | } | ||
81 | |||
82 | #ifndef NDA_RTA | ||
83 | #define NDA_RTA(r) \ | ||
84 | ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg)))) | ||
85 | #endif | ||
86 | |||
87 | |||
88 | static int FAST_FUNC print_neigh(const struct sockaddr_nl *who UNUSED_PARAM, | ||
89 | struct nlmsghdr *n, void *arg UNUSED_PARAM) | ||
90 | { | ||
91 | struct ndmsg *r = NLMSG_DATA(n); | ||
92 | int len = n->nlmsg_len; | ||
93 | struct rtattr *tb[NDA_MAX+1]; | ||
94 | char abuf[256]; | ||
95 | |||
96 | if (n->nlmsg_type != RTM_NEWNEIGH && n->nlmsg_type != RTM_DELNEIGH) { | ||
97 | bb_error_msg_and_die("not RTM_NEWNEIGH: %08x %08x %08x", | ||
98 | n->nlmsg_len, n->nlmsg_type, | ||
99 | n->nlmsg_flags); | ||
100 | } | ||
101 | len -= NLMSG_LENGTH(sizeof(*r)); | ||
102 | if (len < 0) { | ||
103 | bb_error_msg_and_die("BUG: wrong nlmsg len %d", len); | ||
104 | } | ||
105 | |||
106 | if (G_filter.flushb && n->nlmsg_type != RTM_NEWNEIGH) | ||
107 | return 0; | ||
108 | |||
109 | if (G_filter.family && G_filter.family != r->ndm_family) | ||
110 | return 0; | ||
111 | if (G_filter.index && G_filter.index != r->ndm_ifindex) | ||
112 | return 0; | ||
113 | if (!(G_filter.state&r->ndm_state) && | ||
114 | !(r->ndm_flags & NTF_PROXY) && | ||
115 | (r->ndm_state || !(G_filter.state & 0x100)) && | ||
116 | (r->ndm_family != AF_DECnet)) | ||
117 | return 0; | ||
118 | |||
119 | parse_rtattr(tb, NDA_MAX, NDA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r))); | ||
120 | |||
121 | if (tb[NDA_DST]) { | ||
122 | if (G_filter.pfx.family) { | ||
123 | inet_prefix dst; | ||
124 | memset(&dst, 0, sizeof(dst)); | ||
125 | dst.family = r->ndm_family; | ||
126 | memcpy(&dst.data, RTA_DATA(tb[NDA_DST]), RTA_PAYLOAD(tb[NDA_DST])); | ||
127 | if (inet_addr_match(&dst, &G_filter.pfx, G_filter.pfx.bitlen)) | ||
128 | return 0; | ||
129 | } | ||
130 | } | ||
131 | if (G_filter.unused_only && tb[NDA_CACHEINFO]) { | ||
132 | struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]); | ||
133 | if (ci->ndm_refcnt) | ||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | if (G_filter.flushb) { | ||
138 | struct nlmsghdr *fn; | ||
139 | if (NLMSG_ALIGN(G_filter.flushp) + n->nlmsg_len > G_filter.flushe) { | ||
140 | if (flush_update()) | ||
141 | return -1; | ||
142 | } | ||
143 | fn = (struct nlmsghdr*)(G_filter.flushb + NLMSG_ALIGN(G_filter.flushp)); | ||
144 | memcpy(fn, n, n->nlmsg_len); | ||
145 | fn->nlmsg_type = RTM_DELNEIGH; | ||
146 | fn->nlmsg_flags = NLM_F_REQUEST; | ||
147 | fn->nlmsg_seq = ++(G_filter.rth->seq); | ||
148 | G_filter.flushp = (((char*)fn) + n->nlmsg_len) - G_filter.flushb; | ||
149 | G_filter.flushed++; | ||
150 | if (xshow_stats < 2) | ||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | if (tb[NDA_DST]) { | ||
155 | printf("%s ", | ||
156 | format_host(r->ndm_family, | ||
157 | RTA_PAYLOAD(tb[NDA_DST]), | ||
158 | RTA_DATA(tb[NDA_DST]), | ||
159 | abuf, sizeof(abuf))); | ||
160 | } | ||
161 | if (!G_filter.index && r->ndm_ifindex) | ||
162 | printf("dev %s ", ll_index_to_name(r->ndm_ifindex)); | ||
163 | if (tb[NDA_LLADDR]) { | ||
164 | SPRINT_BUF(b1); | ||
165 | printf("lladdr %s", ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]), | ||
166 | RTA_PAYLOAD(tb[NDA_LLADDR]), | ||
167 | ARPHRD_ETHER, | ||
168 | b1, sizeof(b1))); | ||
169 | } | ||
170 | if (r->ndm_flags & NTF_ROUTER) { | ||
171 | printf(" router"); | ||
172 | } | ||
173 | if (r->ndm_flags & NTF_PROXY) { | ||
174 | printf(" proxy"); | ||
175 | } | ||
176 | if (tb[NDA_CACHEINFO] && xshow_stats) { | ||
177 | struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]); | ||
178 | int hz = get_hz(); | ||
179 | |||
180 | if (ci->ndm_refcnt) | ||
181 | printf(" ref %d", ci->ndm_refcnt); | ||
182 | printf(" used %d/%d/%d", ci->ndm_used/hz, | ||
183 | ci->ndm_confirmed/hz, ci->ndm_updated/hz); | ||
184 | } | ||
185 | |||
186 | if (tb[NDA_PROBES] && xshow_stats) { | ||
187 | uint32_t p = rta_getattr_u32(tb[NDA_PROBES]); | ||
188 | printf(" probes %u", p); | ||
189 | } | ||
190 | |||
191 | /*if (r->ndm_state)*/ { | ||
192 | int nud = r->ndm_state; | ||
193 | char c = ' '; | ||
194 | #define PRINT_FLAG(f) \ | ||
195 | if (nud & NUD_##f) { \ | ||
196 | printf("%c"#f, c); \ | ||
197 | c = ','; \ | ||
198 | } | ||
199 | PRINT_FLAG(INCOMPLETE); | ||
200 | PRINT_FLAG(REACHABLE); | ||
201 | PRINT_FLAG(STALE); | ||
202 | PRINT_FLAG(DELAY); | ||
203 | PRINT_FLAG(PROBE); | ||
204 | PRINT_FLAG(FAILED); | ||
205 | PRINT_FLAG(NOARP); | ||
206 | PRINT_FLAG(PERMANENT); | ||
207 | #undef PRINT_FLAG | ||
208 | } | ||
209 | bb_putchar('\n'); | ||
210 | |||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | static void ipneigh_reset_filter(void) | ||
215 | { | ||
216 | memset(&G_filter, 0, sizeof(G_filter)); | ||
217 | G_filter.state = ~0; | ||
218 | } | ||
219 | |||
220 | #define MAX_ROUNDS 10 | ||
221 | /* Return value becomes exitcode. It's okay to not return at all */ | ||
222 | static int FAST_FUNC ipneigh_list_or_flush(char **argv, int flush) | ||
223 | { | ||
224 | static const char keywords[] ALIGN1 = | ||
225 | /* "ip neigh show/flush" parameters: */ | ||
226 | "to\0" "dev\0" "nud\0"; | ||
227 | enum { | ||
228 | KW_to, KW_dev, KW_nud, | ||
229 | }; | ||
230 | struct rtnl_handle rth; | ||
231 | struct ndmsg ndm = { 0 }; | ||
232 | char *filter_dev = NULL; | ||
233 | int state_given = 0; | ||
234 | int arg; | ||
235 | |||
236 | ipneigh_reset_filter(); | ||
237 | |||
238 | if (flush && !*argv) | ||
239 | bb_error_msg_and_die(bb_msg_requires_arg, "\"ip neigh flush\""); | ||
240 | |||
241 | if (!G_filter.family) | ||
242 | G_filter.family = preferred_family; | ||
243 | |||
244 | G_filter.state = (flush) ? | ||
245 | ~(NUD_PERMANENT|NUD_NOARP) : 0xFF & ~NUD_NOARP; | ||
246 | |||
247 | while (*argv) { | ||
248 | arg = index_in_substrings(keywords, *argv); | ||
249 | if (arg == KW_dev) { | ||
250 | NEXT_ARG(); | ||
251 | filter_dev = *argv; | ||
252 | } else if (arg == KW_nud) { | ||
253 | unsigned state; | ||
254 | NEXT_ARG(); | ||
255 | if (!state_given) { | ||
256 | state_given = 1; | ||
257 | G_filter.state = 0; | ||
258 | } | ||
259 | if (strcmp(*argv, "all") == 0) { | ||
260 | state = ~0; | ||
261 | if (flush) | ||
262 | state &= ~NUD_NOARP; | ||
263 | } else { | ||
264 | state = nud_state_a2n(*argv); | ||
265 | } | ||
266 | if (state == 0) | ||
267 | state = 0x100; | ||
268 | G_filter.state |= state; | ||
269 | } else { | ||
270 | if (arg == KW_to) { | ||
271 | NEXT_ARG(); | ||
272 | } | ||
273 | get_prefix(&G_filter.pfx, *argv, G_filter.family); | ||
274 | if (G_filter.family == AF_UNSPEC) | ||
275 | G_filter.family = G_filter.pfx.family; | ||
276 | } | ||
277 | argv++; | ||
278 | } | ||
279 | |||
280 | xrtnl_open(&rth); | ||
281 | ll_init_map(&rth); | ||
282 | |||
283 | if (filter_dev) { | ||
284 | if ((G_filter.index = xll_name_to_index(filter_dev)) == 0) { | ||
285 | bb_error_msg_and_die(bb_msg_invalid_arg, | ||
286 | filter_dev, "Cannot find device"); | ||
287 | } | ||
288 | } | ||
289 | |||
290 | if (flush) { | ||
291 | int round = 0; | ||
292 | char flushb[4096-512]; | ||
293 | G_filter.flushb = flushb; | ||
294 | G_filter.flushp = 0; | ||
295 | G_filter.flushe = sizeof(flushb); | ||
296 | G_filter.state &= ~NUD_FAILED; | ||
297 | G_filter.rth = &rth; | ||
298 | |||
299 | while (round < MAX_ROUNDS) { | ||
300 | if (xrtnl_wilddump_request(&rth, G_filter.family, RTM_GETNEIGH) < 0) { | ||
301 | bb_perror_msg_and_die("can't send dump request"); | ||
302 | } | ||
303 | G_filter.flushed = 0; | ||
304 | if (xrtnl_dump_filter(&rth, print_neigh, NULL) < 0) { | ||
305 | bb_perror_msg_and_die("flush terminated"); | ||
306 | } | ||
307 | if (G_filter.flushed == 0) { | ||
308 | if (round == 0) | ||
309 | puts("Nothing to flush"); | ||
310 | else | ||
311 | printf("*** Flush is complete after %d round(s) ***\n", round); | ||
312 | return 0; | ||
313 | } | ||
314 | round++; | ||
315 | if (flush_update() < 0) | ||
316 | xfunc_die(); | ||
317 | printf("\n*** Round %d, deleting %d entries ***\n", round, G_filter.flushed); | ||
318 | } | ||
319 | bb_error_msg_and_die("*** Flush not complete bailing out after %d rounds", MAX_ROUNDS); | ||
320 | } | ||
321 | |||
322 | ndm.ndm_family = G_filter.family; | ||
323 | |||
324 | if (rtnl_dump_request(&rth, RTM_GETNEIGH, &ndm, sizeof(struct ndmsg)) < 0) { | ||
325 | bb_perror_msg_and_die("can't send dump request"); | ||
326 | } | ||
327 | |||
328 | if (xrtnl_dump_filter(&rth, print_neigh, NULL) < 0) { | ||
329 | bb_error_msg_and_die("dump terminated"); | ||
330 | } | ||
331 | |||
332 | return 0; | ||
333 | } | ||
334 | |||
335 | /* Return value becomes exitcode. It's okay to not return at all */ | ||
336 | int FAST_FUNC do_ipneigh(char **argv) | ||
337 | { | ||
338 | static const char ip_neigh_commands[] ALIGN1 = | ||
339 | /*0-1*/ "show\0" "flush\0"; | ||
340 | int command_num; | ||
341 | |||
342 | if (!*argv) | ||
343 | return ipneigh_list_or_flush(argv, 0); | ||
344 | |||
345 | command_num = index_in_substrings(ip_neigh_commands, *argv); | ||
346 | switch (command_num) { | ||
347 | case 0: /* show */ | ||
348 | return ipneigh_list_or_flush(argv + 1, 0); | ||
349 | case 1: /* flush */ | ||
350 | return ipneigh_list_or_flush(argv + 1, 1); | ||
351 | } | ||
352 | invarg(*argv, applet_name); | ||
353 | return 1; | ||
354 | } | ||
diff --git a/networking/libiproute/iproute.c b/networking/libiproute/iproute.c index 6ecd5f719..f7209b126 100644 --- a/networking/libiproute/iproute.c +++ b/networking/libiproute/iproute.c | |||
@@ -55,28 +55,6 @@ static int flush_update(void) | |||
55 | return 0; | 55 | return 0; |
56 | } | 56 | } |
57 | 57 | ||
58 | static unsigned get_hz(void) | ||
59 | { | ||
60 | static unsigned hz_internal; | ||
61 | FILE *fp; | ||
62 | |||
63 | if (hz_internal) | ||
64 | return hz_internal; | ||
65 | |||
66 | fp = fopen_for_read("/proc/net/psched"); | ||
67 | if (fp) { | ||
68 | unsigned nom, denom; | ||
69 | |||
70 | if (fscanf(fp, "%*08x%*08x%08x%08x", &nom, &denom) == 2) | ||
71 | if (nom == 1000000) | ||
72 | hz_internal = denom; | ||
73 | fclose(fp); | ||
74 | } | ||
75 | if (!hz_internal) | ||
76 | hz_internal = bb_clk_tck(); | ||
77 | return hz_internal; | ||
78 | } | ||
79 | |||
80 | static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM, | 58 | static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM, |
81 | struct nlmsghdr *n, void *arg UNUSED_PARAM) | 59 | struct nlmsghdr *n, void *arg UNUSED_PARAM) |
82 | { | 60 | { |
@@ -217,7 +195,7 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM, | |||
217 | 195 | ||
218 | if (NLMSG_ALIGN(G_filter.flushp) + n->nlmsg_len > G_filter.flushe) { | 196 | if (NLMSG_ALIGN(G_filter.flushp) + n->nlmsg_len > G_filter.flushe) { |
219 | if (flush_update()) | 197 | if (flush_update()) |
220 | bb_error_msg_and_die("flush"); | 198 | xfunc_die(); |
221 | } | 199 | } |
222 | fn = (void*)(G_filter.flushb + NLMSG_ALIGN(G_filter.flushp)); | 200 | fn = (void*)(G_filter.flushb + NLMSG_ALIGN(G_filter.flushp)); |
223 | memcpy(fn, n, n->nlmsg_len); | 201 | memcpy(fn, n, n->nlmsg_len); |
@@ -954,7 +932,7 @@ int FAST_FUNC do_iproute(char **argv) | |||
954 | case 11: /* flush */ | 932 | case 11: /* flush */ |
955 | return iproute_list_or_flush(argv+1, 1); | 933 | return iproute_list_or_flush(argv+1, 1); |
956 | default: | 934 | default: |
957 | bb_error_msg_and_die("unknown command %s", *argv); | 935 | invarg(*argv, applet_name); |
958 | } | 936 | } |
959 | 937 | ||
960 | return iproute_modify(cmd, flags, argv+1); | 938 | return iproute_modify(cmd, flags, argv+1); |
diff --git a/networking/libiproute/utils.c b/networking/libiproute/utils.c index d0fe30605..37b5311f0 100644 --- a/networking/libiproute/utils.c +++ b/networking/libiproute/utils.c | |||
@@ -13,6 +13,28 @@ | |||
13 | #include "utils.h" | 13 | #include "utils.h" |
14 | #include "inet_common.h" | 14 | #include "inet_common.h" |
15 | 15 | ||
16 | unsigned get_hz(void) | ||
17 | { | ||
18 | static unsigned hz_internal; | ||
19 | FILE *fp; | ||
20 | |||
21 | if (hz_internal) | ||
22 | return hz_internal; | ||
23 | |||
24 | fp = fopen_for_read("/proc/net/psched"); | ||
25 | if (fp) { | ||
26 | unsigned nom, denom; | ||
27 | |||
28 | if (fscanf(fp, "%*08x%*08x%08x%08x", &nom, &denom) == 2) | ||
29 | if (nom == 1000000) | ||
30 | hz_internal = denom; | ||
31 | fclose(fp); | ||
32 | } | ||
33 | if (!hz_internal) | ||
34 | hz_internal = bb_clk_tck(); | ||
35 | return hz_internal; | ||
36 | } | ||
37 | |||
16 | unsigned get_unsigned(char *arg, const char *errmsg) | 38 | unsigned get_unsigned(char *arg, const char *errmsg) |
17 | { | 39 | { |
18 | unsigned long res; | 40 | unsigned long res; |
diff --git a/networking/libiproute/utils.h b/networking/libiproute/utils.h index 5fb4a862c..cd15b706b 100644 --- a/networking/libiproute/utils.h +++ b/networking/libiproute/utils.h | |||
@@ -85,6 +85,8 @@ int dnet_pton(int af, const char *src, void *addr); | |||
85 | const char *ipx_ntop(int af, const void *addr, char *str, size_t len); | 85 | const char *ipx_ntop(int af, const void *addr, char *str, size_t len); |
86 | int ipx_pton(int af, const char *src, void *addr); | 86 | int ipx_pton(int af, const char *src, void *addr); |
87 | 87 | ||
88 | unsigned get_hz(void); | ||
89 | |||
88 | POP_SAVED_FUNCTION_VISIBILITY | 90 | POP_SAVED_FUNCTION_VISIBILITY |
89 | 91 | ||
90 | #endif | 92 | #endif |