1*de1e4e89SAndroid Build Coastguard Worker /*
2*de1e4e89SAndroid Build Coastguard Worker * ipneigh.c "ip neigh".
3*de1e4e89SAndroid Build Coastguard Worker *
4*de1e4e89SAndroid Build Coastguard Worker * This program is free software; you can redistribute it and/or
5*de1e4e89SAndroid Build Coastguard Worker * modify it under the terms of the GNU General Public License
6*de1e4e89SAndroid Build Coastguard Worker * as published by the Free Software Foundation; either version
7*de1e4e89SAndroid Build Coastguard Worker * 2 of the License, or (at your option) any later version.
8*de1e4e89SAndroid Build Coastguard Worker *
9*de1e4e89SAndroid Build Coastguard Worker * Authors: Alexey Kuznetsov, <[email protected]>
10*de1e4e89SAndroid Build Coastguard Worker *
11*de1e4e89SAndroid Build Coastguard Worker */
12*de1e4e89SAndroid Build Coastguard Worker
13*de1e4e89SAndroid Build Coastguard Worker #include <stdio.h>
14*de1e4e89SAndroid Build Coastguard Worker #include <stdlib.h>
15*de1e4e89SAndroid Build Coastguard Worker #include <unistd.h>
16*de1e4e89SAndroid Build Coastguard Worker #include <syslog.h>
17*de1e4e89SAndroid Build Coastguard Worker #include <fcntl.h>
18*de1e4e89SAndroid Build Coastguard Worker #include <string.h>
19*de1e4e89SAndroid Build Coastguard Worker #include <sys/time.h>
20*de1e4e89SAndroid Build Coastguard Worker #include <sys/socket.h>
21*de1e4e89SAndroid Build Coastguard Worker #include <netinet/in.h>
22*de1e4e89SAndroid Build Coastguard Worker #include <netinet/ip.h>
23*de1e4e89SAndroid Build Coastguard Worker
24*de1e4e89SAndroid Build Coastguard Worker #include "rt_names.h"
25*de1e4e89SAndroid Build Coastguard Worker #include "utils.h"
26*de1e4e89SAndroid Build Coastguard Worker #include "ip_common.h"
27*de1e4e89SAndroid Build Coastguard Worker
28*de1e4e89SAndroid Build Coastguard Worker #define NUD_VALID (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE|NUD_PROBE|NUD_STALE|NUD_DELAY)
29*de1e4e89SAndroid Build Coastguard Worker #define MAX_ROUNDS 10
30*de1e4e89SAndroid Build Coastguard Worker
31*de1e4e89SAndroid Build Coastguard Worker static struct
32*de1e4e89SAndroid Build Coastguard Worker {
33*de1e4e89SAndroid Build Coastguard Worker int family;
34*de1e4e89SAndroid Build Coastguard Worker int index;
35*de1e4e89SAndroid Build Coastguard Worker int state;
36*de1e4e89SAndroid Build Coastguard Worker int unused_only;
37*de1e4e89SAndroid Build Coastguard Worker inet_prefix pfx;
38*de1e4e89SAndroid Build Coastguard Worker int flushed;
39*de1e4e89SAndroid Build Coastguard Worker char *flushb;
40*de1e4e89SAndroid Build Coastguard Worker int flushp;
41*de1e4e89SAndroid Build Coastguard Worker int flushe;
42*de1e4e89SAndroid Build Coastguard Worker int master;
43*de1e4e89SAndroid Build Coastguard Worker } filter;
44*de1e4e89SAndroid Build Coastguard Worker
45*de1e4e89SAndroid Build Coastguard Worker static void usage(void) __attribute__((noreturn));
46*de1e4e89SAndroid Build Coastguard Worker
usage(void)47*de1e4e89SAndroid Build Coastguard Worker static void usage(void)
48*de1e4e89SAndroid Build Coastguard Worker {
49*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Usage: ip neigh { add | del | change | replace }\n"
50*de1e4e89SAndroid Build Coastguard Worker " { ADDR [ lladdr LLADDR ] [ nud STATE ] | proxy ADDR } [ dev DEV ]\n");
51*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, " ip neigh { show | flush } [ proxy ] [ to PREFIX ] [ dev DEV ] [ nud STATE ]\n");
52*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, " [ vrf NAME ]\n\n");
53*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "STATE := { permanent | noarp | stale | reachable | none |\n"
54*de1e4e89SAndroid Build Coastguard Worker " incomplete | delay | probe | failed }\n");
55*de1e4e89SAndroid Build Coastguard Worker exit(-1);
56*de1e4e89SAndroid Build Coastguard Worker }
57*de1e4e89SAndroid Build Coastguard Worker
nud_state_a2n(unsigned int * state,const char * arg)58*de1e4e89SAndroid Build Coastguard Worker static int nud_state_a2n(unsigned int *state, const char *arg)
59*de1e4e89SAndroid Build Coastguard Worker {
60*de1e4e89SAndroid Build Coastguard Worker if (matches(arg, "permanent") == 0)
61*de1e4e89SAndroid Build Coastguard Worker *state = NUD_PERMANENT;
62*de1e4e89SAndroid Build Coastguard Worker else if (matches(arg, "reachable") == 0)
63*de1e4e89SAndroid Build Coastguard Worker *state = NUD_REACHABLE;
64*de1e4e89SAndroid Build Coastguard Worker else if (strcmp(arg, "noarp") == 0)
65*de1e4e89SAndroid Build Coastguard Worker *state = NUD_NOARP;
66*de1e4e89SAndroid Build Coastguard Worker else if (strcmp(arg, "none") == 0)
67*de1e4e89SAndroid Build Coastguard Worker *state = NUD_NONE;
68*de1e4e89SAndroid Build Coastguard Worker else if (strcmp(arg, "stale") == 0)
69*de1e4e89SAndroid Build Coastguard Worker *state = NUD_STALE;
70*de1e4e89SAndroid Build Coastguard Worker else if (strcmp(arg, "incomplete") == 0)
71*de1e4e89SAndroid Build Coastguard Worker *state = NUD_INCOMPLETE;
72*de1e4e89SAndroid Build Coastguard Worker else if (strcmp(arg, "delay") == 0)
73*de1e4e89SAndroid Build Coastguard Worker *state = NUD_DELAY;
74*de1e4e89SAndroid Build Coastguard Worker else if (strcmp(arg, "probe") == 0)
75*de1e4e89SAndroid Build Coastguard Worker *state = NUD_PROBE;
76*de1e4e89SAndroid Build Coastguard Worker else if (matches(arg, "failed") == 0)
77*de1e4e89SAndroid Build Coastguard Worker *state = NUD_FAILED;
78*de1e4e89SAndroid Build Coastguard Worker else {
79*de1e4e89SAndroid Build Coastguard Worker if (get_unsigned(state, arg, 0))
80*de1e4e89SAndroid Build Coastguard Worker return -1;
81*de1e4e89SAndroid Build Coastguard Worker if (*state >= 0x100 || (*state&((*state)-1)))
82*de1e4e89SAndroid Build Coastguard Worker return -1;
83*de1e4e89SAndroid Build Coastguard Worker }
84*de1e4e89SAndroid Build Coastguard Worker return 0;
85*de1e4e89SAndroid Build Coastguard Worker }
86*de1e4e89SAndroid Build Coastguard Worker
flush_update(void)87*de1e4e89SAndroid Build Coastguard Worker static int flush_update(void)
88*de1e4e89SAndroid Build Coastguard Worker {
89*de1e4e89SAndroid Build Coastguard Worker if (rtnl_send_check(&rth, filter.flushb, filter.flushp) < 0) {
90*de1e4e89SAndroid Build Coastguard Worker perror("Failed to send flush request");
91*de1e4e89SAndroid Build Coastguard Worker return -1;
92*de1e4e89SAndroid Build Coastguard Worker }
93*de1e4e89SAndroid Build Coastguard Worker filter.flushp = 0;
94*de1e4e89SAndroid Build Coastguard Worker return 0;
95*de1e4e89SAndroid Build Coastguard Worker }
96*de1e4e89SAndroid Build Coastguard Worker
97*de1e4e89SAndroid Build Coastguard Worker
ipneigh_modify(int cmd,int flags,int argc,char ** argv)98*de1e4e89SAndroid Build Coastguard Worker static int ipneigh_modify(int cmd, int flags, int argc, char **argv)
99*de1e4e89SAndroid Build Coastguard Worker {
100*de1e4e89SAndroid Build Coastguard Worker struct {
101*de1e4e89SAndroid Build Coastguard Worker struct nlmsghdr n;
102*de1e4e89SAndroid Build Coastguard Worker struct ndmsg ndm;
103*de1e4e89SAndroid Build Coastguard Worker char buf[256];
104*de1e4e89SAndroid Build Coastguard Worker } req = {
105*de1e4e89SAndroid Build Coastguard Worker .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)),
106*de1e4e89SAndroid Build Coastguard Worker .n.nlmsg_flags = NLM_F_REQUEST | flags,
107*de1e4e89SAndroid Build Coastguard Worker .n.nlmsg_type = cmd,
108*de1e4e89SAndroid Build Coastguard Worker .ndm.ndm_family = preferred_family,
109*de1e4e89SAndroid Build Coastguard Worker .ndm.ndm_state = NUD_PERMANENT,
110*de1e4e89SAndroid Build Coastguard Worker };
111*de1e4e89SAndroid Build Coastguard Worker char *dev = NULL;
112*de1e4e89SAndroid Build Coastguard Worker int dst_ok = 0;
113*de1e4e89SAndroid Build Coastguard Worker int dev_ok = 0;
114*de1e4e89SAndroid Build Coastguard Worker int lladdr_ok = 0;
115*de1e4e89SAndroid Build Coastguard Worker char *lla = NULL;
116*de1e4e89SAndroid Build Coastguard Worker inet_prefix dst;
117*de1e4e89SAndroid Build Coastguard Worker
118*de1e4e89SAndroid Build Coastguard Worker while (argc > 0) {
119*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "lladdr") == 0) {
120*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
121*de1e4e89SAndroid Build Coastguard Worker if (lladdr_ok)
122*de1e4e89SAndroid Build Coastguard Worker duparg("lladdr", *argv);
123*de1e4e89SAndroid Build Coastguard Worker lla = *argv;
124*de1e4e89SAndroid Build Coastguard Worker lladdr_ok = 1;
125*de1e4e89SAndroid Build Coastguard Worker } else if (strcmp(*argv, "nud") == 0) {
126*de1e4e89SAndroid Build Coastguard Worker unsigned int state;
127*de1e4e89SAndroid Build Coastguard Worker
128*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
129*de1e4e89SAndroid Build Coastguard Worker if (nud_state_a2n(&state, *argv))
130*de1e4e89SAndroid Build Coastguard Worker invarg("nud state is bad", *argv);
131*de1e4e89SAndroid Build Coastguard Worker req.ndm.ndm_state = state;
132*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "proxy") == 0) {
133*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
134*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "help") == 0)
135*de1e4e89SAndroid Build Coastguard Worker usage();
136*de1e4e89SAndroid Build Coastguard Worker if (dst_ok)
137*de1e4e89SAndroid Build Coastguard Worker duparg("address", *argv);
138*de1e4e89SAndroid Build Coastguard Worker get_addr(&dst, *argv, preferred_family);
139*de1e4e89SAndroid Build Coastguard Worker dst_ok = 1;
140*de1e4e89SAndroid Build Coastguard Worker dev_ok = 1;
141*de1e4e89SAndroid Build Coastguard Worker req.ndm.ndm_flags |= NTF_PROXY;
142*de1e4e89SAndroid Build Coastguard Worker } else if (strcmp(*argv, "dev") == 0) {
143*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
144*de1e4e89SAndroid Build Coastguard Worker dev = *argv;
145*de1e4e89SAndroid Build Coastguard Worker dev_ok = 1;
146*de1e4e89SAndroid Build Coastguard Worker } else {
147*de1e4e89SAndroid Build Coastguard Worker if (strcmp(*argv, "to") == 0) {
148*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
149*de1e4e89SAndroid Build Coastguard Worker }
150*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "help") == 0) {
151*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
152*de1e4e89SAndroid Build Coastguard Worker }
153*de1e4e89SAndroid Build Coastguard Worker if (dst_ok)
154*de1e4e89SAndroid Build Coastguard Worker duparg2("to", *argv);
155*de1e4e89SAndroid Build Coastguard Worker get_addr(&dst, *argv, preferred_family);
156*de1e4e89SAndroid Build Coastguard Worker dst_ok = 1;
157*de1e4e89SAndroid Build Coastguard Worker }
158*de1e4e89SAndroid Build Coastguard Worker argc--; argv++;
159*de1e4e89SAndroid Build Coastguard Worker }
160*de1e4e89SAndroid Build Coastguard Worker if (!dev_ok || !dst_ok || dst.family == AF_UNSPEC) {
161*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Device and destination are required arguments.\n");
162*de1e4e89SAndroid Build Coastguard Worker exit(-1);
163*de1e4e89SAndroid Build Coastguard Worker }
164*de1e4e89SAndroid Build Coastguard Worker req.ndm.ndm_family = dst.family;
165*de1e4e89SAndroid Build Coastguard Worker if (addattr_l(&req.n, sizeof(req), NDA_DST, &dst.data, dst.bytelen) < 0)
166*de1e4e89SAndroid Build Coastguard Worker return -1;
167*de1e4e89SAndroid Build Coastguard Worker
168*de1e4e89SAndroid Build Coastguard Worker if (lla && strcmp(lla, "null")) {
169*de1e4e89SAndroid Build Coastguard Worker char llabuf[20];
170*de1e4e89SAndroid Build Coastguard Worker int l;
171*de1e4e89SAndroid Build Coastguard Worker
172*de1e4e89SAndroid Build Coastguard Worker l = ll_addr_a2n(llabuf, sizeof(llabuf), lla);
173*de1e4e89SAndroid Build Coastguard Worker if (l < 0)
174*de1e4e89SAndroid Build Coastguard Worker return -1;
175*de1e4e89SAndroid Build Coastguard Worker
176*de1e4e89SAndroid Build Coastguard Worker if (addattr_l(&req.n, sizeof(req), NDA_LLADDR, llabuf, l) < 0)
177*de1e4e89SAndroid Build Coastguard Worker return -1;
178*de1e4e89SAndroid Build Coastguard Worker }
179*de1e4e89SAndroid Build Coastguard Worker
180*de1e4e89SAndroid Build Coastguard Worker ll_init_map(&rth);
181*de1e4e89SAndroid Build Coastguard Worker
182*de1e4e89SAndroid Build Coastguard Worker if (dev && (req.ndm.ndm_ifindex = ll_name_to_index(dev)) == 0) {
183*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Cannot find device \"%s\"\n", dev);
184*de1e4e89SAndroid Build Coastguard Worker return -1;
185*de1e4e89SAndroid Build Coastguard Worker }
186*de1e4e89SAndroid Build Coastguard Worker
187*de1e4e89SAndroid Build Coastguard Worker if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
188*de1e4e89SAndroid Build Coastguard Worker exit(2);
189*de1e4e89SAndroid Build Coastguard Worker
190*de1e4e89SAndroid Build Coastguard Worker return 0;
191*de1e4e89SAndroid Build Coastguard Worker }
192*de1e4e89SAndroid Build Coastguard Worker
193*de1e4e89SAndroid Build Coastguard Worker
print_neigh(const struct sockaddr_nl * who,struct nlmsghdr * n,void * arg)194*de1e4e89SAndroid Build Coastguard Worker int print_neigh(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
195*de1e4e89SAndroid Build Coastguard Worker {
196*de1e4e89SAndroid Build Coastguard Worker FILE *fp = (FILE *)arg;
197*de1e4e89SAndroid Build Coastguard Worker struct ndmsg *r = NLMSG_DATA(n);
198*de1e4e89SAndroid Build Coastguard Worker int len = n->nlmsg_len;
199*de1e4e89SAndroid Build Coastguard Worker struct rtattr *tb[NDA_MAX+1];
200*de1e4e89SAndroid Build Coastguard Worker static int logit = 1;
201*de1e4e89SAndroid Build Coastguard Worker
202*de1e4e89SAndroid Build Coastguard Worker if (n->nlmsg_type != RTM_NEWNEIGH && n->nlmsg_type != RTM_DELNEIGH &&
203*de1e4e89SAndroid Build Coastguard Worker n->nlmsg_type != RTM_GETNEIGH) {
204*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Not RTM_NEWNEIGH: %08x %08x %08x\n",
205*de1e4e89SAndroid Build Coastguard Worker n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
206*de1e4e89SAndroid Build Coastguard Worker
207*de1e4e89SAndroid Build Coastguard Worker return 0;
208*de1e4e89SAndroid Build Coastguard Worker }
209*de1e4e89SAndroid Build Coastguard Worker len -= NLMSG_LENGTH(sizeof(*r));
210*de1e4e89SAndroid Build Coastguard Worker if (len < 0) {
211*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
212*de1e4e89SAndroid Build Coastguard Worker return -1;
213*de1e4e89SAndroid Build Coastguard Worker }
214*de1e4e89SAndroid Build Coastguard Worker
215*de1e4e89SAndroid Build Coastguard Worker if (filter.flushb && n->nlmsg_type != RTM_NEWNEIGH)
216*de1e4e89SAndroid Build Coastguard Worker return 0;
217*de1e4e89SAndroid Build Coastguard Worker
218*de1e4e89SAndroid Build Coastguard Worker if (filter.family && filter.family != r->ndm_family)
219*de1e4e89SAndroid Build Coastguard Worker return 0;
220*de1e4e89SAndroid Build Coastguard Worker if (filter.index && filter.index != r->ndm_ifindex)
221*de1e4e89SAndroid Build Coastguard Worker return 0;
222*de1e4e89SAndroid Build Coastguard Worker if (!(filter.state&r->ndm_state) &&
223*de1e4e89SAndroid Build Coastguard Worker !(r->ndm_flags & NTF_PROXY) &&
224*de1e4e89SAndroid Build Coastguard Worker (r->ndm_state || !(filter.state&0x100)) &&
225*de1e4e89SAndroid Build Coastguard Worker (r->ndm_family != AF_DECnet))
226*de1e4e89SAndroid Build Coastguard Worker return 0;
227*de1e4e89SAndroid Build Coastguard Worker
228*de1e4e89SAndroid Build Coastguard Worker if (filter.master && !(n->nlmsg_flags & NLM_F_DUMP_FILTERED)) {
229*de1e4e89SAndroid Build Coastguard Worker if (logit) {
230*de1e4e89SAndroid Build Coastguard Worker logit = 0;
231*de1e4e89SAndroid Build Coastguard Worker fprintf(fp,
232*de1e4e89SAndroid Build Coastguard Worker "\nWARNING: Kernel does not support filtering by master device\n\n");
233*de1e4e89SAndroid Build Coastguard Worker }
234*de1e4e89SAndroid Build Coastguard Worker }
235*de1e4e89SAndroid Build Coastguard Worker
236*de1e4e89SAndroid Build Coastguard Worker parse_rtattr(tb, NDA_MAX, NDA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
237*de1e4e89SAndroid Build Coastguard Worker
238*de1e4e89SAndroid Build Coastguard Worker if (tb[NDA_DST]) {
239*de1e4e89SAndroid Build Coastguard Worker if (filter.pfx.family) {
240*de1e4e89SAndroid Build Coastguard Worker inet_prefix dst = { .family = r->ndm_family };
241*de1e4e89SAndroid Build Coastguard Worker
242*de1e4e89SAndroid Build Coastguard Worker memcpy(&dst.data, RTA_DATA(tb[NDA_DST]), RTA_PAYLOAD(tb[NDA_DST]));
243*de1e4e89SAndroid Build Coastguard Worker if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen))
244*de1e4e89SAndroid Build Coastguard Worker return 0;
245*de1e4e89SAndroid Build Coastguard Worker }
246*de1e4e89SAndroid Build Coastguard Worker }
247*de1e4e89SAndroid Build Coastguard Worker if (filter.unused_only && tb[NDA_CACHEINFO]) {
248*de1e4e89SAndroid Build Coastguard Worker struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]);
249*de1e4e89SAndroid Build Coastguard Worker
250*de1e4e89SAndroid Build Coastguard Worker if (ci->ndm_refcnt)
251*de1e4e89SAndroid Build Coastguard Worker return 0;
252*de1e4e89SAndroid Build Coastguard Worker }
253*de1e4e89SAndroid Build Coastguard Worker
254*de1e4e89SAndroid Build Coastguard Worker if (filter.flushb) {
255*de1e4e89SAndroid Build Coastguard Worker struct nlmsghdr *fn;
256*de1e4e89SAndroid Build Coastguard Worker
257*de1e4e89SAndroid Build Coastguard Worker if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) {
258*de1e4e89SAndroid Build Coastguard Worker if (flush_update())
259*de1e4e89SAndroid Build Coastguard Worker return -1;
260*de1e4e89SAndroid Build Coastguard Worker }
261*de1e4e89SAndroid Build Coastguard Worker fn = (struct nlmsghdr *)(filter.flushb + NLMSG_ALIGN(filter.flushp));
262*de1e4e89SAndroid Build Coastguard Worker memcpy(fn, n, n->nlmsg_len);
263*de1e4e89SAndroid Build Coastguard Worker fn->nlmsg_type = RTM_DELNEIGH;
264*de1e4e89SAndroid Build Coastguard Worker fn->nlmsg_flags = NLM_F_REQUEST;
265*de1e4e89SAndroid Build Coastguard Worker fn->nlmsg_seq = ++rth.seq;
266*de1e4e89SAndroid Build Coastguard Worker filter.flushp = (((char *)fn) + n->nlmsg_len) - filter.flushb;
267*de1e4e89SAndroid Build Coastguard Worker filter.flushed++;
268*de1e4e89SAndroid Build Coastguard Worker if (show_stats < 2)
269*de1e4e89SAndroid Build Coastguard Worker return 0;
270*de1e4e89SAndroid Build Coastguard Worker }
271*de1e4e89SAndroid Build Coastguard Worker
272*de1e4e89SAndroid Build Coastguard Worker if (n->nlmsg_type == RTM_DELNEIGH)
273*de1e4e89SAndroid Build Coastguard Worker fprintf(fp, "Deleted ");
274*de1e4e89SAndroid Build Coastguard Worker else if (n->nlmsg_type == RTM_GETNEIGH)
275*de1e4e89SAndroid Build Coastguard Worker fprintf(fp, "miss ");
276*de1e4e89SAndroid Build Coastguard Worker if (tb[NDA_DST]) {
277*de1e4e89SAndroid Build Coastguard Worker fprintf(fp, "%s ",
278*de1e4e89SAndroid Build Coastguard Worker format_host_rta(r->ndm_family, tb[NDA_DST]));
279*de1e4e89SAndroid Build Coastguard Worker }
280*de1e4e89SAndroid Build Coastguard Worker if (!filter.index && r->ndm_ifindex)
281*de1e4e89SAndroid Build Coastguard Worker fprintf(fp, "dev %s ", ll_index_to_name(r->ndm_ifindex));
282*de1e4e89SAndroid Build Coastguard Worker if (tb[NDA_LLADDR]) {
283*de1e4e89SAndroid Build Coastguard Worker SPRINT_BUF(b1);
284*de1e4e89SAndroid Build Coastguard Worker fprintf(fp, "lladdr %s", ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]),
285*de1e4e89SAndroid Build Coastguard Worker RTA_PAYLOAD(tb[NDA_LLADDR]),
286*de1e4e89SAndroid Build Coastguard Worker ll_index_to_type(r->ndm_ifindex),
287*de1e4e89SAndroid Build Coastguard Worker b1, sizeof(b1)));
288*de1e4e89SAndroid Build Coastguard Worker }
289*de1e4e89SAndroid Build Coastguard Worker if (r->ndm_flags & NTF_ROUTER) {
290*de1e4e89SAndroid Build Coastguard Worker fprintf(fp, " router");
291*de1e4e89SAndroid Build Coastguard Worker }
292*de1e4e89SAndroid Build Coastguard Worker if (r->ndm_flags & NTF_PROXY) {
293*de1e4e89SAndroid Build Coastguard Worker fprintf(fp, " proxy");
294*de1e4e89SAndroid Build Coastguard Worker }
295*de1e4e89SAndroid Build Coastguard Worker if (tb[NDA_CACHEINFO] && show_stats) {
296*de1e4e89SAndroid Build Coastguard Worker struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]);
297*de1e4e89SAndroid Build Coastguard Worker int hz = get_user_hz();
298*de1e4e89SAndroid Build Coastguard Worker
299*de1e4e89SAndroid Build Coastguard Worker if (ci->ndm_refcnt)
300*de1e4e89SAndroid Build Coastguard Worker printf(" ref %d", ci->ndm_refcnt);
301*de1e4e89SAndroid Build Coastguard Worker fprintf(fp, " used %d/%d/%d", ci->ndm_used/hz,
302*de1e4e89SAndroid Build Coastguard Worker ci->ndm_confirmed/hz, ci->ndm_updated/hz);
303*de1e4e89SAndroid Build Coastguard Worker }
304*de1e4e89SAndroid Build Coastguard Worker
305*de1e4e89SAndroid Build Coastguard Worker if (tb[NDA_PROBES] && show_stats) {
306*de1e4e89SAndroid Build Coastguard Worker __u32 p = rta_getattr_u32(tb[NDA_PROBES]);
307*de1e4e89SAndroid Build Coastguard Worker
308*de1e4e89SAndroid Build Coastguard Worker fprintf(fp, " probes %u", p);
309*de1e4e89SAndroid Build Coastguard Worker }
310*de1e4e89SAndroid Build Coastguard Worker
311*de1e4e89SAndroid Build Coastguard Worker if (r->ndm_state) {
312*de1e4e89SAndroid Build Coastguard Worker int nud = r->ndm_state;
313*de1e4e89SAndroid Build Coastguard Worker
314*de1e4e89SAndroid Build Coastguard Worker fprintf(fp, " ");
315*de1e4e89SAndroid Build Coastguard Worker
316*de1e4e89SAndroid Build Coastguard Worker #define PRINT_FLAG(f) if (nud & NUD_##f) { \
317*de1e4e89SAndroid Build Coastguard Worker nud &= ~NUD_##f; fprintf(fp, #f "%s", nud ? "," : ""); }
318*de1e4e89SAndroid Build Coastguard Worker PRINT_FLAG(INCOMPLETE);
319*de1e4e89SAndroid Build Coastguard Worker PRINT_FLAG(REACHABLE);
320*de1e4e89SAndroid Build Coastguard Worker PRINT_FLAG(STALE);
321*de1e4e89SAndroid Build Coastguard Worker PRINT_FLAG(DELAY);
322*de1e4e89SAndroid Build Coastguard Worker PRINT_FLAG(PROBE);
323*de1e4e89SAndroid Build Coastguard Worker PRINT_FLAG(FAILED);
324*de1e4e89SAndroid Build Coastguard Worker PRINT_FLAG(NOARP);
325*de1e4e89SAndroid Build Coastguard Worker PRINT_FLAG(PERMANENT);
326*de1e4e89SAndroid Build Coastguard Worker #undef PRINT_FLAG
327*de1e4e89SAndroid Build Coastguard Worker }
328*de1e4e89SAndroid Build Coastguard Worker fprintf(fp, "\n");
329*de1e4e89SAndroid Build Coastguard Worker
330*de1e4e89SAndroid Build Coastguard Worker fflush(fp);
331*de1e4e89SAndroid Build Coastguard Worker return 0;
332*de1e4e89SAndroid Build Coastguard Worker }
333*de1e4e89SAndroid Build Coastguard Worker
ipneigh_reset_filter(int ifindex)334*de1e4e89SAndroid Build Coastguard Worker void ipneigh_reset_filter(int ifindex)
335*de1e4e89SAndroid Build Coastguard Worker {
336*de1e4e89SAndroid Build Coastguard Worker memset(&filter, 0, sizeof(filter));
337*de1e4e89SAndroid Build Coastguard Worker filter.state = ~0;
338*de1e4e89SAndroid Build Coastguard Worker filter.index = ifindex;
339*de1e4e89SAndroid Build Coastguard Worker }
340*de1e4e89SAndroid Build Coastguard Worker
do_show_or_flush(int argc,char ** argv,int flush)341*de1e4e89SAndroid Build Coastguard Worker static int do_show_or_flush(int argc, char **argv, int flush)
342*de1e4e89SAndroid Build Coastguard Worker {
343*de1e4e89SAndroid Build Coastguard Worker struct {
344*de1e4e89SAndroid Build Coastguard Worker struct nlmsghdr n;
345*de1e4e89SAndroid Build Coastguard Worker struct ndmsg ndm;
346*de1e4e89SAndroid Build Coastguard Worker char buf[256];
347*de1e4e89SAndroid Build Coastguard Worker } req = {
348*de1e4e89SAndroid Build Coastguard Worker .n.nlmsg_type = RTM_GETNEIGH,
349*de1e4e89SAndroid Build Coastguard Worker .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)),
350*de1e4e89SAndroid Build Coastguard Worker };
351*de1e4e89SAndroid Build Coastguard Worker char *filter_dev = NULL;
352*de1e4e89SAndroid Build Coastguard Worker int state_given = 0;
353*de1e4e89SAndroid Build Coastguard Worker
354*de1e4e89SAndroid Build Coastguard Worker ipneigh_reset_filter(0);
355*de1e4e89SAndroid Build Coastguard Worker
356*de1e4e89SAndroid Build Coastguard Worker if (!filter.family)
357*de1e4e89SAndroid Build Coastguard Worker filter.family = preferred_family;
358*de1e4e89SAndroid Build Coastguard Worker
359*de1e4e89SAndroid Build Coastguard Worker if (flush) {
360*de1e4e89SAndroid Build Coastguard Worker if (argc <= 0) {
361*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Flush requires arguments.\n");
362*de1e4e89SAndroid Build Coastguard Worker return -1;
363*de1e4e89SAndroid Build Coastguard Worker }
364*de1e4e89SAndroid Build Coastguard Worker filter.state = ~(NUD_PERMANENT|NUD_NOARP);
365*de1e4e89SAndroid Build Coastguard Worker } else
366*de1e4e89SAndroid Build Coastguard Worker filter.state = 0xFF & ~NUD_NOARP;
367*de1e4e89SAndroid Build Coastguard Worker
368*de1e4e89SAndroid Build Coastguard Worker while (argc > 0) {
369*de1e4e89SAndroid Build Coastguard Worker if (strcmp(*argv, "dev") == 0) {
370*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
371*de1e4e89SAndroid Build Coastguard Worker if (filter_dev)
372*de1e4e89SAndroid Build Coastguard Worker duparg("dev", *argv);
373*de1e4e89SAndroid Build Coastguard Worker filter_dev = *argv;
374*de1e4e89SAndroid Build Coastguard Worker } else if (strcmp(*argv, "master") == 0) {
375*de1e4e89SAndroid Build Coastguard Worker int ifindex;
376*de1e4e89SAndroid Build Coastguard Worker
377*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
378*de1e4e89SAndroid Build Coastguard Worker ifindex = ll_name_to_index(*argv);
379*de1e4e89SAndroid Build Coastguard Worker if (!ifindex)
380*de1e4e89SAndroid Build Coastguard Worker invarg("Device does not exist\n", *argv);
381*de1e4e89SAndroid Build Coastguard Worker addattr32(&req.n, sizeof(req), NDA_MASTER, ifindex);
382*de1e4e89SAndroid Build Coastguard Worker filter.master = ifindex;
383*de1e4e89SAndroid Build Coastguard Worker } else if (strcmp(*argv, "vrf") == 0) {
384*de1e4e89SAndroid Build Coastguard Worker int ifindex;
385*de1e4e89SAndroid Build Coastguard Worker
386*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
387*de1e4e89SAndroid Build Coastguard Worker ifindex = ll_name_to_index(*argv);
388*de1e4e89SAndroid Build Coastguard Worker if (!ifindex)
389*de1e4e89SAndroid Build Coastguard Worker invarg("Not a valid VRF name\n", *argv);
390*de1e4e89SAndroid Build Coastguard Worker if (!name_is_vrf(*argv))
391*de1e4e89SAndroid Build Coastguard Worker invarg("Not a valid VRF name\n", *argv);
392*de1e4e89SAndroid Build Coastguard Worker addattr32(&req.n, sizeof(req), NDA_MASTER, ifindex);
393*de1e4e89SAndroid Build Coastguard Worker filter.master = ifindex;
394*de1e4e89SAndroid Build Coastguard Worker } else if (strcmp(*argv, "unused") == 0) {
395*de1e4e89SAndroid Build Coastguard Worker filter.unused_only = 1;
396*de1e4e89SAndroid Build Coastguard Worker } else if (strcmp(*argv, "nud") == 0) {
397*de1e4e89SAndroid Build Coastguard Worker unsigned int state;
398*de1e4e89SAndroid Build Coastguard Worker
399*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
400*de1e4e89SAndroid Build Coastguard Worker if (!state_given) {
401*de1e4e89SAndroid Build Coastguard Worker state_given = 1;
402*de1e4e89SAndroid Build Coastguard Worker filter.state = 0;
403*de1e4e89SAndroid Build Coastguard Worker }
404*de1e4e89SAndroid Build Coastguard Worker if (nud_state_a2n(&state, *argv)) {
405*de1e4e89SAndroid Build Coastguard Worker if (strcmp(*argv, "all") != 0)
406*de1e4e89SAndroid Build Coastguard Worker invarg("nud state is bad", *argv);
407*de1e4e89SAndroid Build Coastguard Worker state = ~0;
408*de1e4e89SAndroid Build Coastguard Worker if (flush)
409*de1e4e89SAndroid Build Coastguard Worker state &= ~NUD_NOARP;
410*de1e4e89SAndroid Build Coastguard Worker }
411*de1e4e89SAndroid Build Coastguard Worker if (state == 0)
412*de1e4e89SAndroid Build Coastguard Worker state = 0x100;
413*de1e4e89SAndroid Build Coastguard Worker filter.state |= state;
414*de1e4e89SAndroid Build Coastguard Worker } else if (strcmp(*argv, "proxy") == 0)
415*de1e4e89SAndroid Build Coastguard Worker req.ndm.ndm_flags = NTF_PROXY;
416*de1e4e89SAndroid Build Coastguard Worker else {
417*de1e4e89SAndroid Build Coastguard Worker if (strcmp(*argv, "to") == 0) {
418*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
419*de1e4e89SAndroid Build Coastguard Worker }
420*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "help") == 0)
421*de1e4e89SAndroid Build Coastguard Worker usage();
422*de1e4e89SAndroid Build Coastguard Worker get_prefix(&filter.pfx, *argv, filter.family);
423*de1e4e89SAndroid Build Coastguard Worker if (filter.family == AF_UNSPEC)
424*de1e4e89SAndroid Build Coastguard Worker filter.family = filter.pfx.family;
425*de1e4e89SAndroid Build Coastguard Worker }
426*de1e4e89SAndroid Build Coastguard Worker argc--; argv++;
427*de1e4e89SAndroid Build Coastguard Worker }
428*de1e4e89SAndroid Build Coastguard Worker
429*de1e4e89SAndroid Build Coastguard Worker ll_init_map(&rth);
430*de1e4e89SAndroid Build Coastguard Worker
431*de1e4e89SAndroid Build Coastguard Worker if (filter_dev) {
432*de1e4e89SAndroid Build Coastguard Worker if ((filter.index = ll_name_to_index(filter_dev)) == 0) {
433*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Cannot find device \"%s\"\n", filter_dev);
434*de1e4e89SAndroid Build Coastguard Worker return -1;
435*de1e4e89SAndroid Build Coastguard Worker }
436*de1e4e89SAndroid Build Coastguard Worker addattr32(&req.n, sizeof(req), NDA_IFINDEX, filter.index);
437*de1e4e89SAndroid Build Coastguard Worker }
438*de1e4e89SAndroid Build Coastguard Worker
439*de1e4e89SAndroid Build Coastguard Worker req.ndm.ndm_family = filter.family;
440*de1e4e89SAndroid Build Coastguard Worker
441*de1e4e89SAndroid Build Coastguard Worker if (flush) {
442*de1e4e89SAndroid Build Coastguard Worker int round = 0;
443*de1e4e89SAndroid Build Coastguard Worker char flushb[4096-512];
444*de1e4e89SAndroid Build Coastguard Worker
445*de1e4e89SAndroid Build Coastguard Worker filter.flushb = flushb;
446*de1e4e89SAndroid Build Coastguard Worker filter.flushp = 0;
447*de1e4e89SAndroid Build Coastguard Worker filter.flushe = sizeof(flushb);
448*de1e4e89SAndroid Build Coastguard Worker
449*de1e4e89SAndroid Build Coastguard Worker while (round < MAX_ROUNDS) {
450*de1e4e89SAndroid Build Coastguard Worker if (rtnl_dump_request_n(&rth, &req.n) < 0) {
451*de1e4e89SAndroid Build Coastguard Worker perror("Cannot send dump request");
452*de1e4e89SAndroid Build Coastguard Worker exit(1);
453*de1e4e89SAndroid Build Coastguard Worker }
454*de1e4e89SAndroid Build Coastguard Worker filter.flushed = 0;
455*de1e4e89SAndroid Build Coastguard Worker if (rtnl_dump_filter(&rth, print_neigh, stdout) < 0) {
456*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Flush terminated\n");
457*de1e4e89SAndroid Build Coastguard Worker exit(1);
458*de1e4e89SAndroid Build Coastguard Worker }
459*de1e4e89SAndroid Build Coastguard Worker if (filter.flushed == 0) {
460*de1e4e89SAndroid Build Coastguard Worker if (show_stats) {
461*de1e4e89SAndroid Build Coastguard Worker if (round == 0)
462*de1e4e89SAndroid Build Coastguard Worker printf("Nothing to flush.\n");
463*de1e4e89SAndroid Build Coastguard Worker else
464*de1e4e89SAndroid Build Coastguard Worker printf("*** Flush is complete after %d round%s ***\n", round, round > 1?"s":"");
465*de1e4e89SAndroid Build Coastguard Worker }
466*de1e4e89SAndroid Build Coastguard Worker fflush(stdout);
467*de1e4e89SAndroid Build Coastguard Worker return 0;
468*de1e4e89SAndroid Build Coastguard Worker }
469*de1e4e89SAndroid Build Coastguard Worker round++;
470*de1e4e89SAndroid Build Coastguard Worker if (flush_update() < 0)
471*de1e4e89SAndroid Build Coastguard Worker exit(1);
472*de1e4e89SAndroid Build Coastguard Worker if (show_stats) {
473*de1e4e89SAndroid Build Coastguard Worker printf("\n*** Round %d, deleting %d entries ***\n", round, filter.flushed);
474*de1e4e89SAndroid Build Coastguard Worker fflush(stdout);
475*de1e4e89SAndroid Build Coastguard Worker }
476*de1e4e89SAndroid Build Coastguard Worker filter.state &= ~NUD_FAILED;
477*de1e4e89SAndroid Build Coastguard Worker }
478*de1e4e89SAndroid Build Coastguard Worker printf("*** Flush not complete bailing out after %d rounds\n",
479*de1e4e89SAndroid Build Coastguard Worker MAX_ROUNDS);
480*de1e4e89SAndroid Build Coastguard Worker return 1;
481*de1e4e89SAndroid Build Coastguard Worker }
482*de1e4e89SAndroid Build Coastguard Worker
483*de1e4e89SAndroid Build Coastguard Worker if (rtnl_dump_request_n(&rth, &req.n) < 0) {
484*de1e4e89SAndroid Build Coastguard Worker perror("Cannot send dump request");
485*de1e4e89SAndroid Build Coastguard Worker exit(1);
486*de1e4e89SAndroid Build Coastguard Worker }
487*de1e4e89SAndroid Build Coastguard Worker
488*de1e4e89SAndroid Build Coastguard Worker if (rtnl_dump_filter(&rth, print_neigh, stdout) < 0) {
489*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Dump terminated\n");
490*de1e4e89SAndroid Build Coastguard Worker exit(1);
491*de1e4e89SAndroid Build Coastguard Worker }
492*de1e4e89SAndroid Build Coastguard Worker
493*de1e4e89SAndroid Build Coastguard Worker return 0;
494*de1e4e89SAndroid Build Coastguard Worker }
495*de1e4e89SAndroid Build Coastguard Worker
do_ipneigh(int argc,char ** argv)496*de1e4e89SAndroid Build Coastguard Worker int do_ipneigh(int argc, char **argv)
497*de1e4e89SAndroid Build Coastguard Worker {
498*de1e4e89SAndroid Build Coastguard Worker if (argc > 0) {
499*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "add") == 0)
500*de1e4e89SAndroid Build Coastguard Worker return ipneigh_modify(RTM_NEWNEIGH, NLM_F_CREATE|NLM_F_EXCL, argc-1, argv+1);
501*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "change") == 0 ||
502*de1e4e89SAndroid Build Coastguard Worker strcmp(*argv, "chg") == 0)
503*de1e4e89SAndroid Build Coastguard Worker return ipneigh_modify(RTM_NEWNEIGH, NLM_F_REPLACE, argc-1, argv+1);
504*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "replace") == 0)
505*de1e4e89SAndroid Build Coastguard Worker return ipneigh_modify(RTM_NEWNEIGH, NLM_F_CREATE|NLM_F_REPLACE, argc-1, argv+1);
506*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "delete") == 0)
507*de1e4e89SAndroid Build Coastguard Worker return ipneigh_modify(RTM_DELNEIGH, 0, argc-1, argv+1);
508*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "get") == 0) {
509*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Sorry, \"neigh get\" is not implemented :-(\n");
510*de1e4e89SAndroid Build Coastguard Worker return -1;
511*de1e4e89SAndroid Build Coastguard Worker }
512*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "show") == 0 ||
513*de1e4e89SAndroid Build Coastguard Worker matches(*argv, "lst") == 0 ||
514*de1e4e89SAndroid Build Coastguard Worker matches(*argv, "list") == 0)
515*de1e4e89SAndroid Build Coastguard Worker return do_show_or_flush(argc-1, argv+1, 0);
516*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "flush") == 0)
517*de1e4e89SAndroid Build Coastguard Worker return do_show_or_flush(argc-1, argv+1, 1);
518*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "help") == 0)
519*de1e4e89SAndroid Build Coastguard Worker usage();
520*de1e4e89SAndroid Build Coastguard Worker } else
521*de1e4e89SAndroid Build Coastguard Worker return do_show_or_flush(0, NULL, 0);
522*de1e4e89SAndroid Build Coastguard Worker
523*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Command \"%s\" is unknown, try \"ip neigh help\".\n", *argv);
524*de1e4e89SAndroid Build Coastguard Worker exit(-1);
525*de1e4e89SAndroid Build Coastguard Worker }
526