aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--networking/Config.src13
-rw-r--r--networking/ip.c19
-rw-r--r--networking/libiproute/Kbuild.src8
-rw-r--r--networking/libiproute/ip_common.h2
-rw-r--r--networking/libiproute/ipneigh.c354
-rw-r--r--networking/libiproute/iproute.c26
-rw-r--r--networking/libiproute/utils.c22
-rw-r--r--networking/libiproute/utils.h2
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
557config 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
557config FEATURE_IP_SHORT_FORMS 564config 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
615config IPNEIGH
616 bool
617 default y
618 depends on FEATURE_IP_SHORT_FORMS && FEATURE_IP_NEIGH
619
607config IPCALC 620config 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
95static int FAST_FUNC ip_print_help(char **argv UNUSED_PARAM) 103static 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
152int ipneigh_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
153int ipneigh_main(int argc UNUSED_PARAM, char **argv)
154{
155 return ip_do(do_ipneigh, argv);
156}
157#endif
143 158
144 159
145int ip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 160int 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
68lib-$(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);
24int FAST_FUNC do_ipaddr(char **argv); 24int FAST_FUNC do_ipaddr(char **argv);
25int FAST_FUNC do_iproute(char **argv); 25int FAST_FUNC do_iproute(char **argv);
26int FAST_FUNC do_iprule(char **argv); 26int FAST_FUNC do_iprule(char **argv);
27//int FAST_FUNC do_ipneigh(char **argv); 27int FAST_FUNC do_ipneigh(char **argv);
28int FAST_FUNC do_iptunnel(char **argv); 28int FAST_FUNC do_iptunnel(char **argv);
29int FAST_FUNC do_iplink(char **argv); 29int 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;
17enum { xshow_stats = 3 };
18
19static 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
29struct 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;
41typedef struct filter_t filter_t;
42
43#define G_filter (*(filter_t*)&bb_common_bufsiz1)
44
45static 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
55static 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
88static 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
214static 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 */
222static 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 */
336int 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
58static 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
80static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM, 58static 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
16unsigned 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
16unsigned get_unsigned(char *arg, const char *errmsg) 38unsigned 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);
85const char *ipx_ntop(int af, const void *addr, char *str, size_t len); 85const char *ipx_ntop(int af, const void *addr, char *str, size_t len);
86int ipx_pton(int af, const char *src, void *addr); 86int ipx_pton(int af, const char *src, void *addr);
87 87
88unsigned get_hz(void);
89
88POP_SAVED_FUNCTION_VISIBILITY 90POP_SAVED_FUNCTION_VISIBILITY
89 91
90#endif 92#endif