xref: /aosp_15_r20/external/iputils/arping.c (revision bd1f8aeb6080fa6544ec30aeca3eb4da100f359f)
1*bd1f8aebSAndroid Build Coastguard Worker /*
2*bd1f8aebSAndroid Build Coastguard Worker  * arping.c
3*bd1f8aebSAndroid Build Coastguard Worker  *
4*bd1f8aebSAndroid Build Coastguard Worker  *		This program is free software; you can redistribute it and/or
5*bd1f8aebSAndroid Build Coastguard Worker  *		modify it under the terms of the GNU General Public License
6*bd1f8aebSAndroid Build Coastguard Worker  *		as published by the Free Software Foundation; either version
7*bd1f8aebSAndroid Build Coastguard Worker  *		2 of the License, or (at your option) any later version.
8*bd1f8aebSAndroid Build Coastguard Worker  *
9*bd1f8aebSAndroid Build Coastguard Worker  * Authors:	Alexey Kuznetsov, <[email protected]>
10*bd1f8aebSAndroid Build Coastguard Worker  * 		YOSHIFUJI Hideaki <[email protected]>
11*bd1f8aebSAndroid Build Coastguard Worker  */
12*bd1f8aebSAndroid Build Coastguard Worker 
13*bd1f8aebSAndroid Build Coastguard Worker #include <stdlib.h>
14*bd1f8aebSAndroid Build Coastguard Worker #include <sys/param.h>
15*bd1f8aebSAndroid Build Coastguard Worker #include <sys/socket.h>
16*bd1f8aebSAndroid Build Coastguard Worker #include <linux/sockios.h>
17*bd1f8aebSAndroid Build Coastguard Worker #include <sys/file.h>
18*bd1f8aebSAndroid Build Coastguard Worker #include <sys/time.h>
19*bd1f8aebSAndroid Build Coastguard Worker #include <sys/signal.h>
20*bd1f8aebSAndroid Build Coastguard Worker #include <sys/ioctl.h>
21*bd1f8aebSAndroid Build Coastguard Worker #include <net/if.h>
22*bd1f8aebSAndroid Build Coastguard Worker #include <linux/if_packet.h>
23*bd1f8aebSAndroid Build Coastguard Worker #include <linux/if_ether.h>
24*bd1f8aebSAndroid Build Coastguard Worker #include <net/if_arp.h>
25*bd1f8aebSAndroid Build Coastguard Worker #include <sys/uio.h>
26*bd1f8aebSAndroid Build Coastguard Worker #ifdef CAPABILITIES
27*bd1f8aebSAndroid Build Coastguard Worker #include <sys/prctl.h>
28*bd1f8aebSAndroid Build Coastguard Worker #include <sys/capability.h>
29*bd1f8aebSAndroid Build Coastguard Worker #endif
30*bd1f8aebSAndroid Build Coastguard Worker 
31*bd1f8aebSAndroid Build Coastguard Worker #include <netdb.h>
32*bd1f8aebSAndroid Build Coastguard Worker #include <unistd.h>
33*bd1f8aebSAndroid Build Coastguard Worker #include <stdio.h>
34*bd1f8aebSAndroid Build Coastguard Worker #include <ctype.h>
35*bd1f8aebSAndroid Build Coastguard Worker #include <errno.h>
36*bd1f8aebSAndroid Build Coastguard Worker #include <string.h>
37*bd1f8aebSAndroid Build Coastguard Worker #include <netinet/in.h>
38*bd1f8aebSAndroid Build Coastguard Worker #include <arpa/inet.h>
39*bd1f8aebSAndroid Build Coastguard Worker 
40*bd1f8aebSAndroid Build Coastguard Worker #ifdef USE_SYSFS
41*bd1f8aebSAndroid Build Coastguard Worker #include <sysfs/libsysfs.h>
42*bd1f8aebSAndroid Build Coastguard Worker struct sysfs_devattr_values;
43*bd1f8aebSAndroid Build Coastguard Worker #endif
44*bd1f8aebSAndroid Build Coastguard Worker 
45*bd1f8aebSAndroid Build Coastguard Worker #ifndef WITHOUT_IFADDRS
46*bd1f8aebSAndroid Build Coastguard Worker #include <ifaddrs.h>
47*bd1f8aebSAndroid Build Coastguard Worker #endif
48*bd1f8aebSAndroid Build Coastguard Worker 
49*bd1f8aebSAndroid Build Coastguard Worker #ifdef USE_IDN
50*bd1f8aebSAndroid Build Coastguard Worker #include <idna.h>
51*bd1f8aebSAndroid Build Coastguard Worker #include <locale.h>
52*bd1f8aebSAndroid Build Coastguard Worker #endif
53*bd1f8aebSAndroid Build Coastguard Worker 
54*bd1f8aebSAndroid Build Coastguard Worker #include "SNAPSHOT.h"
55*bd1f8aebSAndroid Build Coastguard Worker 
56*bd1f8aebSAndroid Build Coastguard Worker static void usage(void) __attribute__((noreturn));
57*bd1f8aebSAndroid Build Coastguard Worker 
58*bd1f8aebSAndroid Build Coastguard Worker #ifdef DEFAULT_DEVICE
59*bd1f8aebSAndroid Build Coastguard Worker # define DEFAULT_DEVICE_STR	DEFAULT_DEVICE
60*bd1f8aebSAndroid Build Coastguard Worker #else
61*bd1f8aebSAndroid Build Coastguard Worker # define DEFAULT_DEVICE		NULL
62*bd1f8aebSAndroid Build Coastguard Worker #endif
63*bd1f8aebSAndroid Build Coastguard Worker 
64*bd1f8aebSAndroid Build Coastguard Worker struct device {
65*bd1f8aebSAndroid Build Coastguard Worker 	char *name;
66*bd1f8aebSAndroid Build Coastguard Worker 	int ifindex;
67*bd1f8aebSAndroid Build Coastguard Worker #ifndef WITHOUT_IFADDRS
68*bd1f8aebSAndroid Build Coastguard Worker 	struct ifaddrs *ifa;
69*bd1f8aebSAndroid Build Coastguard Worker #endif
70*bd1f8aebSAndroid Build Coastguard Worker #ifdef USE_SYSFS
71*bd1f8aebSAndroid Build Coastguard Worker 	struct sysfs_devattr_values *sysfs;
72*bd1f8aebSAndroid Build Coastguard Worker #endif
73*bd1f8aebSAndroid Build Coastguard Worker };
74*bd1f8aebSAndroid Build Coastguard Worker 
75*bd1f8aebSAndroid Build Coastguard Worker int quit_on_reply=0;
76*bd1f8aebSAndroid Build Coastguard Worker struct device device = {
77*bd1f8aebSAndroid Build Coastguard Worker 	.name = DEFAULT_DEVICE,
78*bd1f8aebSAndroid Build Coastguard Worker };
79*bd1f8aebSAndroid Build Coastguard Worker char *source;
80*bd1f8aebSAndroid Build Coastguard Worker struct in_addr src, dst;
81*bd1f8aebSAndroid Build Coastguard Worker char *target;
82*bd1f8aebSAndroid Build Coastguard Worker int dad, unsolicited, advert;
83*bd1f8aebSAndroid Build Coastguard Worker int quiet;
84*bd1f8aebSAndroid Build Coastguard Worker int count=-1;
85*bd1f8aebSAndroid Build Coastguard Worker int timeout;
86*bd1f8aebSAndroid Build Coastguard Worker int unicasting;
87*bd1f8aebSAndroid Build Coastguard Worker int s;
88*bd1f8aebSAndroid Build Coastguard Worker int broadcast_only;
89*bd1f8aebSAndroid Build Coastguard Worker 
90*bd1f8aebSAndroid Build Coastguard Worker struct sockaddr_storage me;
91*bd1f8aebSAndroid Build Coastguard Worker struct sockaddr_storage he;
92*bd1f8aebSAndroid Build Coastguard Worker 
93*bd1f8aebSAndroid Build Coastguard Worker struct timeval start, last;
94*bd1f8aebSAndroid Build Coastguard Worker 
95*bd1f8aebSAndroid Build Coastguard Worker int sent, brd_sent;
96*bd1f8aebSAndroid Build Coastguard Worker int received, brd_recv, req_recv;
97*bd1f8aebSAndroid Build Coastguard Worker 
98*bd1f8aebSAndroid Build Coastguard Worker #ifndef CAPABILITIES
99*bd1f8aebSAndroid Build Coastguard Worker static uid_t euid;
100*bd1f8aebSAndroid Build Coastguard Worker #endif
101*bd1f8aebSAndroid Build Coastguard Worker 
102*bd1f8aebSAndroid Build Coastguard Worker #define MS_TDIFF(tv1,tv2) ( ((tv1).tv_sec-(tv2).tv_sec)*1000 + \
103*bd1f8aebSAndroid Build Coastguard Worker 			   ((tv1).tv_usec-(tv2).tv_usec)/1000 )
104*bd1f8aebSAndroid Build Coastguard Worker 
105*bd1f8aebSAndroid Build Coastguard Worker #define OFFSET_OF(name,ele)	((size_t)(((name *)0)->ele))
106*bd1f8aebSAndroid Build Coastguard Worker 
sll_len(size_t halen)107*bd1f8aebSAndroid Build Coastguard Worker static inline socklen_t sll_len(size_t halen)
108*bd1f8aebSAndroid Build Coastguard Worker {
109*bd1f8aebSAndroid Build Coastguard Worker 	socklen_t len = OFFSET_OF(struct sockaddr_ll, sll_addr) + halen;
110*bd1f8aebSAndroid Build Coastguard Worker 	if (len < sizeof(struct sockaddr_ll))
111*bd1f8aebSAndroid Build Coastguard Worker 		len = sizeof(struct sockaddr_ll);
112*bd1f8aebSAndroid Build Coastguard Worker 	return len;
113*bd1f8aebSAndroid Build Coastguard Worker }
114*bd1f8aebSAndroid Build Coastguard Worker 
115*bd1f8aebSAndroid Build Coastguard Worker #define SLL_LEN(hln)		sll_len(hln)
116*bd1f8aebSAndroid Build Coastguard Worker 
usage(void)117*bd1f8aebSAndroid Build Coastguard Worker void usage(void)
118*bd1f8aebSAndroid Build Coastguard Worker {
119*bd1f8aebSAndroid Build Coastguard Worker 	fprintf(stderr,
120*bd1f8aebSAndroid Build Coastguard Worker 		"Usage: arping [-fqbDUAV] [-c count] [-w timeout] [-I device] [-s source] destination\n"
121*bd1f8aebSAndroid Build Coastguard Worker 		"  -f : quit on first reply\n"
122*bd1f8aebSAndroid Build Coastguard Worker 		"  -q : be quiet\n"
123*bd1f8aebSAndroid Build Coastguard Worker 		"  -b : keep broadcasting, don't go unicast\n"
124*bd1f8aebSAndroid Build Coastguard Worker 		"  -D : duplicate address detection mode\n"
125*bd1f8aebSAndroid Build Coastguard Worker 		"  -U : Unsolicited ARP mode, update your neighbours\n"
126*bd1f8aebSAndroid Build Coastguard Worker 		"  -A : ARP answer mode, update your neighbours\n"
127*bd1f8aebSAndroid Build Coastguard Worker 		"  -V : print version and exit\n"
128*bd1f8aebSAndroid Build Coastguard Worker 		"  -c count : how many packets to send\n"
129*bd1f8aebSAndroid Build Coastguard Worker 		"  -w timeout : how long to wait for a reply\n"
130*bd1f8aebSAndroid Build Coastguard Worker 		"  -I device : which ethernet device to use"
131*bd1f8aebSAndroid Build Coastguard Worker #ifdef DEFAULT_DEVICE_STR
132*bd1f8aebSAndroid Build Coastguard Worker 			" (" DEFAULT_DEVICE_STR ")"
133*bd1f8aebSAndroid Build Coastguard Worker #endif
134*bd1f8aebSAndroid Build Coastguard Worker 			"\n"
135*bd1f8aebSAndroid Build Coastguard Worker 		"  -s source : source ip address\n"
136*bd1f8aebSAndroid Build Coastguard Worker 		"  destination : ask for what ip address\n"
137*bd1f8aebSAndroid Build Coastguard Worker 		);
138*bd1f8aebSAndroid Build Coastguard Worker 	exit(2);
139*bd1f8aebSAndroid Build Coastguard Worker }
140*bd1f8aebSAndroid Build Coastguard Worker 
set_signal(int signo,void (* handler)(void))141*bd1f8aebSAndroid Build Coastguard Worker void set_signal(int signo, void (*handler)(void))
142*bd1f8aebSAndroid Build Coastguard Worker {
143*bd1f8aebSAndroid Build Coastguard Worker 	struct sigaction sa;
144*bd1f8aebSAndroid Build Coastguard Worker 
145*bd1f8aebSAndroid Build Coastguard Worker 	memset(&sa, 0, sizeof(sa));
146*bd1f8aebSAndroid Build Coastguard Worker 	sa.sa_handler = (void (*)(int))handler;
147*bd1f8aebSAndroid Build Coastguard Worker 	sa.sa_flags = SA_RESTART;
148*bd1f8aebSAndroid Build Coastguard Worker 	sigaction(signo, &sa, NULL);
149*bd1f8aebSAndroid Build Coastguard Worker }
150*bd1f8aebSAndroid Build Coastguard Worker 
151*bd1f8aebSAndroid Build Coastguard Worker #ifdef CAPABILITIES
152*bd1f8aebSAndroid Build Coastguard Worker static const cap_value_t caps[] = { CAP_NET_RAW, };
153*bd1f8aebSAndroid Build Coastguard Worker static cap_flag_value_t cap_raw = CAP_CLEAR;
154*bd1f8aebSAndroid Build Coastguard Worker #endif
155*bd1f8aebSAndroid Build Coastguard Worker 
limit_capabilities(void)156*bd1f8aebSAndroid Build Coastguard Worker void limit_capabilities(void)
157*bd1f8aebSAndroid Build Coastguard Worker {
158*bd1f8aebSAndroid Build Coastguard Worker #ifdef CAPABILITIES
159*bd1f8aebSAndroid Build Coastguard Worker 	cap_t cap_p;
160*bd1f8aebSAndroid Build Coastguard Worker 
161*bd1f8aebSAndroid Build Coastguard Worker 	cap_p = cap_get_proc();
162*bd1f8aebSAndroid Build Coastguard Worker 	if (!cap_p) {
163*bd1f8aebSAndroid Build Coastguard Worker 		perror("arping: cap_get_proc");
164*bd1f8aebSAndroid Build Coastguard Worker 		exit(-1);
165*bd1f8aebSAndroid Build Coastguard Worker 	}
166*bd1f8aebSAndroid Build Coastguard Worker 
167*bd1f8aebSAndroid Build Coastguard Worker 	cap_get_flag(cap_p, CAP_NET_RAW, CAP_PERMITTED, &cap_raw);
168*bd1f8aebSAndroid Build Coastguard Worker 
169*bd1f8aebSAndroid Build Coastguard Worker 	if (cap_raw != CAP_CLEAR) {
170*bd1f8aebSAndroid Build Coastguard Worker 		if (cap_clear(cap_p) < 0) {
171*bd1f8aebSAndroid Build Coastguard Worker 			perror("arping: cap_clear");
172*bd1f8aebSAndroid Build Coastguard Worker 			exit(-1);
173*bd1f8aebSAndroid Build Coastguard Worker 		}
174*bd1f8aebSAndroid Build Coastguard Worker 
175*bd1f8aebSAndroid Build Coastguard Worker 		cap_set_flag(cap_p, CAP_PERMITTED, 1, caps, CAP_SET);
176*bd1f8aebSAndroid Build Coastguard Worker 
177*bd1f8aebSAndroid Build Coastguard Worker 		if (cap_set_proc(cap_p) < 0) {
178*bd1f8aebSAndroid Build Coastguard Worker 			perror("arping: cap_set_proc");
179*bd1f8aebSAndroid Build Coastguard Worker 			if (errno != EPERM)
180*bd1f8aebSAndroid Build Coastguard Worker 				exit(-1);
181*bd1f8aebSAndroid Build Coastguard Worker 		}
182*bd1f8aebSAndroid Build Coastguard Worker 	}
183*bd1f8aebSAndroid Build Coastguard Worker 
184*bd1f8aebSAndroid Build Coastguard Worker 	if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
185*bd1f8aebSAndroid Build Coastguard Worker 		perror("arping: prctl");
186*bd1f8aebSAndroid Build Coastguard Worker 		exit(-1);
187*bd1f8aebSAndroid Build Coastguard Worker 	}
188*bd1f8aebSAndroid Build Coastguard Worker 
189*bd1f8aebSAndroid Build Coastguard Worker 	if (setuid(getuid()) < 0) {
190*bd1f8aebSAndroid Build Coastguard Worker 		perror("arping: setuid");
191*bd1f8aebSAndroid Build Coastguard Worker 		exit(-1);
192*bd1f8aebSAndroid Build Coastguard Worker 	}
193*bd1f8aebSAndroid Build Coastguard Worker 
194*bd1f8aebSAndroid Build Coastguard Worker 	if (prctl(PR_SET_KEEPCAPS, 0) < 0) {
195*bd1f8aebSAndroid Build Coastguard Worker 		perror("arping: prctl");
196*bd1f8aebSAndroid Build Coastguard Worker 		exit(-1);
197*bd1f8aebSAndroid Build Coastguard Worker 	}
198*bd1f8aebSAndroid Build Coastguard Worker 
199*bd1f8aebSAndroid Build Coastguard Worker 	cap_free(cap_p);
200*bd1f8aebSAndroid Build Coastguard Worker #else
201*bd1f8aebSAndroid Build Coastguard Worker 	euid = geteuid();
202*bd1f8aebSAndroid Build Coastguard Worker #endif
203*bd1f8aebSAndroid Build Coastguard Worker }
204*bd1f8aebSAndroid Build Coastguard Worker 
modify_capability_raw(int on)205*bd1f8aebSAndroid Build Coastguard Worker int modify_capability_raw(int on)
206*bd1f8aebSAndroid Build Coastguard Worker {
207*bd1f8aebSAndroid Build Coastguard Worker #ifdef CAPABILITIES
208*bd1f8aebSAndroid Build Coastguard Worker 	cap_t cap_p;
209*bd1f8aebSAndroid Build Coastguard Worker 
210*bd1f8aebSAndroid Build Coastguard Worker 	if (cap_raw != CAP_SET)
211*bd1f8aebSAndroid Build Coastguard Worker 		return on ? -1 : 0;
212*bd1f8aebSAndroid Build Coastguard Worker 
213*bd1f8aebSAndroid Build Coastguard Worker 	cap_p = cap_get_proc();
214*bd1f8aebSAndroid Build Coastguard Worker 	if (!cap_p) {
215*bd1f8aebSAndroid Build Coastguard Worker 		perror("arping: cap_get_proc");
216*bd1f8aebSAndroid Build Coastguard Worker 		return -1;
217*bd1f8aebSAndroid Build Coastguard Worker 	}
218*bd1f8aebSAndroid Build Coastguard Worker 
219*bd1f8aebSAndroid Build Coastguard Worker 	cap_set_flag(cap_p, CAP_EFFECTIVE, 1, caps, on ? CAP_SET : CAP_CLEAR);
220*bd1f8aebSAndroid Build Coastguard Worker 
221*bd1f8aebSAndroid Build Coastguard Worker 	if (cap_set_proc(cap_p) < 0) {
222*bd1f8aebSAndroid Build Coastguard Worker 		perror("arping: cap_set_proc");
223*bd1f8aebSAndroid Build Coastguard Worker 		return -1;
224*bd1f8aebSAndroid Build Coastguard Worker 	}
225*bd1f8aebSAndroid Build Coastguard Worker 
226*bd1f8aebSAndroid Build Coastguard Worker 	cap_free(cap_p);
227*bd1f8aebSAndroid Build Coastguard Worker #else
228*bd1f8aebSAndroid Build Coastguard Worker 	if (setuid(on ? euid : getuid())) {
229*bd1f8aebSAndroid Build Coastguard Worker 		perror("arping: setuid");
230*bd1f8aebSAndroid Build Coastguard Worker 		return -1;
231*bd1f8aebSAndroid Build Coastguard Worker 	}
232*bd1f8aebSAndroid Build Coastguard Worker #endif
233*bd1f8aebSAndroid Build Coastguard Worker 	return 0;
234*bd1f8aebSAndroid Build Coastguard Worker }
235*bd1f8aebSAndroid Build Coastguard Worker 
enable_capability_raw(void)236*bd1f8aebSAndroid Build Coastguard Worker static inline int enable_capability_raw(void)
237*bd1f8aebSAndroid Build Coastguard Worker {
238*bd1f8aebSAndroid Build Coastguard Worker 	return modify_capability_raw(1);
239*bd1f8aebSAndroid Build Coastguard Worker }
240*bd1f8aebSAndroid Build Coastguard Worker 
disable_capability_raw(void)241*bd1f8aebSAndroid Build Coastguard Worker static inline int disable_capability_raw(void)
242*bd1f8aebSAndroid Build Coastguard Worker {
243*bd1f8aebSAndroid Build Coastguard Worker 	return modify_capability_raw(0);
244*bd1f8aebSAndroid Build Coastguard Worker }
245*bd1f8aebSAndroid Build Coastguard Worker 
drop_capabilities(void)246*bd1f8aebSAndroid Build Coastguard Worker void drop_capabilities(void)
247*bd1f8aebSAndroid Build Coastguard Worker {
248*bd1f8aebSAndroid Build Coastguard Worker #ifdef CAPABILITIES
249*bd1f8aebSAndroid Build Coastguard Worker 	cap_t cap_p = cap_init();
250*bd1f8aebSAndroid Build Coastguard Worker 
251*bd1f8aebSAndroid Build Coastguard Worker 	if (!cap_p) {
252*bd1f8aebSAndroid Build Coastguard Worker 		perror("arping: cap_init");
253*bd1f8aebSAndroid Build Coastguard Worker 		exit(-1);
254*bd1f8aebSAndroid Build Coastguard Worker 	}
255*bd1f8aebSAndroid Build Coastguard Worker 
256*bd1f8aebSAndroid Build Coastguard Worker 	if (cap_set_proc(cap_p) < 0) {
257*bd1f8aebSAndroid Build Coastguard Worker 		perror("arping: cap_set_proc");
258*bd1f8aebSAndroid Build Coastguard Worker 		exit(-1);
259*bd1f8aebSAndroid Build Coastguard Worker 	}
260*bd1f8aebSAndroid Build Coastguard Worker 
261*bd1f8aebSAndroid Build Coastguard Worker 	cap_free(cap_p);
262*bd1f8aebSAndroid Build Coastguard Worker #else
263*bd1f8aebSAndroid Build Coastguard Worker 	if (setuid(getuid()) < 0) {
264*bd1f8aebSAndroid Build Coastguard Worker 		perror("arping: setuid");
265*bd1f8aebSAndroid Build Coastguard Worker 		exit(-1);
266*bd1f8aebSAndroid Build Coastguard Worker 	}
267*bd1f8aebSAndroid Build Coastguard Worker #endif
268*bd1f8aebSAndroid Build Coastguard Worker }
269*bd1f8aebSAndroid Build Coastguard Worker 
send_pack(int s,struct in_addr src,struct in_addr dst,struct sockaddr_ll * ME,struct sockaddr_ll * HE)270*bd1f8aebSAndroid Build Coastguard Worker int send_pack(int s, struct in_addr src, struct in_addr dst,
271*bd1f8aebSAndroid Build Coastguard Worker 	      struct sockaddr_ll *ME, struct sockaddr_ll *HE)
272*bd1f8aebSAndroid Build Coastguard Worker {
273*bd1f8aebSAndroid Build Coastguard Worker 	int err;
274*bd1f8aebSAndroid Build Coastguard Worker 	struct timeval now;
275*bd1f8aebSAndroid Build Coastguard Worker 	unsigned char buf[256];
276*bd1f8aebSAndroid Build Coastguard Worker 	struct arphdr *ah = (struct arphdr*)buf;
277*bd1f8aebSAndroid Build Coastguard Worker 	unsigned char *p = (unsigned char *)(ah+1);
278*bd1f8aebSAndroid Build Coastguard Worker 
279*bd1f8aebSAndroid Build Coastguard Worker 	ah->ar_hrd = htons(ME->sll_hatype);
280*bd1f8aebSAndroid Build Coastguard Worker 	if (ah->ar_hrd == htons(ARPHRD_FDDI))
281*bd1f8aebSAndroid Build Coastguard Worker 		ah->ar_hrd = htons(ARPHRD_ETHER);
282*bd1f8aebSAndroid Build Coastguard Worker 	ah->ar_pro = htons(ETH_P_IP);
283*bd1f8aebSAndroid Build Coastguard Worker 	ah->ar_hln = ME->sll_halen;
284*bd1f8aebSAndroid Build Coastguard Worker 	ah->ar_pln = 4;
285*bd1f8aebSAndroid Build Coastguard Worker 	ah->ar_op  = advert ? htons(ARPOP_REPLY) : htons(ARPOP_REQUEST);
286*bd1f8aebSAndroid Build Coastguard Worker 
287*bd1f8aebSAndroid Build Coastguard Worker 	memcpy(p, &ME->sll_addr, ah->ar_hln);
288*bd1f8aebSAndroid Build Coastguard Worker 	p+=ME->sll_halen;
289*bd1f8aebSAndroid Build Coastguard Worker 
290*bd1f8aebSAndroid Build Coastguard Worker 	memcpy(p, &src, 4);
291*bd1f8aebSAndroid Build Coastguard Worker 	p+=4;
292*bd1f8aebSAndroid Build Coastguard Worker 
293*bd1f8aebSAndroid Build Coastguard Worker 	if (advert)
294*bd1f8aebSAndroid Build Coastguard Worker 		memcpy(p, &ME->sll_addr, ah->ar_hln);
295*bd1f8aebSAndroid Build Coastguard Worker 	else
296*bd1f8aebSAndroid Build Coastguard Worker 		memcpy(p, &HE->sll_addr, ah->ar_hln);
297*bd1f8aebSAndroid Build Coastguard Worker 	p+=ah->ar_hln;
298*bd1f8aebSAndroid Build Coastguard Worker 
299*bd1f8aebSAndroid Build Coastguard Worker 	memcpy(p, &dst, 4);
300*bd1f8aebSAndroid Build Coastguard Worker 	p+=4;
301*bd1f8aebSAndroid Build Coastguard Worker 
302*bd1f8aebSAndroid Build Coastguard Worker 	gettimeofday(&now, NULL);
303*bd1f8aebSAndroid Build Coastguard Worker 	err = sendto(s, buf, p-buf, 0, (struct sockaddr*)HE, SLL_LEN(ah->ar_hln));
304*bd1f8aebSAndroid Build Coastguard Worker 	if (err == p-buf) {
305*bd1f8aebSAndroid Build Coastguard Worker 		last = now;
306*bd1f8aebSAndroid Build Coastguard Worker 		sent++;
307*bd1f8aebSAndroid Build Coastguard Worker 		if (!unicasting)
308*bd1f8aebSAndroid Build Coastguard Worker 			brd_sent++;
309*bd1f8aebSAndroid Build Coastguard Worker 	}
310*bd1f8aebSAndroid Build Coastguard Worker 	return err;
311*bd1f8aebSAndroid Build Coastguard Worker }
312*bd1f8aebSAndroid Build Coastguard Worker 
finish(void)313*bd1f8aebSAndroid Build Coastguard Worker void finish(void)
314*bd1f8aebSAndroid Build Coastguard Worker {
315*bd1f8aebSAndroid Build Coastguard Worker 	if (!quiet) {
316*bd1f8aebSAndroid Build Coastguard Worker 		printf("Sent %d probes (%d broadcast(s))\n", sent, brd_sent);
317*bd1f8aebSAndroid Build Coastguard Worker 		printf("Received %d response(s)", received);
318*bd1f8aebSAndroid Build Coastguard Worker 		if (brd_recv || req_recv) {
319*bd1f8aebSAndroid Build Coastguard Worker 			printf(" (");
320*bd1f8aebSAndroid Build Coastguard Worker 			if (req_recv)
321*bd1f8aebSAndroid Build Coastguard Worker 				printf("%d request(s)", req_recv);
322*bd1f8aebSAndroid Build Coastguard Worker 			if (brd_recv)
323*bd1f8aebSAndroid Build Coastguard Worker 				printf("%s%d broadcast(s)",
324*bd1f8aebSAndroid Build Coastguard Worker 				       req_recv ? ", " : "",
325*bd1f8aebSAndroid Build Coastguard Worker 				       brd_recv);
326*bd1f8aebSAndroid Build Coastguard Worker 			printf(")");
327*bd1f8aebSAndroid Build Coastguard Worker 		}
328*bd1f8aebSAndroid Build Coastguard Worker 		printf("\n");
329*bd1f8aebSAndroid Build Coastguard Worker 		fflush(stdout);
330*bd1f8aebSAndroid Build Coastguard Worker 	}
331*bd1f8aebSAndroid Build Coastguard Worker 	if (dad)
332*bd1f8aebSAndroid Build Coastguard Worker 		exit(!!received);
333*bd1f8aebSAndroid Build Coastguard Worker 	if (unsolicited)
334*bd1f8aebSAndroid Build Coastguard Worker 		exit(0);
335*bd1f8aebSAndroid Build Coastguard Worker 	exit(!received);
336*bd1f8aebSAndroid Build Coastguard Worker }
337*bd1f8aebSAndroid Build Coastguard Worker 
catcher(void)338*bd1f8aebSAndroid Build Coastguard Worker void catcher(void)
339*bd1f8aebSAndroid Build Coastguard Worker {
340*bd1f8aebSAndroid Build Coastguard Worker 	struct timeval tv, tv_s, tv_o;
341*bd1f8aebSAndroid Build Coastguard Worker 
342*bd1f8aebSAndroid Build Coastguard Worker 	gettimeofday(&tv, NULL);
343*bd1f8aebSAndroid Build Coastguard Worker 
344*bd1f8aebSAndroid Build Coastguard Worker 	if (start.tv_sec==0)
345*bd1f8aebSAndroid Build Coastguard Worker 		start = tv;
346*bd1f8aebSAndroid Build Coastguard Worker 
347*bd1f8aebSAndroid Build Coastguard Worker 	timersub(&tv, &start, &tv_s);
348*bd1f8aebSAndroid Build Coastguard Worker 	tv_o.tv_sec = timeout;
349*bd1f8aebSAndroid Build Coastguard Worker 	tv_o.tv_usec = 500 * 1000;
350*bd1f8aebSAndroid Build Coastguard Worker 
351*bd1f8aebSAndroid Build Coastguard Worker 	if (count-- == 0 || (timeout && timercmp(&tv_s, &tv_o, >)))
352*bd1f8aebSAndroid Build Coastguard Worker 		finish();
353*bd1f8aebSAndroid Build Coastguard Worker 
354*bd1f8aebSAndroid Build Coastguard Worker 	timersub(&tv, &last, &tv_s);
355*bd1f8aebSAndroid Build Coastguard Worker 	tv_o.tv_sec = 0;
356*bd1f8aebSAndroid Build Coastguard Worker 
357*bd1f8aebSAndroid Build Coastguard Worker 	if (last.tv_sec==0 || timercmp(&tv_s, &tv_o, >)) {
358*bd1f8aebSAndroid Build Coastguard Worker 		send_pack(s, src, dst,
359*bd1f8aebSAndroid Build Coastguard Worker 			  (struct sockaddr_ll *)&me, (struct sockaddr_ll *)&he);
360*bd1f8aebSAndroid Build Coastguard Worker 		if (count == 0 && unsolicited)
361*bd1f8aebSAndroid Build Coastguard Worker 			finish();
362*bd1f8aebSAndroid Build Coastguard Worker 	}
363*bd1f8aebSAndroid Build Coastguard Worker 	alarm(1);
364*bd1f8aebSAndroid Build Coastguard Worker }
365*bd1f8aebSAndroid Build Coastguard Worker 
print_hex(unsigned char * p,int len)366*bd1f8aebSAndroid Build Coastguard Worker void print_hex(unsigned char *p, int len)
367*bd1f8aebSAndroid Build Coastguard Worker {
368*bd1f8aebSAndroid Build Coastguard Worker 	int i;
369*bd1f8aebSAndroid Build Coastguard Worker 	for (i=0; i<len; i++) {
370*bd1f8aebSAndroid Build Coastguard Worker 		printf("%02X", p[i]);
371*bd1f8aebSAndroid Build Coastguard Worker 		if (i != len-1)
372*bd1f8aebSAndroid Build Coastguard Worker 			printf(":");
373*bd1f8aebSAndroid Build Coastguard Worker 	}
374*bd1f8aebSAndroid Build Coastguard Worker }
375*bd1f8aebSAndroid Build Coastguard Worker 
recv_pack(unsigned char * buf,int len,struct sockaddr_ll * FROM)376*bd1f8aebSAndroid Build Coastguard Worker int recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
377*bd1f8aebSAndroid Build Coastguard Worker {
378*bd1f8aebSAndroid Build Coastguard Worker 	struct timeval tv;
379*bd1f8aebSAndroid Build Coastguard Worker 	struct arphdr *ah = (struct arphdr*)buf;
380*bd1f8aebSAndroid Build Coastguard Worker 	unsigned char *p = (unsigned char *)(ah+1);
381*bd1f8aebSAndroid Build Coastguard Worker 	struct in_addr src_ip, dst_ip;
382*bd1f8aebSAndroid Build Coastguard Worker 
383*bd1f8aebSAndroid Build Coastguard Worker 	gettimeofday(&tv, NULL);
384*bd1f8aebSAndroid Build Coastguard Worker 
385*bd1f8aebSAndroid Build Coastguard Worker 	/* Filter out wild packets */
386*bd1f8aebSAndroid Build Coastguard Worker 	if (FROM->sll_pkttype != PACKET_HOST &&
387*bd1f8aebSAndroid Build Coastguard Worker 	    FROM->sll_pkttype != PACKET_BROADCAST &&
388*bd1f8aebSAndroid Build Coastguard Worker 	    FROM->sll_pkttype != PACKET_MULTICAST)
389*bd1f8aebSAndroid Build Coastguard Worker 		return 0;
390*bd1f8aebSAndroid Build Coastguard Worker 
391*bd1f8aebSAndroid Build Coastguard Worker 	/* Only these types are recognised */
392*bd1f8aebSAndroid Build Coastguard Worker 	if (ah->ar_op != htons(ARPOP_REQUEST) &&
393*bd1f8aebSAndroid Build Coastguard Worker 	    ah->ar_op != htons(ARPOP_REPLY))
394*bd1f8aebSAndroid Build Coastguard Worker 		return 0;
395*bd1f8aebSAndroid Build Coastguard Worker 
396*bd1f8aebSAndroid Build Coastguard Worker 	/* ARPHRD check and this darned FDDI hack here :-( */
397*bd1f8aebSAndroid Build Coastguard Worker 	if (ah->ar_hrd != htons(FROM->sll_hatype) &&
398*bd1f8aebSAndroid Build Coastguard Worker 	    (FROM->sll_hatype != ARPHRD_FDDI || ah->ar_hrd != htons(ARPHRD_ETHER)))
399*bd1f8aebSAndroid Build Coastguard Worker 		return 0;
400*bd1f8aebSAndroid Build Coastguard Worker 
401*bd1f8aebSAndroid Build Coastguard Worker 	/* Protocol must be IP. */
402*bd1f8aebSAndroid Build Coastguard Worker 	if (ah->ar_pro != htons(ETH_P_IP))
403*bd1f8aebSAndroid Build Coastguard Worker 		return 0;
404*bd1f8aebSAndroid Build Coastguard Worker 	if (ah->ar_pln != 4)
405*bd1f8aebSAndroid Build Coastguard Worker 		return 0;
406*bd1f8aebSAndroid Build Coastguard Worker 	if (ah->ar_hln != ((struct sockaddr_ll *)&me)->sll_halen)
407*bd1f8aebSAndroid Build Coastguard Worker 		return 0;
408*bd1f8aebSAndroid Build Coastguard Worker 	if (len < sizeof(*ah) + 2*(4 + ah->ar_hln))
409*bd1f8aebSAndroid Build Coastguard Worker 		return 0;
410*bd1f8aebSAndroid Build Coastguard Worker 	memcpy(&src_ip, p+ah->ar_hln, 4);
411*bd1f8aebSAndroid Build Coastguard Worker 	memcpy(&dst_ip, p+ah->ar_hln+4+ah->ar_hln, 4);
412*bd1f8aebSAndroid Build Coastguard Worker 	if (!dad) {
413*bd1f8aebSAndroid Build Coastguard Worker 		if (src_ip.s_addr != dst.s_addr)
414*bd1f8aebSAndroid Build Coastguard Worker 			return 0;
415*bd1f8aebSAndroid Build Coastguard Worker 		if (src.s_addr != dst_ip.s_addr)
416*bd1f8aebSAndroid Build Coastguard Worker 			return 0;
417*bd1f8aebSAndroid Build Coastguard Worker 		if (memcmp(p+ah->ar_hln+4, ((struct sockaddr_ll *)&me)->sll_addr, ah->ar_hln))
418*bd1f8aebSAndroid Build Coastguard Worker 			return 0;
419*bd1f8aebSAndroid Build Coastguard Worker 	} else {
420*bd1f8aebSAndroid Build Coastguard Worker 		/* DAD packet was:
421*bd1f8aebSAndroid Build Coastguard Worker 		   src_ip = 0 (or some src)
422*bd1f8aebSAndroid Build Coastguard Worker 		   src_hw = ME
423*bd1f8aebSAndroid Build Coastguard Worker 		   dst_ip = tested address
424*bd1f8aebSAndroid Build Coastguard Worker 		   dst_hw = <unspec>
425*bd1f8aebSAndroid Build Coastguard Worker 
426*bd1f8aebSAndroid Build Coastguard Worker 		   We fail, if receive request/reply with:
427*bd1f8aebSAndroid Build Coastguard Worker 		   src_ip = tested_address
428*bd1f8aebSAndroid Build Coastguard Worker 		   src_hw != ME
429*bd1f8aebSAndroid Build Coastguard Worker 		   if src_ip in request was not zero, check
430*bd1f8aebSAndroid Build Coastguard Worker 		   also that it matches to dst_ip, otherwise
431*bd1f8aebSAndroid Build Coastguard Worker 		   dst_ip/dst_hw do not matter.
432*bd1f8aebSAndroid Build Coastguard Worker 		 */
433*bd1f8aebSAndroid Build Coastguard Worker 		if (src_ip.s_addr != dst.s_addr)
434*bd1f8aebSAndroid Build Coastguard Worker 			return 0;
435*bd1f8aebSAndroid Build Coastguard Worker 		if (memcmp(p, ((struct sockaddr_ll *)&me)->sll_addr, ((struct sockaddr_ll *)&me)->sll_halen) == 0)
436*bd1f8aebSAndroid Build Coastguard Worker 			return 0;
437*bd1f8aebSAndroid Build Coastguard Worker 		if (src.s_addr && src.s_addr != dst_ip.s_addr)
438*bd1f8aebSAndroid Build Coastguard Worker 			return 0;
439*bd1f8aebSAndroid Build Coastguard Worker 	}
440*bd1f8aebSAndroid Build Coastguard Worker 	if (!quiet) {
441*bd1f8aebSAndroid Build Coastguard Worker 		int s_printed = 0;
442*bd1f8aebSAndroid Build Coastguard Worker 		printf("%s ", FROM->sll_pkttype==PACKET_HOST ? "Unicast" : "Broadcast");
443*bd1f8aebSAndroid Build Coastguard Worker 		printf("%s from ", ah->ar_op == htons(ARPOP_REPLY) ? "reply" : "request");
444*bd1f8aebSAndroid Build Coastguard Worker 		printf("%s [", inet_ntoa(src_ip));
445*bd1f8aebSAndroid Build Coastguard Worker 		print_hex(p, ah->ar_hln);
446*bd1f8aebSAndroid Build Coastguard Worker 		printf("] ");
447*bd1f8aebSAndroid Build Coastguard Worker 		if (dst_ip.s_addr != src.s_addr) {
448*bd1f8aebSAndroid Build Coastguard Worker 			printf("for %s ", inet_ntoa(dst_ip));
449*bd1f8aebSAndroid Build Coastguard Worker 			s_printed = 1;
450*bd1f8aebSAndroid Build Coastguard Worker 		}
451*bd1f8aebSAndroid Build Coastguard Worker 		if (memcmp(p+ah->ar_hln+4, ((struct sockaddr_ll *)&me)->sll_addr, ah->ar_hln)) {
452*bd1f8aebSAndroid Build Coastguard Worker 			if (!s_printed)
453*bd1f8aebSAndroid Build Coastguard Worker 				printf("for ");
454*bd1f8aebSAndroid Build Coastguard Worker 			printf("[");
455*bd1f8aebSAndroid Build Coastguard Worker 			print_hex(p+ah->ar_hln+4, ah->ar_hln);
456*bd1f8aebSAndroid Build Coastguard Worker 			printf("]");
457*bd1f8aebSAndroid Build Coastguard Worker 		}
458*bd1f8aebSAndroid Build Coastguard Worker 		if (last.tv_sec) {
459*bd1f8aebSAndroid Build Coastguard Worker 			long usecs = (tv.tv_sec-last.tv_sec) * 1000000 +
460*bd1f8aebSAndroid Build Coastguard Worker 				tv.tv_usec-last.tv_usec;
461*bd1f8aebSAndroid Build Coastguard Worker 			long msecs = (usecs+500)/1000;
462*bd1f8aebSAndroid Build Coastguard Worker 			usecs -= msecs*1000 - 500;
463*bd1f8aebSAndroid Build Coastguard Worker 			printf(" %ld.%03ldms\n", msecs, usecs);
464*bd1f8aebSAndroid Build Coastguard Worker 		} else {
465*bd1f8aebSAndroid Build Coastguard Worker 			printf(" UNSOLICITED?\n");
466*bd1f8aebSAndroid Build Coastguard Worker 		}
467*bd1f8aebSAndroid Build Coastguard Worker 		fflush(stdout);
468*bd1f8aebSAndroid Build Coastguard Worker 	}
469*bd1f8aebSAndroid Build Coastguard Worker 	received++;
470*bd1f8aebSAndroid Build Coastguard Worker 	if (FROM->sll_pkttype != PACKET_HOST)
471*bd1f8aebSAndroid Build Coastguard Worker 		brd_recv++;
472*bd1f8aebSAndroid Build Coastguard Worker 	if (ah->ar_op == htons(ARPOP_REQUEST))
473*bd1f8aebSAndroid Build Coastguard Worker 		req_recv++;
474*bd1f8aebSAndroid Build Coastguard Worker 	if (quit_on_reply)
475*bd1f8aebSAndroid Build Coastguard Worker 		finish();
476*bd1f8aebSAndroid Build Coastguard Worker 	if(!broadcast_only) {
477*bd1f8aebSAndroid Build Coastguard Worker 		memcpy(((struct sockaddr_ll *)&he)->sll_addr, p, ((struct sockaddr_ll *)&me)->sll_halen);
478*bd1f8aebSAndroid Build Coastguard Worker 		unicasting=1;
479*bd1f8aebSAndroid Build Coastguard Worker 	}
480*bd1f8aebSAndroid Build Coastguard Worker 	return 1;
481*bd1f8aebSAndroid Build Coastguard Worker }
482*bd1f8aebSAndroid Build Coastguard Worker 
483*bd1f8aebSAndroid Build Coastguard Worker #ifdef USE_SYSFS
484*bd1f8aebSAndroid Build Coastguard Worker union sysfs_devattr_value {
485*bd1f8aebSAndroid Build Coastguard Worker 	unsigned long	ulong;
486*bd1f8aebSAndroid Build Coastguard Worker 	void		*ptr;
487*bd1f8aebSAndroid Build Coastguard Worker };
488*bd1f8aebSAndroid Build Coastguard Worker 
489*bd1f8aebSAndroid Build Coastguard Worker enum {
490*bd1f8aebSAndroid Build Coastguard Worker 	SYSFS_DEVATTR_IFINDEX,
491*bd1f8aebSAndroid Build Coastguard Worker 	SYSFS_DEVATTR_FLAGS,
492*bd1f8aebSAndroid Build Coastguard Worker 	SYSFS_DEVATTR_ADDR_LEN,
493*bd1f8aebSAndroid Build Coastguard Worker #if 0
494*bd1f8aebSAndroid Build Coastguard Worker 	SYSFS_DEVATTR_TYPE,
495*bd1f8aebSAndroid Build Coastguard Worker 	SYSFS_DEVATTR_ADDRESS,
496*bd1f8aebSAndroid Build Coastguard Worker #endif
497*bd1f8aebSAndroid Build Coastguard Worker 	SYSFS_DEVATTR_BROADCAST,
498*bd1f8aebSAndroid Build Coastguard Worker 	SYSFS_DEVATTR_NUM
499*bd1f8aebSAndroid Build Coastguard Worker };
500*bd1f8aebSAndroid Build Coastguard Worker 
501*bd1f8aebSAndroid Build Coastguard Worker struct sysfs_devattr_values
502*bd1f8aebSAndroid Build Coastguard Worker {
503*bd1f8aebSAndroid Build Coastguard Worker 	char *ifname;
504*bd1f8aebSAndroid Build Coastguard Worker 	union sysfs_devattr_value	value[SYSFS_DEVATTR_NUM];
505*bd1f8aebSAndroid Build Coastguard Worker };
506*bd1f8aebSAndroid Build Coastguard Worker 
507*bd1f8aebSAndroid Build Coastguard Worker static int sysfs_devattr_ulong_dec(char *ptr, struct sysfs_devattr_values *v, unsigned idx);
508*bd1f8aebSAndroid Build Coastguard Worker static int sysfs_devattr_ulong_hex(char *ptr, struct sysfs_devattr_values *v, unsigned idx);
509*bd1f8aebSAndroid Build Coastguard Worker static int sysfs_devattr_macaddr(char *ptr, struct sysfs_devattr_values *v, unsigned idx);
510*bd1f8aebSAndroid Build Coastguard Worker 
511*bd1f8aebSAndroid Build Coastguard Worker struct sysfs_devattrs {
512*bd1f8aebSAndroid Build Coastguard Worker 	const char *name;
513*bd1f8aebSAndroid Build Coastguard Worker 	int (*handler)(char *ptr, struct sysfs_devattr_values *v, unsigned int idx);
514*bd1f8aebSAndroid Build Coastguard Worker 	int free;
515*bd1f8aebSAndroid Build Coastguard Worker } sysfs_devattrs[SYSFS_DEVATTR_NUM] = {
516*bd1f8aebSAndroid Build Coastguard Worker 	[SYSFS_DEVATTR_IFINDEX] = {
517*bd1f8aebSAndroid Build Coastguard Worker 		.name		= "ifindex",
518*bd1f8aebSAndroid Build Coastguard Worker 		.handler	= sysfs_devattr_ulong_dec,
519*bd1f8aebSAndroid Build Coastguard Worker 	},
520*bd1f8aebSAndroid Build Coastguard Worker 	[SYSFS_DEVATTR_ADDR_LEN] = {
521*bd1f8aebSAndroid Build Coastguard Worker 		.name		= "addr_len",
522*bd1f8aebSAndroid Build Coastguard Worker 		.handler	= sysfs_devattr_ulong_dec,
523*bd1f8aebSAndroid Build Coastguard Worker 	},
524*bd1f8aebSAndroid Build Coastguard Worker 	[SYSFS_DEVATTR_FLAGS] = {
525*bd1f8aebSAndroid Build Coastguard Worker 		.name		= "flags",
526*bd1f8aebSAndroid Build Coastguard Worker 		.handler	= sysfs_devattr_ulong_hex,
527*bd1f8aebSAndroid Build Coastguard Worker 	},
528*bd1f8aebSAndroid Build Coastguard Worker #if 0
529*bd1f8aebSAndroid Build Coastguard Worker 	[SYSFS_DEVATTR_TYPE] = {
530*bd1f8aebSAndroid Build Coastguard Worker 		.name		= "type",
531*bd1f8aebSAndroid Build Coastguard Worker 		.handler	= sysfs_devattr_ulong_dec,
532*bd1f8aebSAndroid Build Coastguard Worker 	},
533*bd1f8aebSAndroid Build Coastguard Worker 	[SYSFS_DEVATTR_ADDRESS] = {
534*bd1f8aebSAndroid Build Coastguard Worker 		.name		= "address",
535*bd1f8aebSAndroid Build Coastguard Worker 		.handler	= sysfs_devattr_macaddr,
536*bd1f8aebSAndroid Build Coastguard Worker 		.free		= 1,
537*bd1f8aebSAndroid Build Coastguard Worker 	},
538*bd1f8aebSAndroid Build Coastguard Worker #endif
539*bd1f8aebSAndroid Build Coastguard Worker 	[SYSFS_DEVATTR_BROADCAST] = {
540*bd1f8aebSAndroid Build Coastguard Worker 		.name		= "broadcast",
541*bd1f8aebSAndroid Build Coastguard Worker 		.handler	= sysfs_devattr_macaddr,
542*bd1f8aebSAndroid Build Coastguard Worker 		.free		= 1,
543*bd1f8aebSAndroid Build Coastguard Worker 	},
544*bd1f8aebSAndroid Build Coastguard Worker };
545*bd1f8aebSAndroid Build Coastguard Worker #endif
546*bd1f8aebSAndroid Build Coastguard Worker 
547*bd1f8aebSAndroid Build Coastguard Worker /*
548*bd1f8aebSAndroid Build Coastguard Worker  * find_device()
549*bd1f8aebSAndroid Build Coastguard Worker  *
550*bd1f8aebSAndroid Build Coastguard Worker  * This function checks 1) if the device (if given) is okay for ARP,
551*bd1f8aebSAndroid Build Coastguard Worker  * or 2) find fist appropriate device on the system.
552*bd1f8aebSAndroid Build Coastguard Worker  *
553*bd1f8aebSAndroid Build Coastguard Worker  * Return value:
554*bd1f8aebSAndroid Build Coastguard Worker  *	>0	: Succeeded, and appropriate device not found.
555*bd1f8aebSAndroid Build Coastguard Worker  *		  device.ifindex remains 0.
556*bd1f8aebSAndroid Build Coastguard Worker  *	0	: Succeeded, and approptiate device found.
557*bd1f8aebSAndroid Build Coastguard Worker  *		  device.ifindex is set.
558*bd1f8aebSAndroid Build Coastguard Worker  *	<0	: Failed.  Support not found, or other
559*bd1f8aebSAndroid Build Coastguard Worker  *		: system error.  Try other method.
560*bd1f8aebSAndroid Build Coastguard Worker  *
561*bd1f8aebSAndroid Build Coastguard Worker  * If an appropriate device found, it is recorded inside the
562*bd1f8aebSAndroid Build Coastguard Worker  * "device" variable for later reference.
563*bd1f8aebSAndroid Build Coastguard Worker  *
564*bd1f8aebSAndroid Build Coastguard Worker  * We have several implementations for this.
565*bd1f8aebSAndroid Build Coastguard Worker  *	by_ifaddrs():	requires getifaddr() in glibc, and rtnetlink in
566*bd1f8aebSAndroid Build Coastguard Worker  *			kernel. default and recommended for recent systems.
567*bd1f8aebSAndroid Build Coastguard Worker  *	by_sysfs():	requires libsysfs , and sysfs in kernel.
568*bd1f8aebSAndroid Build Coastguard Worker  *	by_ioctl():	unable to list devices without ipv4 address; this
569*bd1f8aebSAndroid Build Coastguard Worker  *			means, you need to supply the device name for
570*bd1f8aebSAndroid Build Coastguard Worker  *			DAD purpose.
571*bd1f8aebSAndroid Build Coastguard Worker  */
572*bd1f8aebSAndroid Build Coastguard Worker /* Common check for ifa->ifa_flags */
check_ifflags(unsigned int ifflags,int fatal)573*bd1f8aebSAndroid Build Coastguard Worker static int check_ifflags(unsigned int ifflags, int fatal)
574*bd1f8aebSAndroid Build Coastguard Worker {
575*bd1f8aebSAndroid Build Coastguard Worker 	if (!(ifflags & IFF_UP)) {
576*bd1f8aebSAndroid Build Coastguard Worker 		if (fatal) {
577*bd1f8aebSAndroid Build Coastguard Worker 			if (!quiet)
578*bd1f8aebSAndroid Build Coastguard Worker 				printf("Interface \"%s\" is down\n", device.name);
579*bd1f8aebSAndroid Build Coastguard Worker 			exit(2);
580*bd1f8aebSAndroid Build Coastguard Worker 		}
581*bd1f8aebSAndroid Build Coastguard Worker 		return -1;
582*bd1f8aebSAndroid Build Coastguard Worker 	}
583*bd1f8aebSAndroid Build Coastguard Worker 	if (ifflags & (IFF_NOARP | IFF_LOOPBACK)) {
584*bd1f8aebSAndroid Build Coastguard Worker 		if (fatal) {
585*bd1f8aebSAndroid Build Coastguard Worker 			if (!quiet)
586*bd1f8aebSAndroid Build Coastguard Worker 				printf("Interface \"%s\" is not ARPable\n", device.name);
587*bd1f8aebSAndroid Build Coastguard Worker 			exit(dad ? 0 : 2);
588*bd1f8aebSAndroid Build Coastguard Worker 		}
589*bd1f8aebSAndroid Build Coastguard Worker 		return -1;
590*bd1f8aebSAndroid Build Coastguard Worker 	}
591*bd1f8aebSAndroid Build Coastguard Worker 	return 0;
592*bd1f8aebSAndroid Build Coastguard Worker }
593*bd1f8aebSAndroid Build Coastguard Worker 
find_device_by_ifaddrs(void)594*bd1f8aebSAndroid Build Coastguard Worker static int find_device_by_ifaddrs(void)
595*bd1f8aebSAndroid Build Coastguard Worker {
596*bd1f8aebSAndroid Build Coastguard Worker #ifndef WITHOUT_IFADDRS
597*bd1f8aebSAndroid Build Coastguard Worker 	int rc;
598*bd1f8aebSAndroid Build Coastguard Worker 	struct ifaddrs *ifa0, *ifa;
599*bd1f8aebSAndroid Build Coastguard Worker 	int count = 0;
600*bd1f8aebSAndroid Build Coastguard Worker 
601*bd1f8aebSAndroid Build Coastguard Worker 	rc = getifaddrs(&ifa0);
602*bd1f8aebSAndroid Build Coastguard Worker 	if (rc) {
603*bd1f8aebSAndroid Build Coastguard Worker 		perror("getifaddrs");
604*bd1f8aebSAndroid Build Coastguard Worker 		return -1;
605*bd1f8aebSAndroid Build Coastguard Worker 	}
606*bd1f8aebSAndroid Build Coastguard Worker 
607*bd1f8aebSAndroid Build Coastguard Worker 	for (ifa = ifa0; ifa; ifa = ifa->ifa_next) {
608*bd1f8aebSAndroid Build Coastguard Worker 		if (!ifa->ifa_addr)
609*bd1f8aebSAndroid Build Coastguard Worker 			continue;
610*bd1f8aebSAndroid Build Coastguard Worker 		if (ifa->ifa_addr->sa_family != AF_PACKET)
611*bd1f8aebSAndroid Build Coastguard Worker 			continue;
612*bd1f8aebSAndroid Build Coastguard Worker 		if (device.name && ifa->ifa_name && strcmp(ifa->ifa_name, device.name))
613*bd1f8aebSAndroid Build Coastguard Worker 			continue;
614*bd1f8aebSAndroid Build Coastguard Worker 
615*bd1f8aebSAndroid Build Coastguard Worker 		if (check_ifflags(ifa->ifa_flags, device.name != NULL) < 0)
616*bd1f8aebSAndroid Build Coastguard Worker 			continue;
617*bd1f8aebSAndroid Build Coastguard Worker 
618*bd1f8aebSAndroid Build Coastguard Worker 		if (!((struct sockaddr_ll *)ifa->ifa_addr)->sll_halen)
619*bd1f8aebSAndroid Build Coastguard Worker 			continue;
620*bd1f8aebSAndroid Build Coastguard Worker 		if (!ifa->ifa_broadaddr)
621*bd1f8aebSAndroid Build Coastguard Worker 			continue;
622*bd1f8aebSAndroid Build Coastguard Worker 
623*bd1f8aebSAndroid Build Coastguard Worker 		device.ifa = ifa;
624*bd1f8aebSAndroid Build Coastguard Worker 
625*bd1f8aebSAndroid Build Coastguard Worker 		if (count++)
626*bd1f8aebSAndroid Build Coastguard Worker 			break;
627*bd1f8aebSAndroid Build Coastguard Worker 	}
628*bd1f8aebSAndroid Build Coastguard Worker 
629*bd1f8aebSAndroid Build Coastguard Worker 	if (count == 1 && device.ifa) {
630*bd1f8aebSAndroid Build Coastguard Worker 		device.ifindex = if_nametoindex(device.ifa->ifa_name);
631*bd1f8aebSAndroid Build Coastguard Worker 		if (!device.ifindex) {
632*bd1f8aebSAndroid Build Coastguard Worker 			perror("arping: if_nametoindex");
633*bd1f8aebSAndroid Build Coastguard Worker 			freeifaddrs(ifa0);
634*bd1f8aebSAndroid Build Coastguard Worker 			return -1;
635*bd1f8aebSAndroid Build Coastguard Worker 		}
636*bd1f8aebSAndroid Build Coastguard Worker 		device.name  = device.ifa->ifa_name;
637*bd1f8aebSAndroid Build Coastguard Worker 		return 0;
638*bd1f8aebSAndroid Build Coastguard Worker 	}
639*bd1f8aebSAndroid Build Coastguard Worker 	return 1;
640*bd1f8aebSAndroid Build Coastguard Worker #else
641*bd1f8aebSAndroid Build Coastguard Worker 	return -1;
642*bd1f8aebSAndroid Build Coastguard Worker #endif
643*bd1f8aebSAndroid Build Coastguard Worker }
644*bd1f8aebSAndroid Build Coastguard Worker 
645*bd1f8aebSAndroid Build Coastguard Worker #ifdef USE_SYSFS
sysfs_devattr_values_init(struct sysfs_devattr_values * v,int do_free)646*bd1f8aebSAndroid Build Coastguard Worker static void sysfs_devattr_values_init(struct sysfs_devattr_values *v, int do_free)
647*bd1f8aebSAndroid Build Coastguard Worker {
648*bd1f8aebSAndroid Build Coastguard Worker 	int i;
649*bd1f8aebSAndroid Build Coastguard Worker 	if (do_free) {
650*bd1f8aebSAndroid Build Coastguard Worker 		free(v->ifname);
651*bd1f8aebSAndroid Build Coastguard Worker 		for (i = 0; i < SYSFS_DEVATTR_NUM; i++) {
652*bd1f8aebSAndroid Build Coastguard Worker 			if (sysfs_devattrs[i].free)
653*bd1f8aebSAndroid Build Coastguard Worker 				free(v->value[i].ptr);
654*bd1f8aebSAndroid Build Coastguard Worker 		}
655*bd1f8aebSAndroid Build Coastguard Worker 	}
656*bd1f8aebSAndroid Build Coastguard Worker 	memset(v, 0, sizeof(*v));
657*bd1f8aebSAndroid Build Coastguard Worker }
658*bd1f8aebSAndroid Build Coastguard Worker 
sysfs_devattr_ulong(char * ptr,struct sysfs_devattr_values * v,unsigned int idx,unsigned int base)659*bd1f8aebSAndroid Build Coastguard Worker static int sysfs_devattr_ulong(char *ptr, struct sysfs_devattr_values *v, unsigned int idx,
660*bd1f8aebSAndroid Build Coastguard Worker 				     unsigned int base)
661*bd1f8aebSAndroid Build Coastguard Worker {
662*bd1f8aebSAndroid Build Coastguard Worker 	unsigned long *p;
663*bd1f8aebSAndroid Build Coastguard Worker 	char *ep;
664*bd1f8aebSAndroid Build Coastguard Worker 
665*bd1f8aebSAndroid Build Coastguard Worker 	if (!ptr || !v)
666*bd1f8aebSAndroid Build Coastguard Worker 		return -1;
667*bd1f8aebSAndroid Build Coastguard Worker 
668*bd1f8aebSAndroid Build Coastguard Worker 	p = &v->value[idx].ulong;
669*bd1f8aebSAndroid Build Coastguard Worker 	errno = 0;
670*bd1f8aebSAndroid Build Coastguard Worker 	*p = strtoul(ptr, &ep, base);
671*bd1f8aebSAndroid Build Coastguard Worker 	if ((*ptr && isspace(*ptr & 0xff)) || errno || (*ep != '\0' && *ep != '\n'))
672*bd1f8aebSAndroid Build Coastguard Worker 		goto out;
673*bd1f8aebSAndroid Build Coastguard Worker 
674*bd1f8aebSAndroid Build Coastguard Worker 	return 0;
675*bd1f8aebSAndroid Build Coastguard Worker out:
676*bd1f8aebSAndroid Build Coastguard Worker 	return -1;
677*bd1f8aebSAndroid Build Coastguard Worker }
678*bd1f8aebSAndroid Build Coastguard Worker 
sysfs_devattr_ulong_dec(char * ptr,struct sysfs_devattr_values * v,unsigned int idx)679*bd1f8aebSAndroid Build Coastguard Worker static int sysfs_devattr_ulong_dec(char *ptr, struct sysfs_devattr_values *v, unsigned int idx)
680*bd1f8aebSAndroid Build Coastguard Worker {
681*bd1f8aebSAndroid Build Coastguard Worker 	int rc = sysfs_devattr_ulong(ptr, v, idx, 10);
682*bd1f8aebSAndroid Build Coastguard Worker 	return rc;
683*bd1f8aebSAndroid Build Coastguard Worker }
684*bd1f8aebSAndroid Build Coastguard Worker 
sysfs_devattr_ulong_hex(char * ptr,struct sysfs_devattr_values * v,unsigned int idx)685*bd1f8aebSAndroid Build Coastguard Worker static int sysfs_devattr_ulong_hex(char *ptr, struct sysfs_devattr_values *v, unsigned int idx)
686*bd1f8aebSAndroid Build Coastguard Worker {
687*bd1f8aebSAndroid Build Coastguard Worker 	int rc = sysfs_devattr_ulong(ptr, v, idx, 16);
688*bd1f8aebSAndroid Build Coastguard Worker 	return rc;
689*bd1f8aebSAndroid Build Coastguard Worker }
690*bd1f8aebSAndroid Build Coastguard Worker 
sysfs_devattr_macaddr(char * ptr,struct sysfs_devattr_values * v,unsigned int idx)691*bd1f8aebSAndroid Build Coastguard Worker static int sysfs_devattr_macaddr(char *ptr, struct sysfs_devattr_values *v, unsigned int idx)
692*bd1f8aebSAndroid Build Coastguard Worker {
693*bd1f8aebSAndroid Build Coastguard Worker 	unsigned char *m;
694*bd1f8aebSAndroid Build Coastguard Worker 	int i;
695*bd1f8aebSAndroid Build Coastguard Worker 	unsigned int addrlen;
696*bd1f8aebSAndroid Build Coastguard Worker 
697*bd1f8aebSAndroid Build Coastguard Worker 	if (!ptr || !v)
698*bd1f8aebSAndroid Build Coastguard Worker 		return -1;
699*bd1f8aebSAndroid Build Coastguard Worker 
700*bd1f8aebSAndroid Build Coastguard Worker 	addrlen = v->value[SYSFS_DEVATTR_ADDR_LEN].ulong;
701*bd1f8aebSAndroid Build Coastguard Worker 	m = malloc(addrlen);
702*bd1f8aebSAndroid Build Coastguard Worker 
703*bd1f8aebSAndroid Build Coastguard Worker 	for (i = 0; i < addrlen; i++) {
704*bd1f8aebSAndroid Build Coastguard Worker 		if (i && *(ptr + i * 3 - 1) != ':')
705*bd1f8aebSAndroid Build Coastguard Worker 			goto out;
706*bd1f8aebSAndroid Build Coastguard Worker 		if (sscanf(ptr + i * 3, "%02hhx", &m[i]) != 1)
707*bd1f8aebSAndroid Build Coastguard Worker 			goto out;
708*bd1f8aebSAndroid Build Coastguard Worker 	}
709*bd1f8aebSAndroid Build Coastguard Worker 
710*bd1f8aebSAndroid Build Coastguard Worker 	v->value[idx].ptr = m;
711*bd1f8aebSAndroid Build Coastguard Worker 	return 0;
712*bd1f8aebSAndroid Build Coastguard Worker out:
713*bd1f8aebSAndroid Build Coastguard Worker 	free(m);
714*bd1f8aebSAndroid Build Coastguard Worker 	return -1;
715*bd1f8aebSAndroid Build Coastguard Worker }
716*bd1f8aebSAndroid Build Coastguard Worker #endif
717*bd1f8aebSAndroid Build Coastguard Worker 
find_device_by_sysfs(void)718*bd1f8aebSAndroid Build Coastguard Worker int find_device_by_sysfs(void)
719*bd1f8aebSAndroid Build Coastguard Worker {
720*bd1f8aebSAndroid Build Coastguard Worker 	int rc = -1;
721*bd1f8aebSAndroid Build Coastguard Worker #ifdef USE_SYSFS
722*bd1f8aebSAndroid Build Coastguard Worker 	struct sysfs_class *cls_net;
723*bd1f8aebSAndroid Build Coastguard Worker 	struct dlist *dev_list;
724*bd1f8aebSAndroid Build Coastguard Worker 	struct sysfs_class_device *dev;
725*bd1f8aebSAndroid Build Coastguard Worker 	struct sysfs_attribute *dev_attr;
726*bd1f8aebSAndroid Build Coastguard Worker 	struct sysfs_devattr_values sysfs_devattr_values;
727*bd1f8aebSAndroid Build Coastguard Worker 	int count = 0;
728*bd1f8aebSAndroid Build Coastguard Worker 
729*bd1f8aebSAndroid Build Coastguard Worker 	if (!device.sysfs) {
730*bd1f8aebSAndroid Build Coastguard Worker 		device.sysfs = malloc(sizeof(*device.sysfs));
731*bd1f8aebSAndroid Build Coastguard Worker 		sysfs_devattr_values_init(device.sysfs, 0);
732*bd1f8aebSAndroid Build Coastguard Worker 	}
733*bd1f8aebSAndroid Build Coastguard Worker 
734*bd1f8aebSAndroid Build Coastguard Worker 	cls_net = sysfs_open_class("net");
735*bd1f8aebSAndroid Build Coastguard Worker 	if (!cls_net) {
736*bd1f8aebSAndroid Build Coastguard Worker 		perror("sysfs_open_class");
737*bd1f8aebSAndroid Build Coastguard Worker 		return -1;
738*bd1f8aebSAndroid Build Coastguard Worker 	}
739*bd1f8aebSAndroid Build Coastguard Worker 
740*bd1f8aebSAndroid Build Coastguard Worker 	dev_list = sysfs_get_class_devices(cls_net);
741*bd1f8aebSAndroid Build Coastguard Worker 	if (!dev_list) {
742*bd1f8aebSAndroid Build Coastguard Worker 		perror("sysfs_get_class_devices");
743*bd1f8aebSAndroid Build Coastguard Worker 		goto out;
744*bd1f8aebSAndroid Build Coastguard Worker 	}
745*bd1f8aebSAndroid Build Coastguard Worker 
746*bd1f8aebSAndroid Build Coastguard Worker 	sysfs_devattr_values_init(&sysfs_devattr_values, 0);
747*bd1f8aebSAndroid Build Coastguard Worker 
748*bd1f8aebSAndroid Build Coastguard Worker 	dlist_for_each_data(dev_list, dev, struct sysfs_class_device) {
749*bd1f8aebSAndroid Build Coastguard Worker 		int i;
750*bd1f8aebSAndroid Build Coastguard Worker 		int rc = -1;
751*bd1f8aebSAndroid Build Coastguard Worker 
752*bd1f8aebSAndroid Build Coastguard Worker 		if (device.name && strcmp(dev->name, device.name))
753*bd1f8aebSAndroid Build Coastguard Worker 			goto do_next;
754*bd1f8aebSAndroid Build Coastguard Worker 
755*bd1f8aebSAndroid Build Coastguard Worker 		sysfs_devattr_values_init(&sysfs_devattr_values, 1);
756*bd1f8aebSAndroid Build Coastguard Worker 
757*bd1f8aebSAndroid Build Coastguard Worker 		for (i = 0; i < SYSFS_DEVATTR_NUM; i++) {
758*bd1f8aebSAndroid Build Coastguard Worker 
759*bd1f8aebSAndroid Build Coastguard Worker 			dev_attr = sysfs_get_classdev_attr(dev, sysfs_devattrs[i].name);
760*bd1f8aebSAndroid Build Coastguard Worker 			if (!dev_attr) {
761*bd1f8aebSAndroid Build Coastguard Worker 				perror("sysfs_get_classdev_attr");
762*bd1f8aebSAndroid Build Coastguard Worker 				rc = -1;
763*bd1f8aebSAndroid Build Coastguard Worker 				break;
764*bd1f8aebSAndroid Build Coastguard Worker 			}
765*bd1f8aebSAndroid Build Coastguard Worker 			if (sysfs_read_attribute(dev_attr)) {
766*bd1f8aebSAndroid Build Coastguard Worker 				perror("sysfs_read_attribute");
767*bd1f8aebSAndroid Build Coastguard Worker 				rc = -1;
768*bd1f8aebSAndroid Build Coastguard Worker 				break;
769*bd1f8aebSAndroid Build Coastguard Worker 			}
770*bd1f8aebSAndroid Build Coastguard Worker 			rc = sysfs_devattrs[i].handler(dev_attr->value, &sysfs_devattr_values, i);
771*bd1f8aebSAndroid Build Coastguard Worker 
772*bd1f8aebSAndroid Build Coastguard Worker 			if (rc < 0)
773*bd1f8aebSAndroid Build Coastguard Worker 				break;
774*bd1f8aebSAndroid Build Coastguard Worker 		}
775*bd1f8aebSAndroid Build Coastguard Worker 
776*bd1f8aebSAndroid Build Coastguard Worker 		if (rc < 0)
777*bd1f8aebSAndroid Build Coastguard Worker 			goto do_next;
778*bd1f8aebSAndroid Build Coastguard Worker 
779*bd1f8aebSAndroid Build Coastguard Worker 		if (check_ifflags(sysfs_devattr_values.value[SYSFS_DEVATTR_FLAGS].ulong,
780*bd1f8aebSAndroid Build Coastguard Worker 				  device.name != NULL) < 0)
781*bd1f8aebSAndroid Build Coastguard Worker 			goto do_next;
782*bd1f8aebSAndroid Build Coastguard Worker 
783*bd1f8aebSAndroid Build Coastguard Worker 		if (!sysfs_devattr_values.value[SYSFS_DEVATTR_ADDR_LEN].ulong)
784*bd1f8aebSAndroid Build Coastguard Worker 			goto do_next;
785*bd1f8aebSAndroid Build Coastguard Worker 
786*bd1f8aebSAndroid Build Coastguard Worker 		if (device.sysfs->value[SYSFS_DEVATTR_IFINDEX].ulong) {
787*bd1f8aebSAndroid Build Coastguard Worker 			if (device.sysfs->value[SYSFS_DEVATTR_FLAGS].ulong & IFF_RUNNING)
788*bd1f8aebSAndroid Build Coastguard Worker 				goto do_next;
789*bd1f8aebSAndroid Build Coastguard Worker 		}
790*bd1f8aebSAndroid Build Coastguard Worker 
791*bd1f8aebSAndroid Build Coastguard Worker 		sysfs_devattr_values.ifname = strdup(dev->name);
792*bd1f8aebSAndroid Build Coastguard Worker 		if (!sysfs_devattr_values.ifname) {
793*bd1f8aebSAndroid Build Coastguard Worker 			perror("malloc");
794*bd1f8aebSAndroid Build Coastguard Worker 			goto out;
795*bd1f8aebSAndroid Build Coastguard Worker 		}
796*bd1f8aebSAndroid Build Coastguard Worker 
797*bd1f8aebSAndroid Build Coastguard Worker 		sysfs_devattr_values_init(device.sysfs, 1);
798*bd1f8aebSAndroid Build Coastguard Worker 		memcpy(device.sysfs, &sysfs_devattr_values, sizeof(*device.sysfs));
799*bd1f8aebSAndroid Build Coastguard Worker 		sysfs_devattr_values_init(&sysfs_devattr_values, 0);
800*bd1f8aebSAndroid Build Coastguard Worker 
801*bd1f8aebSAndroid Build Coastguard Worker 		if (count++)
802*bd1f8aebSAndroid Build Coastguard Worker 			break;
803*bd1f8aebSAndroid Build Coastguard Worker 
804*bd1f8aebSAndroid Build Coastguard Worker 		continue;
805*bd1f8aebSAndroid Build Coastguard Worker do_next:
806*bd1f8aebSAndroid Build Coastguard Worker 		sysfs_devattr_values_init(&sysfs_devattr_values, 1);
807*bd1f8aebSAndroid Build Coastguard Worker 	}
808*bd1f8aebSAndroid Build Coastguard Worker 
809*bd1f8aebSAndroid Build Coastguard Worker 	if (count == 1) {
810*bd1f8aebSAndroid Build Coastguard Worker 		device.ifindex = device.sysfs->value[SYSFS_DEVATTR_IFINDEX].ulong;
811*bd1f8aebSAndroid Build Coastguard Worker 		device.name = device.sysfs->ifname;
812*bd1f8aebSAndroid Build Coastguard Worker 	}
813*bd1f8aebSAndroid Build Coastguard Worker 	rc = !device.ifindex;
814*bd1f8aebSAndroid Build Coastguard Worker out:
815*bd1f8aebSAndroid Build Coastguard Worker 	sysfs_close_class(cls_net);
816*bd1f8aebSAndroid Build Coastguard Worker #endif
817*bd1f8aebSAndroid Build Coastguard Worker 	return rc;
818*bd1f8aebSAndroid Build Coastguard Worker }
819*bd1f8aebSAndroid Build Coastguard Worker 
check_device_by_ioctl(int s,struct ifreq * ifr)820*bd1f8aebSAndroid Build Coastguard Worker static int check_device_by_ioctl(int s, struct ifreq *ifr)
821*bd1f8aebSAndroid Build Coastguard Worker {
822*bd1f8aebSAndroid Build Coastguard Worker 	if (ioctl(s, SIOCGIFFLAGS, ifr) < 0) {
823*bd1f8aebSAndroid Build Coastguard Worker 		perror("ioctl(SIOCGIFINDEX");
824*bd1f8aebSAndroid Build Coastguard Worker 		return -1;
825*bd1f8aebSAndroid Build Coastguard Worker 	}
826*bd1f8aebSAndroid Build Coastguard Worker 
827*bd1f8aebSAndroid Build Coastguard Worker 	if (check_ifflags(ifr->ifr_flags, device.name != NULL) < 0)
828*bd1f8aebSAndroid Build Coastguard Worker 		return 1;
829*bd1f8aebSAndroid Build Coastguard Worker 
830*bd1f8aebSAndroid Build Coastguard Worker 	if (ioctl(s, SIOCGIFINDEX, ifr) < 0) {
831*bd1f8aebSAndroid Build Coastguard Worker 		perror("ioctl(SIOCGIFINDEX");
832*bd1f8aebSAndroid Build Coastguard Worker 		return -1;
833*bd1f8aebSAndroid Build Coastguard Worker 	}
834*bd1f8aebSAndroid Build Coastguard Worker 
835*bd1f8aebSAndroid Build Coastguard Worker 	return 0;
836*bd1f8aebSAndroid Build Coastguard Worker }
837*bd1f8aebSAndroid Build Coastguard Worker 
find_device_by_ioctl(void)838*bd1f8aebSAndroid Build Coastguard Worker static int find_device_by_ioctl(void)
839*bd1f8aebSAndroid Build Coastguard Worker {
840*bd1f8aebSAndroid Build Coastguard Worker 	int s;
841*bd1f8aebSAndroid Build Coastguard Worker 	struct ifreq *ifr0, *ifr, *ifr_end;
842*bd1f8aebSAndroid Build Coastguard Worker 	size_t ifrsize = sizeof(*ifr);
843*bd1f8aebSAndroid Build Coastguard Worker 	struct ifconf ifc;
844*bd1f8aebSAndroid Build Coastguard Worker 	static struct ifreq ifrbuf;
845*bd1f8aebSAndroid Build Coastguard Worker 	int count = 0;
846*bd1f8aebSAndroid Build Coastguard Worker 
847*bd1f8aebSAndroid Build Coastguard Worker 	s = socket(AF_INET, SOCK_DGRAM, 0);
848*bd1f8aebSAndroid Build Coastguard Worker 	if (s < 0) {
849*bd1f8aebSAndroid Build Coastguard Worker 		perror("socket");
850*bd1f8aebSAndroid Build Coastguard Worker 		return -1;
851*bd1f8aebSAndroid Build Coastguard Worker 	}
852*bd1f8aebSAndroid Build Coastguard Worker 
853*bd1f8aebSAndroid Build Coastguard Worker 	memset(&ifrbuf, 0, sizeof(ifrbuf));
854*bd1f8aebSAndroid Build Coastguard Worker 
855*bd1f8aebSAndroid Build Coastguard Worker 	if (device.name) {
856*bd1f8aebSAndroid Build Coastguard Worker 		strncpy(ifrbuf.ifr_name, device.name, sizeof(ifrbuf.ifr_name) - 1);
857*bd1f8aebSAndroid Build Coastguard Worker 		if (check_device_by_ioctl(s, &ifrbuf))
858*bd1f8aebSAndroid Build Coastguard Worker 			goto out;
859*bd1f8aebSAndroid Build Coastguard Worker 		count++;
860*bd1f8aebSAndroid Build Coastguard Worker 	} else {
861*bd1f8aebSAndroid Build Coastguard Worker 		do {
862*bd1f8aebSAndroid Build Coastguard Worker 			int rc;
863*bd1f8aebSAndroid Build Coastguard Worker 			ifr0 = malloc(ifrsize);
864*bd1f8aebSAndroid Build Coastguard Worker 			if (!ifr0) {
865*bd1f8aebSAndroid Build Coastguard Worker 				perror("malloc");
866*bd1f8aebSAndroid Build Coastguard Worker 				goto out;
867*bd1f8aebSAndroid Build Coastguard Worker 			}
868*bd1f8aebSAndroid Build Coastguard Worker 
869*bd1f8aebSAndroid Build Coastguard Worker 			ifc.ifc_buf = (char *)ifr0;
870*bd1f8aebSAndroid Build Coastguard Worker 			ifc.ifc_len = ifrsize;
871*bd1f8aebSAndroid Build Coastguard Worker 
872*bd1f8aebSAndroid Build Coastguard Worker 			rc = ioctl(s, SIOCGIFCONF, &ifc);
873*bd1f8aebSAndroid Build Coastguard Worker 			if (rc < 0) {
874*bd1f8aebSAndroid Build Coastguard Worker 				perror("ioctl(SIOCFIFCONF");
875*bd1f8aebSAndroid Build Coastguard Worker 				goto out;
876*bd1f8aebSAndroid Build Coastguard Worker 			}
877*bd1f8aebSAndroid Build Coastguard Worker 
878*bd1f8aebSAndroid Build Coastguard Worker 			if (ifc.ifc_len + sizeof(*ifr0) + sizeof(struct sockaddr_storage) - sizeof(struct sockaddr) <= ifrsize)
879*bd1f8aebSAndroid Build Coastguard Worker 				break;
880*bd1f8aebSAndroid Build Coastguard Worker 			ifrsize *= 2;
881*bd1f8aebSAndroid Build Coastguard Worker 			free(ifr0);
882*bd1f8aebSAndroid Build Coastguard Worker 			ifr0 = NULL;
883*bd1f8aebSAndroid Build Coastguard Worker 		} while(ifrsize < INT_MAX / 2);
884*bd1f8aebSAndroid Build Coastguard Worker 
885*bd1f8aebSAndroid Build Coastguard Worker 		if (!ifr0) {
886*bd1f8aebSAndroid Build Coastguard Worker 			fprintf(stderr, "arping: too many interfaces!?\n");
887*bd1f8aebSAndroid Build Coastguard Worker 			goto out;
888*bd1f8aebSAndroid Build Coastguard Worker 		}
889*bd1f8aebSAndroid Build Coastguard Worker 
890*bd1f8aebSAndroid Build Coastguard Worker 		ifr_end = (struct ifreq *)(((char *)ifr0) + ifc.ifc_len - sizeof(*ifr0));
891*bd1f8aebSAndroid Build Coastguard Worker 		for (ifr = ifr0; ifr <= ifr_end; ifr++) {
892*bd1f8aebSAndroid Build Coastguard Worker 			if (check_device_by_ioctl(s, &ifrbuf))
893*bd1f8aebSAndroid Build Coastguard Worker 				continue;
894*bd1f8aebSAndroid Build Coastguard Worker 			memcpy(&ifrbuf.ifr_name, ifr->ifr_name, sizeof(ifrbuf.ifr_name));
895*bd1f8aebSAndroid Build Coastguard Worker 			if (count++)
896*bd1f8aebSAndroid Build Coastguard Worker 				break;
897*bd1f8aebSAndroid Build Coastguard Worker 		}
898*bd1f8aebSAndroid Build Coastguard Worker 	}
899*bd1f8aebSAndroid Build Coastguard Worker 
900*bd1f8aebSAndroid Build Coastguard Worker 	close(s);
901*bd1f8aebSAndroid Build Coastguard Worker 
902*bd1f8aebSAndroid Build Coastguard Worker 	if (count == 1) {
903*bd1f8aebSAndroid Build Coastguard Worker 		device.ifindex = ifrbuf.ifr_ifindex;
904*bd1f8aebSAndroid Build Coastguard Worker 		device.name = ifrbuf.ifr_name;
905*bd1f8aebSAndroid Build Coastguard Worker 	}
906*bd1f8aebSAndroid Build Coastguard Worker 	return !device.ifindex;
907*bd1f8aebSAndroid Build Coastguard Worker out:
908*bd1f8aebSAndroid Build Coastguard Worker 	close(s);
909*bd1f8aebSAndroid Build Coastguard Worker 	return -1;
910*bd1f8aebSAndroid Build Coastguard Worker }
911*bd1f8aebSAndroid Build Coastguard Worker 
find_device(void)912*bd1f8aebSAndroid Build Coastguard Worker static int find_device(void)
913*bd1f8aebSAndroid Build Coastguard Worker {
914*bd1f8aebSAndroid Build Coastguard Worker 	int rc;
915*bd1f8aebSAndroid Build Coastguard Worker 	rc = find_device_by_ifaddrs();
916*bd1f8aebSAndroid Build Coastguard Worker 	if (rc >= 0)
917*bd1f8aebSAndroid Build Coastguard Worker 		goto out;
918*bd1f8aebSAndroid Build Coastguard Worker 	rc = find_device_by_sysfs();
919*bd1f8aebSAndroid Build Coastguard Worker 	if (rc >= 0)
920*bd1f8aebSAndroid Build Coastguard Worker 		goto out;
921*bd1f8aebSAndroid Build Coastguard Worker 	rc = find_device_by_ioctl();
922*bd1f8aebSAndroid Build Coastguard Worker out:
923*bd1f8aebSAndroid Build Coastguard Worker 	return rc;
924*bd1f8aebSAndroid Build Coastguard Worker }
925*bd1f8aebSAndroid Build Coastguard Worker 
926*bd1f8aebSAndroid Build Coastguard Worker /*
927*bd1f8aebSAndroid Build Coastguard Worker  * set_device_broadcast()
928*bd1f8aebSAndroid Build Coastguard Worker  *
929*bd1f8aebSAndroid Build Coastguard Worker  * This fills the device "broadcast address"
930*bd1f8aebSAndroid Build Coastguard Worker  * based on information found by find_device() funcion.
931*bd1f8aebSAndroid Build Coastguard Worker  */
set_device_broadcast_ifaddrs_one(struct device * device,unsigned char * ba,size_t balen,int fatal)932*bd1f8aebSAndroid Build Coastguard Worker static int set_device_broadcast_ifaddrs_one(struct device *device, unsigned char *ba, size_t balen, int fatal)
933*bd1f8aebSAndroid Build Coastguard Worker {
934*bd1f8aebSAndroid Build Coastguard Worker #ifndef WITHOUT_IFADDRS
935*bd1f8aebSAndroid Build Coastguard Worker 	struct ifaddrs *ifa;
936*bd1f8aebSAndroid Build Coastguard Worker 	struct sockaddr_ll *sll;
937*bd1f8aebSAndroid Build Coastguard Worker 
938*bd1f8aebSAndroid Build Coastguard Worker 	if (!device)
939*bd1f8aebSAndroid Build Coastguard Worker 		return -1;
940*bd1f8aebSAndroid Build Coastguard Worker 
941*bd1f8aebSAndroid Build Coastguard Worker 	ifa = device->ifa;
942*bd1f8aebSAndroid Build Coastguard Worker 	if (!ifa)
943*bd1f8aebSAndroid Build Coastguard Worker 		return -1;
944*bd1f8aebSAndroid Build Coastguard Worker 
945*bd1f8aebSAndroid Build Coastguard Worker 	sll = (struct sockaddr_ll *)ifa->ifa_broadaddr;
946*bd1f8aebSAndroid Build Coastguard Worker 
947*bd1f8aebSAndroid Build Coastguard Worker 	if (sll->sll_halen != balen) {
948*bd1f8aebSAndroid Build Coastguard Worker 		if (fatal) {
949*bd1f8aebSAndroid Build Coastguard Worker 			if (!quiet)
950*bd1f8aebSAndroid Build Coastguard Worker 				printf("Address length does not match...\n");
951*bd1f8aebSAndroid Build Coastguard Worker 			exit(2);
952*bd1f8aebSAndroid Build Coastguard Worker 		}
953*bd1f8aebSAndroid Build Coastguard Worker 		return -1;
954*bd1f8aebSAndroid Build Coastguard Worker 	}
955*bd1f8aebSAndroid Build Coastguard Worker 	memcpy(ba, sll->sll_addr, sll->sll_halen);
956*bd1f8aebSAndroid Build Coastguard Worker 	return 0;
957*bd1f8aebSAndroid Build Coastguard Worker #else
958*bd1f8aebSAndroid Build Coastguard Worker 	return -1;
959*bd1f8aebSAndroid Build Coastguard Worker #endif
960*bd1f8aebSAndroid Build Coastguard Worker }
set_device_broadcast_sysfs(struct device * device,unsigned char * ba,size_t balen)961*bd1f8aebSAndroid Build Coastguard Worker int set_device_broadcast_sysfs(struct device *device, unsigned char *ba, size_t balen)
962*bd1f8aebSAndroid Build Coastguard Worker {
963*bd1f8aebSAndroid Build Coastguard Worker #ifdef USE_SYSFS
964*bd1f8aebSAndroid Build Coastguard Worker 	struct sysfs_devattr_values *v;
965*bd1f8aebSAndroid Build Coastguard Worker 	if (!device)
966*bd1f8aebSAndroid Build Coastguard Worker 		return -1;
967*bd1f8aebSAndroid Build Coastguard Worker 	v = device->sysfs;
968*bd1f8aebSAndroid Build Coastguard Worker 	if (!v)
969*bd1f8aebSAndroid Build Coastguard Worker 		return -1;
970*bd1f8aebSAndroid Build Coastguard Worker 	if (v->value[SYSFS_DEVATTR_ADDR_LEN].ulong != balen)
971*bd1f8aebSAndroid Build Coastguard Worker 		return -1;
972*bd1f8aebSAndroid Build Coastguard Worker 	memcpy(ba, v->value[SYSFS_DEVATTR_BROADCAST].ptr, balen);
973*bd1f8aebSAndroid Build Coastguard Worker 	return 0;
974*bd1f8aebSAndroid Build Coastguard Worker #else
975*bd1f8aebSAndroid Build Coastguard Worker 	return -1;
976*bd1f8aebSAndroid Build Coastguard Worker #endif
977*bd1f8aebSAndroid Build Coastguard Worker }
978*bd1f8aebSAndroid Build Coastguard Worker 
set_device_broadcast_fallback(struct device * device,unsigned char * ba,size_t balen)979*bd1f8aebSAndroid Build Coastguard Worker static int set_device_broadcast_fallback(struct device *device, unsigned char *ba, size_t balen)
980*bd1f8aebSAndroid Build Coastguard Worker {
981*bd1f8aebSAndroid Build Coastguard Worker 	if (!quiet)
982*bd1f8aebSAndroid Build Coastguard Worker 		fprintf(stderr, "WARNING: using default broadcast address.\n");
983*bd1f8aebSAndroid Build Coastguard Worker 	memset(ba, -1, balen);
984*bd1f8aebSAndroid Build Coastguard Worker 	return 0;
985*bd1f8aebSAndroid Build Coastguard Worker }
986*bd1f8aebSAndroid Build Coastguard Worker 
set_device_broadcast(struct device * dev,unsigned char * ba,size_t balen)987*bd1f8aebSAndroid Build Coastguard Worker static void set_device_broadcast(struct device *dev, unsigned char *ba, size_t balen)
988*bd1f8aebSAndroid Build Coastguard Worker {
989*bd1f8aebSAndroid Build Coastguard Worker 	if (!set_device_broadcast_ifaddrs_one(dev, ba, balen, 0))
990*bd1f8aebSAndroid Build Coastguard Worker 		return;
991*bd1f8aebSAndroid Build Coastguard Worker 	if (!set_device_broadcast_sysfs(dev, ba, balen))
992*bd1f8aebSAndroid Build Coastguard Worker 		return;
993*bd1f8aebSAndroid Build Coastguard Worker 	set_device_broadcast_fallback(dev, ba, balen);
994*bd1f8aebSAndroid Build Coastguard Worker }
995*bd1f8aebSAndroid Build Coastguard Worker 
996*bd1f8aebSAndroid Build Coastguard Worker int
main(int argc,char ** argv)997*bd1f8aebSAndroid Build Coastguard Worker main(int argc, char **argv)
998*bd1f8aebSAndroid Build Coastguard Worker {
999*bd1f8aebSAndroid Build Coastguard Worker 	int socket_errno;
1000*bd1f8aebSAndroid Build Coastguard Worker 	int ch;
1001*bd1f8aebSAndroid Build Coastguard Worker 
1002*bd1f8aebSAndroid Build Coastguard Worker 	limit_capabilities();
1003*bd1f8aebSAndroid Build Coastguard Worker 
1004*bd1f8aebSAndroid Build Coastguard Worker #ifdef USE_IDN
1005*bd1f8aebSAndroid Build Coastguard Worker 	setlocale(LC_ALL, "");
1006*bd1f8aebSAndroid Build Coastguard Worker #endif
1007*bd1f8aebSAndroid Build Coastguard Worker 
1008*bd1f8aebSAndroid Build Coastguard Worker 	enable_capability_raw();
1009*bd1f8aebSAndroid Build Coastguard Worker 
1010*bd1f8aebSAndroid Build Coastguard Worker 	s = socket(PF_PACKET, SOCK_DGRAM, 0);
1011*bd1f8aebSAndroid Build Coastguard Worker 	socket_errno = errno;
1012*bd1f8aebSAndroid Build Coastguard Worker 
1013*bd1f8aebSAndroid Build Coastguard Worker 	disable_capability_raw();
1014*bd1f8aebSAndroid Build Coastguard Worker 
1015*bd1f8aebSAndroid Build Coastguard Worker 	while ((ch = getopt(argc, argv, "h?bfDUAqc:w:s:I:V")) != EOF) {
1016*bd1f8aebSAndroid Build Coastguard Worker 		switch(ch) {
1017*bd1f8aebSAndroid Build Coastguard Worker 		case 'b':
1018*bd1f8aebSAndroid Build Coastguard Worker 			broadcast_only=1;
1019*bd1f8aebSAndroid Build Coastguard Worker 			break;
1020*bd1f8aebSAndroid Build Coastguard Worker 		case 'D':
1021*bd1f8aebSAndroid Build Coastguard Worker 			dad++;
1022*bd1f8aebSAndroid Build Coastguard Worker 			quit_on_reply=1;
1023*bd1f8aebSAndroid Build Coastguard Worker 			break;
1024*bd1f8aebSAndroid Build Coastguard Worker 		case 'U':
1025*bd1f8aebSAndroid Build Coastguard Worker 			unsolicited++;
1026*bd1f8aebSAndroid Build Coastguard Worker 			break;
1027*bd1f8aebSAndroid Build Coastguard Worker 		case 'A':
1028*bd1f8aebSAndroid Build Coastguard Worker 			advert++;
1029*bd1f8aebSAndroid Build Coastguard Worker 			unsolicited++;
1030*bd1f8aebSAndroid Build Coastguard Worker 			break;
1031*bd1f8aebSAndroid Build Coastguard Worker 		case 'q':
1032*bd1f8aebSAndroid Build Coastguard Worker 			quiet++;
1033*bd1f8aebSAndroid Build Coastguard Worker 			break;
1034*bd1f8aebSAndroid Build Coastguard Worker 		case 'c':
1035*bd1f8aebSAndroid Build Coastguard Worker 			count = atoi(optarg);
1036*bd1f8aebSAndroid Build Coastguard Worker 			break;
1037*bd1f8aebSAndroid Build Coastguard Worker 		case 'w':
1038*bd1f8aebSAndroid Build Coastguard Worker 			timeout = atoi(optarg);
1039*bd1f8aebSAndroid Build Coastguard Worker 			break;
1040*bd1f8aebSAndroid Build Coastguard Worker 		case 'I':
1041*bd1f8aebSAndroid Build Coastguard Worker 			device.name = optarg;
1042*bd1f8aebSAndroid Build Coastguard Worker 			break;
1043*bd1f8aebSAndroid Build Coastguard Worker 		case 'f':
1044*bd1f8aebSAndroid Build Coastguard Worker 			quit_on_reply=1;
1045*bd1f8aebSAndroid Build Coastguard Worker 			break;
1046*bd1f8aebSAndroid Build Coastguard Worker 		case 's':
1047*bd1f8aebSAndroid Build Coastguard Worker 			source = optarg;
1048*bd1f8aebSAndroid Build Coastguard Worker 			break;
1049*bd1f8aebSAndroid Build Coastguard Worker 		case 'V':
1050*bd1f8aebSAndroid Build Coastguard Worker 			printf("arping utility, iputils-%s\n", SNAPSHOT);
1051*bd1f8aebSAndroid Build Coastguard Worker 			exit(0);
1052*bd1f8aebSAndroid Build Coastguard Worker 		case 'h':
1053*bd1f8aebSAndroid Build Coastguard Worker 		case '?':
1054*bd1f8aebSAndroid Build Coastguard Worker 		default:
1055*bd1f8aebSAndroid Build Coastguard Worker 			usage();
1056*bd1f8aebSAndroid Build Coastguard Worker 		}
1057*bd1f8aebSAndroid Build Coastguard Worker 	}
1058*bd1f8aebSAndroid Build Coastguard Worker 	argc -= optind;
1059*bd1f8aebSAndroid Build Coastguard Worker 	argv += optind;
1060*bd1f8aebSAndroid Build Coastguard Worker 
1061*bd1f8aebSAndroid Build Coastguard Worker 	if (argc != 1)
1062*bd1f8aebSAndroid Build Coastguard Worker 		usage();
1063*bd1f8aebSAndroid Build Coastguard Worker 
1064*bd1f8aebSAndroid Build Coastguard Worker 	target = *argv;
1065*bd1f8aebSAndroid Build Coastguard Worker 
1066*bd1f8aebSAndroid Build Coastguard Worker 	if (device.name && !*device.name)
1067*bd1f8aebSAndroid Build Coastguard Worker 		device.name = NULL;
1068*bd1f8aebSAndroid Build Coastguard Worker 
1069*bd1f8aebSAndroid Build Coastguard Worker 	if (s < 0) {
1070*bd1f8aebSAndroid Build Coastguard Worker 		errno = socket_errno;
1071*bd1f8aebSAndroid Build Coastguard Worker 		perror("arping: socket");
1072*bd1f8aebSAndroid Build Coastguard Worker 		exit(2);
1073*bd1f8aebSAndroid Build Coastguard Worker 	}
1074*bd1f8aebSAndroid Build Coastguard Worker 
1075*bd1f8aebSAndroid Build Coastguard Worker 	if (find_device() < 0)
1076*bd1f8aebSAndroid Build Coastguard Worker 		exit(2);
1077*bd1f8aebSAndroid Build Coastguard Worker 
1078*bd1f8aebSAndroid Build Coastguard Worker 	if (!device.ifindex) {
1079*bd1f8aebSAndroid Build Coastguard Worker 		if (device.name) {
1080*bd1f8aebSAndroid Build Coastguard Worker 			fprintf(stderr, "arping: Device %s not available.\n", device.name);
1081*bd1f8aebSAndroid Build Coastguard Worker 			exit(2);
1082*bd1f8aebSAndroid Build Coastguard Worker 		}
1083*bd1f8aebSAndroid Build Coastguard Worker 		fprintf(stderr, "arping: device (option -I) is required.\n");
1084*bd1f8aebSAndroid Build Coastguard Worker 		usage();
1085*bd1f8aebSAndroid Build Coastguard Worker 	}
1086*bd1f8aebSAndroid Build Coastguard Worker 
1087*bd1f8aebSAndroid Build Coastguard Worker 	if (inet_aton(target, &dst) != 1) {
1088*bd1f8aebSAndroid Build Coastguard Worker 		struct hostent *hp;
1089*bd1f8aebSAndroid Build Coastguard Worker 		char *idn = target;
1090*bd1f8aebSAndroid Build Coastguard Worker #ifdef USE_IDN
1091*bd1f8aebSAndroid Build Coastguard Worker 		int rc;
1092*bd1f8aebSAndroid Build Coastguard Worker 
1093*bd1f8aebSAndroid Build Coastguard Worker 		rc = idna_to_ascii_lz(target, &idn, 0);
1094*bd1f8aebSAndroid Build Coastguard Worker 
1095*bd1f8aebSAndroid Build Coastguard Worker 		if (rc != IDNA_SUCCESS) {
1096*bd1f8aebSAndroid Build Coastguard Worker 			fprintf(stderr, "arping: IDN encoding failed: %s\n", idna_strerror(rc));
1097*bd1f8aebSAndroid Build Coastguard Worker 			exit(2);
1098*bd1f8aebSAndroid Build Coastguard Worker 		}
1099*bd1f8aebSAndroid Build Coastguard Worker #endif
1100*bd1f8aebSAndroid Build Coastguard Worker 
1101*bd1f8aebSAndroid Build Coastguard Worker 		hp = gethostbyname2(idn, AF_INET);
1102*bd1f8aebSAndroid Build Coastguard Worker 		if (!hp) {
1103*bd1f8aebSAndroid Build Coastguard Worker 			fprintf(stderr, "arping: unknown host %s\n", target);
1104*bd1f8aebSAndroid Build Coastguard Worker 			exit(2);
1105*bd1f8aebSAndroid Build Coastguard Worker 		}
1106*bd1f8aebSAndroid Build Coastguard Worker 
1107*bd1f8aebSAndroid Build Coastguard Worker #ifdef USE_IDN
1108*bd1f8aebSAndroid Build Coastguard Worker 		free(idn);
1109*bd1f8aebSAndroid Build Coastguard Worker #endif
1110*bd1f8aebSAndroid Build Coastguard Worker 
1111*bd1f8aebSAndroid Build Coastguard Worker 		memcpy(&dst, hp->h_addr, 4);
1112*bd1f8aebSAndroid Build Coastguard Worker 	}
1113*bd1f8aebSAndroid Build Coastguard Worker 
1114*bd1f8aebSAndroid Build Coastguard Worker 	if (source && inet_aton(source, &src) != 1) {
1115*bd1f8aebSAndroid Build Coastguard Worker 		fprintf(stderr, "arping: invalid source %s\n", source);
1116*bd1f8aebSAndroid Build Coastguard Worker 		exit(2);
1117*bd1f8aebSAndroid Build Coastguard Worker 	}
1118*bd1f8aebSAndroid Build Coastguard Worker 
1119*bd1f8aebSAndroid Build Coastguard Worker 	if (!dad && unsolicited && src.s_addr == 0)
1120*bd1f8aebSAndroid Build Coastguard Worker 		src = dst;
1121*bd1f8aebSAndroid Build Coastguard Worker 
1122*bd1f8aebSAndroid Build Coastguard Worker 	if (!dad || src.s_addr) {
1123*bd1f8aebSAndroid Build Coastguard Worker 		struct sockaddr_in saddr;
1124*bd1f8aebSAndroid Build Coastguard Worker 		int probe_fd = socket(AF_INET, SOCK_DGRAM, 0);
1125*bd1f8aebSAndroid Build Coastguard Worker 
1126*bd1f8aebSAndroid Build Coastguard Worker 		if (probe_fd < 0) {
1127*bd1f8aebSAndroid Build Coastguard Worker 			perror("socket");
1128*bd1f8aebSAndroid Build Coastguard Worker 			exit(2);
1129*bd1f8aebSAndroid Build Coastguard Worker 		}
1130*bd1f8aebSAndroid Build Coastguard Worker 		if (device.name) {
1131*bd1f8aebSAndroid Build Coastguard Worker 			enable_capability_raw();
1132*bd1f8aebSAndroid Build Coastguard Worker 
1133*bd1f8aebSAndroid Build Coastguard Worker 			if (setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, device.name, strlen(device.name)+1) == -1)
1134*bd1f8aebSAndroid Build Coastguard Worker 				perror("WARNING: interface is ignored");
1135*bd1f8aebSAndroid Build Coastguard Worker 
1136*bd1f8aebSAndroid Build Coastguard Worker 			disable_capability_raw();
1137*bd1f8aebSAndroid Build Coastguard Worker 		}
1138*bd1f8aebSAndroid Build Coastguard Worker 		memset(&saddr, 0, sizeof(saddr));
1139*bd1f8aebSAndroid Build Coastguard Worker 		saddr.sin_family = AF_INET;
1140*bd1f8aebSAndroid Build Coastguard Worker 		if (src.s_addr) {
1141*bd1f8aebSAndroid Build Coastguard Worker 			saddr.sin_addr = src;
1142*bd1f8aebSAndroid Build Coastguard Worker 			if (bind(probe_fd, (struct sockaddr*)&saddr, sizeof(saddr)) == -1) {
1143*bd1f8aebSAndroid Build Coastguard Worker 				perror("bind");
1144*bd1f8aebSAndroid Build Coastguard Worker 				exit(2);
1145*bd1f8aebSAndroid Build Coastguard Worker 			}
1146*bd1f8aebSAndroid Build Coastguard Worker 		} else if (!dad) {
1147*bd1f8aebSAndroid Build Coastguard Worker 			int on = 1;
1148*bd1f8aebSAndroid Build Coastguard Worker 			socklen_t alen = sizeof(saddr);
1149*bd1f8aebSAndroid Build Coastguard Worker 
1150*bd1f8aebSAndroid Build Coastguard Worker 			saddr.sin_port = htons(1025);
1151*bd1f8aebSAndroid Build Coastguard Worker 			saddr.sin_addr = dst;
1152*bd1f8aebSAndroid Build Coastguard Worker 
1153*bd1f8aebSAndroid Build Coastguard Worker 			if (setsockopt(probe_fd, SOL_SOCKET, SO_DONTROUTE, (char*)&on, sizeof(on)) == -1)
1154*bd1f8aebSAndroid Build Coastguard Worker 				perror("WARNING: setsockopt(SO_DONTROUTE)");
1155*bd1f8aebSAndroid Build Coastguard Worker 			if (connect(probe_fd, (struct sockaddr*)&saddr, sizeof(saddr)) == -1) {
1156*bd1f8aebSAndroid Build Coastguard Worker 				perror("connect");
1157*bd1f8aebSAndroid Build Coastguard Worker 				exit(2);
1158*bd1f8aebSAndroid Build Coastguard Worker 			}
1159*bd1f8aebSAndroid Build Coastguard Worker 			if (getsockname(probe_fd, (struct sockaddr*)&saddr, &alen) == -1) {
1160*bd1f8aebSAndroid Build Coastguard Worker 				perror("getsockname");
1161*bd1f8aebSAndroid Build Coastguard Worker 				exit(2);
1162*bd1f8aebSAndroid Build Coastguard Worker 			}
1163*bd1f8aebSAndroid Build Coastguard Worker 			src = saddr.sin_addr;
1164*bd1f8aebSAndroid Build Coastguard Worker 		}
1165*bd1f8aebSAndroid Build Coastguard Worker 		close(probe_fd);
1166*bd1f8aebSAndroid Build Coastguard Worker 	};
1167*bd1f8aebSAndroid Build Coastguard Worker 
1168*bd1f8aebSAndroid Build Coastguard Worker 	((struct sockaddr_ll *)&me)->sll_family = AF_PACKET;
1169*bd1f8aebSAndroid Build Coastguard Worker 	((struct sockaddr_ll *)&me)->sll_ifindex = device.ifindex;
1170*bd1f8aebSAndroid Build Coastguard Worker 	((struct sockaddr_ll *)&me)->sll_protocol = htons(ETH_P_ARP);
1171*bd1f8aebSAndroid Build Coastguard Worker 	if (bind(s, (struct sockaddr*)&me, sizeof(me)) == -1) {
1172*bd1f8aebSAndroid Build Coastguard Worker 		perror("bind");
1173*bd1f8aebSAndroid Build Coastguard Worker 		exit(2);
1174*bd1f8aebSAndroid Build Coastguard Worker 	}
1175*bd1f8aebSAndroid Build Coastguard Worker 
1176*bd1f8aebSAndroid Build Coastguard Worker 	if (1) {
1177*bd1f8aebSAndroid Build Coastguard Worker 		socklen_t alen = sizeof(me);
1178*bd1f8aebSAndroid Build Coastguard Worker 		if (getsockname(s, (struct sockaddr*)&me, &alen) == -1) {
1179*bd1f8aebSAndroid Build Coastguard Worker 			perror("getsockname");
1180*bd1f8aebSAndroid Build Coastguard Worker 			exit(2);
1181*bd1f8aebSAndroid Build Coastguard Worker 		}
1182*bd1f8aebSAndroid Build Coastguard Worker 	}
1183*bd1f8aebSAndroid Build Coastguard Worker 	if (((struct sockaddr_ll *)&me)->sll_halen == 0) {
1184*bd1f8aebSAndroid Build Coastguard Worker 		if (!quiet)
1185*bd1f8aebSAndroid Build Coastguard Worker 			printf("Interface \"%s\" is not ARPable (no ll address)\n", device.name);
1186*bd1f8aebSAndroid Build Coastguard Worker 		exit(dad?0:2);
1187*bd1f8aebSAndroid Build Coastguard Worker 	}
1188*bd1f8aebSAndroid Build Coastguard Worker 
1189*bd1f8aebSAndroid Build Coastguard Worker 	he = me;
1190*bd1f8aebSAndroid Build Coastguard Worker 
1191*bd1f8aebSAndroid Build Coastguard Worker 	set_device_broadcast(&device, ((struct sockaddr_ll *)&he)->sll_addr,
1192*bd1f8aebSAndroid Build Coastguard Worker 			     ((struct sockaddr_ll *)&he)->sll_halen);
1193*bd1f8aebSAndroid Build Coastguard Worker 
1194*bd1f8aebSAndroid Build Coastguard Worker 	if (!quiet) {
1195*bd1f8aebSAndroid Build Coastguard Worker 		printf("ARPING %s ", inet_ntoa(dst));
1196*bd1f8aebSAndroid Build Coastguard Worker 		printf("from %s %s\n",  inet_ntoa(src), device.name ? : "");
1197*bd1f8aebSAndroid Build Coastguard Worker 	}
1198*bd1f8aebSAndroid Build Coastguard Worker 
1199*bd1f8aebSAndroid Build Coastguard Worker 	if (!src.s_addr && !dad) {
1200*bd1f8aebSAndroid Build Coastguard Worker 		fprintf(stderr, "arping: no source address in not-DAD mode\n");
1201*bd1f8aebSAndroid Build Coastguard Worker 		exit(2);
1202*bd1f8aebSAndroid Build Coastguard Worker 	}
1203*bd1f8aebSAndroid Build Coastguard Worker 
1204*bd1f8aebSAndroid Build Coastguard Worker 	drop_capabilities();
1205*bd1f8aebSAndroid Build Coastguard Worker 
1206*bd1f8aebSAndroid Build Coastguard Worker 	set_signal(SIGINT, finish);
1207*bd1f8aebSAndroid Build Coastguard Worker 	set_signal(SIGALRM, catcher);
1208*bd1f8aebSAndroid Build Coastguard Worker 
1209*bd1f8aebSAndroid Build Coastguard Worker 	catcher();
1210*bd1f8aebSAndroid Build Coastguard Worker 
1211*bd1f8aebSAndroid Build Coastguard Worker 	while(1) {
1212*bd1f8aebSAndroid Build Coastguard Worker 		sigset_t sset, osset;
1213*bd1f8aebSAndroid Build Coastguard Worker 		unsigned char packet[4096];
1214*bd1f8aebSAndroid Build Coastguard Worker 		struct sockaddr_storage from;
1215*bd1f8aebSAndroid Build Coastguard Worker 		socklen_t alen = sizeof(from);
1216*bd1f8aebSAndroid Build Coastguard Worker 		int cc;
1217*bd1f8aebSAndroid Build Coastguard Worker 
1218*bd1f8aebSAndroid Build Coastguard Worker 		if ((cc = recvfrom(s, packet, sizeof(packet), 0,
1219*bd1f8aebSAndroid Build Coastguard Worker 				   (struct sockaddr *)&from, &alen)) < 0) {
1220*bd1f8aebSAndroid Build Coastguard Worker 			perror("arping: recvfrom");
1221*bd1f8aebSAndroid Build Coastguard Worker 			continue;
1222*bd1f8aebSAndroid Build Coastguard Worker 		}
1223*bd1f8aebSAndroid Build Coastguard Worker 
1224*bd1f8aebSAndroid Build Coastguard Worker 		sigemptyset(&sset);
1225*bd1f8aebSAndroid Build Coastguard Worker 		sigaddset(&sset, SIGALRM);
1226*bd1f8aebSAndroid Build Coastguard Worker 		sigaddset(&sset, SIGINT);
1227*bd1f8aebSAndroid Build Coastguard Worker 		sigprocmask(SIG_BLOCK, &sset, &osset);
1228*bd1f8aebSAndroid Build Coastguard Worker 		recv_pack(packet, cc, (struct sockaddr_ll *)&from);
1229*bd1f8aebSAndroid Build Coastguard Worker 		sigprocmask(SIG_SETMASK, &osset, NULL);
1230*bd1f8aebSAndroid Build Coastguard Worker 	}
1231*bd1f8aebSAndroid Build Coastguard Worker }
1232*bd1f8aebSAndroid Build Coastguard Worker 
1233*bd1f8aebSAndroid Build Coastguard Worker 
1234