4 |
* |
* |
5 |
* Mostly stolen from: dhcpcd - DHCP client daemon |
* Mostly stolen from: dhcpcd - DHCP client daemon |
6 |
* by Yoichi Hariguchi <yoichi@fore.com> |
* by Yoichi Hariguchi <yoichi@fore.com> |
7 |
|
* |
8 |
|
* Licensed under GPLv2, see file LICENSE in this tarball for details. |
9 |
*/ |
*/ |
|
|
|
10 |
#include <netinet/if_ether.h> |
#include <netinet/if_ether.h> |
11 |
#include <net/if_arp.h> |
#include <net/if_arp.h> |
12 |
|
|
13 |
#include "common.h" |
#include "common.h" |
14 |
#include "dhcpd.h" |
#include "dhcpd.h" |
15 |
|
|
|
|
|
16 |
struct arpMsg { |
struct arpMsg { |
17 |
/* Ethernet header */ |
/* Ethernet header */ |
18 |
uint8_t h_dest[6]; /* 00 destination ether addr */ |
uint8_t h_dest[6]; /* 00 destination ether addr */ |
36 |
ARP_MSG_SIZE = 0x2a |
ARP_MSG_SIZE = 0x2a |
37 |
}; |
}; |
38 |
|
|
|
|
|
39 |
/* Returns 1 if no reply received */ |
/* Returns 1 if no reply received */ |
40 |
|
int FAST_FUNC arpping(uint32_t test_nip, |
41 |
int FAST_FUNC arpping(uint32_t test_ip, uint32_t from_ip, uint8_t *from_mac, const char *interface) |
const uint8_t *safe_mac, |
42 |
|
uint32_t from_ip, |
43 |
|
uint8_t *from_mac, |
44 |
|
const char *interface) |
45 |
{ |
{ |
46 |
int timeout_ms; |
int timeout_ms; |
47 |
struct pollfd pfd[1]; |
struct pollfd pfd[1]; |
57 |
} |
} |
58 |
|
|
59 |
if (setsockopt_broadcast(s) == -1) { |
if (setsockopt_broadcast(s) == -1) { |
60 |
bb_perror_msg("cannot enable bcast on raw socket"); |
bb_perror_msg("can't enable bcast on raw socket"); |
61 |
goto ret; |
goto ret; |
62 |
} |
} |
63 |
|
|
73 |
arp.operation = htons(ARPOP_REQUEST); /* ARP op code */ |
arp.operation = htons(ARPOP_REQUEST); /* ARP op code */ |
74 |
memcpy(arp.sHaddr, from_mac, 6); /* source hardware address */ |
memcpy(arp.sHaddr, from_mac, 6); /* source hardware address */ |
75 |
memcpy(arp.sInaddr, &from_ip, sizeof(from_ip)); /* source IP address */ |
memcpy(arp.sInaddr, &from_ip, sizeof(from_ip)); /* source IP address */ |
76 |
/* tHaddr is zero-fiiled */ /* target hardware address */ |
/* tHaddr is zero-filled */ /* target hardware address */ |
77 |
memcpy(arp.tInaddr, &test_ip, sizeof(test_ip)); /* target IP address */ |
memcpy(arp.tInaddr, &test_nip, sizeof(test_nip));/* target IP address */ |
78 |
|
|
79 |
memset(&addr, 0, sizeof(addr)); |
memset(&addr, 0, sizeof(addr)); |
80 |
safe_strncpy(addr.sa_data, interface, sizeof(addr.sa_data)); |
safe_strncpy(addr.sa_data, interface, sizeof(addr.sa_data)); |
88 |
timeout_ms = 2000; |
timeout_ms = 2000; |
89 |
do { |
do { |
90 |
int r; |
int r; |
91 |
unsigned prevTime = monotonic_us(); |
unsigned prevTime = monotonic_ms(); |
92 |
|
|
93 |
pfd[0].events = POLLIN; |
pfd[0].events = POLLIN; |
94 |
r = safe_poll(pfd, 1, timeout_ms); |
r = safe_poll(pfd, 1, timeout_ms); |
95 |
if (r < 0) |
if (r < 0) |
96 |
break; |
break; |
97 |
if (r) { |
if (r) { |
98 |
r = read(s, &arp, sizeof(arp)); |
r = safe_read(s, &arp, sizeof(arp)); |
99 |
if (r < 0) |
if (r < 0) |
100 |
break; |
break; |
101 |
|
|
102 |
|
//log3("sHaddr %02x:%02x:%02x:%02x:%02x:%02x", |
103 |
|
// arp.sHaddr[0], arp.sHaddr[1], arp.sHaddr[2], |
104 |
|
// arp.sHaddr[3], arp.sHaddr[4], arp.sHaddr[5]); |
105 |
|
|
106 |
if (r >= ARP_MSG_SIZE |
if (r >= ARP_MSG_SIZE |
107 |
&& arp.operation == htons(ARPOP_REPLY) |
&& arp.operation == htons(ARPOP_REPLY) |
108 |
/* don't check it: Linux doesn't return proper tHaddr (fixed in 2.6.24?) */ |
/* don't check it: Linux doesn't return proper tHaddr (fixed in 2.6.24?) */ |
109 |
/* && memcmp(arp.tHaddr, from_mac, 6) == 0 */ |
/* && memcmp(arp.tHaddr, from_mac, 6) == 0 */ |
110 |
&& *((uint32_t *) arp.sInaddr) == test_ip |
&& *((uint32_t *) arp.sInaddr) == test_nip |
111 |
) { |
) { |
112 |
rv = 0; |
/* if ARP source MAC matches safe_mac |
113 |
|
* (which is client's MAC), then it's not a conflict |
114 |
|
* (client simply already has this IP and replies to ARPs!) |
115 |
|
*/ |
116 |
|
if (!safe_mac || memcmp(safe_mac, arp.sHaddr, 6) != 0) |
117 |
|
rv = 0; |
118 |
|
//else log2("sHaddr == safe_mac"); |
119 |
break; |
break; |
120 |
} |
} |
121 |
} |
} |
122 |
timeout_ms -= ((unsigned)monotonic_us() - prevTime) / 1000; |
timeout_ms -= (unsigned)monotonic_ms() - prevTime; |
123 |
} while (timeout_ms > 0); |
} while (timeout_ms > 0); |
124 |
|
|
125 |
ret: |
ret: |
126 |
close(s); |
close(s); |
127 |
DEBUG("%srp reply received for this address", rv ? "No a" : "A"); |
log1("%srp reply received for this address", rv ? "No a" : "A"); |
128 |
return rv; |
return rv; |
129 |
} |
} |