xref: /aosp_15_r20/external/iproute2/ip/ipneigh.c (revision de1e4e894b0c224df933550f0afdecc354b238c4)
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