diff options
-rw-r--r-- | networking/udhcp/arpping.c | 21 | ||||
-rw-r--r-- | networking/udhcp/common.h | 6 | ||||
-rw-r--r-- | networking/udhcp/dhcpc.c | 7 | ||||
-rw-r--r-- | networking/udhcp/dhcpd.h | 2 | ||||
-rw-r--r-- | networking/udhcp/leases.c | 12 | ||||
-rw-r--r-- | networking/udhcp/serverpacket.c | 51 |
6 files changed, 66 insertions, 33 deletions
diff --git a/networking/udhcp/arpping.c b/networking/udhcp/arpping.c index b10bff651..fa0989d0f 100644 --- a/networking/udhcp/arpping.c +++ b/networking/udhcp/arpping.c | |||
@@ -41,7 +41,11 @@ enum { | |||
41 | 41 | ||
42 | /* Returns 1 if no reply received */ | 42 | /* Returns 1 if no reply received */ |
43 | 43 | ||
44 | int FAST_FUNC arpping(uint32_t test_ip, uint32_t from_ip, uint8_t *from_mac, const char *interface) | 44 | int FAST_FUNC arpping(uint32_t test_ip, |
45 | const uint8_t *safe_mac, | ||
46 | uint32_t from_ip, | ||
47 | uint8_t *from_mac, | ||
48 | const char *interface) | ||
45 | { | 49 | { |
46 | int timeout_ms; | 50 | int timeout_ms; |
47 | struct pollfd pfd[1]; | 51 | struct pollfd pfd[1]; |
@@ -73,7 +77,7 @@ int FAST_FUNC arpping(uint32_t test_ip, uint32_t from_ip, uint8_t *from_mac, con | |||
73 | arp.operation = htons(ARPOP_REQUEST); /* ARP op code */ | 77 | arp.operation = htons(ARPOP_REQUEST); /* ARP op code */ |
74 | memcpy(arp.sHaddr, from_mac, 6); /* source hardware address */ | 78 | memcpy(arp.sHaddr, from_mac, 6); /* source hardware address */ |
75 | memcpy(arp.sInaddr, &from_ip, sizeof(from_ip)); /* source IP address */ | 79 | memcpy(arp.sInaddr, &from_ip, sizeof(from_ip)); /* source IP address */ |
76 | /* tHaddr is zero-fiiled */ /* target hardware address */ | 80 | /* tHaddr is zero-filled */ /* target hardware address */ |
77 | memcpy(arp.tInaddr, &test_ip, sizeof(test_ip)); /* target IP address */ | 81 | memcpy(arp.tInaddr, &test_ip, sizeof(test_ip)); /* target IP address */ |
78 | 82 | ||
79 | memset(&addr, 0, sizeof(addr)); | 83 | memset(&addr, 0, sizeof(addr)); |
@@ -98,13 +102,24 @@ int FAST_FUNC arpping(uint32_t test_ip, uint32_t from_ip, uint8_t *from_mac, con | |||
98 | r = read(s, &arp, sizeof(arp)); | 102 | r = read(s, &arp, sizeof(arp)); |
99 | if (r < 0) | 103 | if (r < 0) |
100 | break; | 104 | break; |
105 | |||
106 | //bb_error_msg("sHaddr %02x:%02x:%02x:%02x:%02x:%02x", | ||
107 | // arp.sHaddr[0], arp.sHaddr[1], arp.sHaddr[2], | ||
108 | // arp.sHaddr[3], arp.sHaddr[4], arp.sHaddr[5]); | ||
109 | |||
101 | if (r >= ARP_MSG_SIZE | 110 | if (r >= ARP_MSG_SIZE |
102 | && arp.operation == htons(ARPOP_REPLY) | 111 | && arp.operation == htons(ARPOP_REPLY) |
103 | /* don't check it: Linux doesn't return proper tHaddr (fixed in 2.6.24?) */ | 112 | /* don't check it: Linux doesn't return proper tHaddr (fixed in 2.6.24?) */ |
104 | /* && memcmp(arp.tHaddr, from_mac, 6) == 0 */ | 113 | /* && memcmp(arp.tHaddr, from_mac, 6) == 0 */ |
105 | && *((uint32_t *) arp.sInaddr) == test_ip | 114 | && *((uint32_t *) arp.sInaddr) == test_ip |
106 | ) { | 115 | ) { |
107 | rv = 0; | 116 | /* if ARP source MAC matches safe_mac |
117 | * (which is client's MAC), then it's not a conflict | ||
118 | * (client simply already has this IP and replies to ARPs!) | ||
119 | */ | ||
120 | if (!safe_mac || memcmp(safe_mac, arp.sHaddr, 6) != 0) | ||
121 | rv = 0; | ||
122 | //else bb_error_msg("sHaddr == safe_mac"); | ||
108 | break; | 123 | break; |
109 | } | 124 | } |
110 | } | 125 | } |
diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h index 5a258c064..ca96847a7 100644 --- a/networking/udhcp/common.h +++ b/networking/udhcp/common.h | |||
@@ -92,7 +92,11 @@ int udhcp_read_interface(const char *interface, int *ifindex, uint32_t *addr, ui | |||
92 | int udhcp_raw_socket(int ifindex) FAST_FUNC; | 92 | int udhcp_raw_socket(int ifindex) FAST_FUNC; |
93 | int udhcp_listen_socket(/*uint32_t ip,*/ int port, const char *inf) FAST_FUNC; | 93 | int udhcp_listen_socket(/*uint32_t ip,*/ int port, const char *inf) FAST_FUNC; |
94 | /* Returns 1 if no reply received */ | 94 | /* Returns 1 if no reply received */ |
95 | int arpping(uint32_t test_ip, uint32_t from_ip, uint8_t *from_mac, const char *interface) FAST_FUNC; | 95 | int arpping(uint32_t test_ip, |
96 | const uint8_t *safe_mac, | ||
97 | uint32_t from_ip, | ||
98 | uint8_t *from_mac, | ||
99 | const char *interface) FAST_FUNC; | ||
96 | 100 | ||
97 | #if ENABLE_UDHCP_DEBUG | 101 | #if ENABLE_UDHCP_DEBUG |
98 | # define DEBUG(str, args...) bb_info_msg("### " str, ## args) | 102 | # define DEBUG(str, args...) bb_info_msg("### " str, ## args) |
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index 2dd3cd077..ab34b0472 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c | |||
@@ -553,9 +553,10 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
553 | * the client MUST send a DHCPDECLINE message to the server and restarts | 553 | * the client MUST send a DHCPDECLINE message to the server and restarts |
554 | * the configuration process..." */ | 554 | * the configuration process..." */ |
555 | if (!arpping(packet.yiaddr, | 555 | if (!arpping(packet.yiaddr, |
556 | (uint32_t) 0, | 556 | NULL, |
557 | client_config.arp, | 557 | (uint32_t) 0, |
558 | client_config.interface) | 558 | client_config.arp, |
559 | client_config.interface) | ||
559 | ) { | 560 | ) { |
560 | bb_info_msg("offered address is in use " | 561 | bb_info_msg("offered address is in use " |
561 | "(got ARP reply), declining"); | 562 | "(got ARP reply), declining"); |
diff --git a/networking/udhcp/dhcpd.h b/networking/udhcp/dhcpd.h index 9667c61e8..4b5fcc00f 100644 --- a/networking/udhcp/dhcpd.h +++ b/networking/udhcp/dhcpd.h | |||
@@ -99,7 +99,7 @@ struct dhcpOfferedAddr *add_lease( | |||
99 | int lease_expired(struct dhcpOfferedAddr *lease) FAST_FUNC; | 99 | int lease_expired(struct dhcpOfferedAddr *lease) FAST_FUNC; |
100 | struct dhcpOfferedAddr *find_lease_by_chaddr(const uint8_t *chaddr) FAST_FUNC; | 100 | struct dhcpOfferedAddr *find_lease_by_chaddr(const uint8_t *chaddr) FAST_FUNC; |
101 | struct dhcpOfferedAddr *find_lease_by_yiaddr(uint32_t yiaddr) FAST_FUNC; | 101 | struct dhcpOfferedAddr *find_lease_by_yiaddr(uint32_t yiaddr) FAST_FUNC; |
102 | uint32_t find_free_or_expired_address(void) FAST_FUNC; | 102 | uint32_t find_free_or_expired_address(const uint8_t *chaddr) FAST_FUNC; |
103 | 103 | ||
104 | 104 | ||
105 | /*** static_leases.h ***/ | 105 | /*** static_leases.h ***/ |
diff --git a/networking/udhcp/leases.c b/networking/udhcp/leases.c index e17fb9e3f..b2cdd1942 100644 --- a/networking/udhcp/leases.c +++ b/networking/udhcp/leases.c | |||
@@ -118,7 +118,7 @@ struct dhcpOfferedAddr* FAST_FUNC find_lease_by_yiaddr(uint32_t yiaddr) | |||
118 | 118 | ||
119 | 119 | ||
120 | /* check is an IP is taken, if it is, add it to the lease table */ | 120 | /* check is an IP is taken, if it is, add it to the lease table */ |
121 | static int nobody_responds_to_arp(uint32_t addr) | 121 | static int nobody_responds_to_arp(uint32_t addr, const uint8_t *safe_mac) |
122 | { | 122 | { |
123 | /* 16 zero bytes */ | 123 | /* 16 zero bytes */ |
124 | static const uint8_t blank_chaddr[16] = { 0 }; | 124 | static const uint8_t blank_chaddr[16] = { 0 }; |
@@ -127,7 +127,9 @@ static int nobody_responds_to_arp(uint32_t addr) | |||
127 | struct in_addr temp; | 127 | struct in_addr temp; |
128 | int r; | 128 | int r; |
129 | 129 | ||
130 | r = arpping(addr, server_config.server, server_config.arp, server_config.interface); | 130 | r = arpping(addr, safe_mac, |
131 | server_config.server, server_config.arp, | ||
132 | server_config.interface); | ||
131 | if (r) | 133 | if (r) |
132 | return r; | 134 | return r; |
133 | 135 | ||
@@ -140,7 +142,7 @@ static int nobody_responds_to_arp(uint32_t addr) | |||
140 | 142 | ||
141 | 143 | ||
142 | /* Find a new usable (we think) address. */ | 144 | /* Find a new usable (we think) address. */ |
143 | uint32_t FAST_FUNC find_free_or_expired_address(void) | 145 | uint32_t FAST_FUNC find_free_or_expired_address(const uint8_t *chaddr) |
144 | { | 146 | { |
145 | uint32_t addr; | 147 | uint32_t addr; |
146 | struct dhcpOfferedAddr *oldest_lease = NULL; | 148 | struct dhcpOfferedAddr *oldest_lease = NULL; |
@@ -163,7 +165,7 @@ uint32_t FAST_FUNC find_free_or_expired_address(void) | |||
163 | 165 | ||
164 | lease = find_lease_by_yiaddr(net_addr); | 166 | lease = find_lease_by_yiaddr(net_addr); |
165 | if (!lease) { | 167 | if (!lease) { |
166 | if (nobody_responds_to_arp(net_addr)) | 168 | if (nobody_responds_to_arp(net_addr, chaddr)) |
167 | return net_addr; | 169 | return net_addr; |
168 | } else { | 170 | } else { |
169 | if (!oldest_lease || lease->expires < oldest_lease->expires) | 171 | if (!oldest_lease || lease->expires < oldest_lease->expires) |
@@ -172,7 +174,7 @@ uint32_t FAST_FUNC find_free_or_expired_address(void) | |||
172 | } | 174 | } |
173 | 175 | ||
174 | if (oldest_lease && lease_expired(oldest_lease) | 176 | if (oldest_lease && lease_expired(oldest_lease) |
175 | && nobody_responds_to_arp(oldest_lease->yiaddr) | 177 | && nobody_responds_to_arp(oldest_lease->yiaddr, chaddr) |
176 | ) { | 178 | ) { |
177 | return oldest_lease->yiaddr; | 179 | return oldest_lease->yiaddr; |
178 | } | 180 | } |
diff --git a/networking/udhcp/serverpacket.c b/networking/udhcp/serverpacket.c index 8b0f1856b..157d157ba 100644 --- a/networking/udhcp/serverpacket.c +++ b/networking/udhcp/serverpacket.c | |||
@@ -31,7 +31,8 @@ static int send_packet_to_relay(struct dhcpMessage *payload) | |||
31 | { | 31 | { |
32 | DEBUG("Forwarding packet to relay"); | 32 | DEBUG("Forwarding packet to relay"); |
33 | 33 | ||
34 | return udhcp_send_kernel_packet(payload, server_config.server, SERVER_PORT, | 34 | return udhcp_send_kernel_packet(payload, |
35 | server_config.server, SERVER_PORT, | ||
35 | payload->giaddr, SERVER_PORT); | 36 | payload->giaddr, SERVER_PORT); |
36 | } | 37 | } |
37 | 38 | ||
@@ -42,23 +43,31 @@ static int send_packet_to_client(struct dhcpMessage *payload, int force_broadcas | |||
42 | const uint8_t *chaddr; | 43 | const uint8_t *chaddr; |
43 | uint32_t ciaddr; | 44 | uint32_t ciaddr; |
44 | 45 | ||
45 | if (force_broadcast) { | 46 | // Was: |
46 | DEBUG("broadcasting packet to client (NAK)"); | 47 | //if (force_broadcast) { /* broadcast */ } |
48 | //else if (payload->ciaddr) { /* unicast to payload->ciaddr */ } | ||
49 | //else if (payload->flags & htons(BROADCAST_FLAG)) { /* broadcast */ } | ||
50 | //else { /* unicast to payload->yiaddr */ } | ||
51 | // But this is wrong: yiaddr is _our_ idea what client's IP is | ||
52 | // (for example, from lease file). Client may not know that, | ||
53 | // and may not have UDP socket listening on that IP! | ||
54 | // We should never unicast to payload->yiaddr! | ||
55 | // payload->ciaddr, OTOH, comes from client's request packet, | ||
56 | // and can be used. | ||
57 | |||
58 | if (force_broadcast | ||
59 | || (payload->flags & htons(BROADCAST_FLAG)) | ||
60 | || !payload->ciaddr | ||
61 | ) { | ||
62 | DEBUG("broadcasting packet to client"); | ||
47 | ciaddr = INADDR_BROADCAST; | 63 | ciaddr = INADDR_BROADCAST; |
48 | chaddr = MAC_BCAST_ADDR; | 64 | chaddr = MAC_BCAST_ADDR; |
49 | } else if (payload->ciaddr) { | 65 | } else { |
50 | DEBUG("unicasting packet to client ciaddr"); | 66 | DEBUG("unicasting packet to client ciaddr"); |
51 | ciaddr = payload->ciaddr; | 67 | ciaddr = payload->ciaddr; |
52 | chaddr = payload->chaddr; | 68 | chaddr = payload->chaddr; |
53 | } else if (payload->flags & htons(BROADCAST_FLAG)) { | ||
54 | DEBUG("broadcasting packet to client (requested)"); | ||
55 | ciaddr = INADDR_BROADCAST; | ||
56 | chaddr = MAC_BCAST_ADDR; | ||
57 | } else { | ||
58 | DEBUG("unicasting packet to client yiaddr"); | ||
59 | ciaddr = payload->yiaddr; | ||
60 | chaddr = payload->chaddr; | ||
61 | } | 69 | } |
70 | |||
62 | return udhcp_send_raw_packet(payload, | 71 | return udhcp_send_raw_packet(payload, |
63 | /*src*/ server_config.server, SERVER_PORT, | 72 | /*src*/ server_config.server, SERVER_PORT, |
64 | /*dst*/ ciaddr, CLIENT_PORT, chaddr, | 73 | /*dst*/ ciaddr, CLIENT_PORT, chaddr, |
@@ -118,17 +127,18 @@ int FAST_FUNC send_offer(struct dhcpMessage *oldpacket) | |||
118 | struct dhcpOfferedAddr *lease; | 127 | struct dhcpOfferedAddr *lease; |
119 | 128 | ||
120 | lease = find_lease_by_chaddr(oldpacket->chaddr); | 129 | lease = find_lease_by_chaddr(oldpacket->chaddr); |
121 | /* the client is in our lease/offered table */ | 130 | /* The client is in our lease/offered table */ |
122 | if (lease) { | 131 | if (lease) { |
123 | signed_leasetime_t tmp = lease->expires - time(NULL); | 132 | signed_leasetime_t tmp = lease->expires - time(NULL); |
124 | if (tmp >= 0) | 133 | if (tmp >= 0) |
125 | lease_time_aligned = tmp; | 134 | lease_time_aligned = tmp; |
126 | packet.yiaddr = lease->yiaddr; | 135 | packet.yiaddr = lease->yiaddr; |
127 | /* Or the client has requested an ip */ | 136 | } |
128 | } else if ((req = get_option(oldpacket, DHCP_REQUESTED_IP)) != NULL | 137 | /* Or the client has requested an IP */ |
129 | /* Don't look here (ugly hackish thing to do) */ | 138 | else if ((req = get_option(oldpacket, DHCP_REQUESTED_IP)) != NULL |
139 | /* (read IP) */ | ||
130 | && (move_from_unaligned32(req_align, req), 1) | 140 | && (move_from_unaligned32(req_align, req), 1) |
131 | /* and the ip is in the lease range */ | 141 | /* and the IP is in the lease range */ |
132 | && ntohl(req_align) >= server_config.start_ip | 142 | && ntohl(req_align) >= server_config.start_ip |
133 | && ntohl(req_align) <= server_config.end_ip | 143 | && ntohl(req_align) <= server_config.end_ip |
134 | /* and is not already taken/offered */ | 144 | /* and is not already taken/offered */ |
@@ -137,9 +147,10 @@ int FAST_FUNC send_offer(struct dhcpMessage *oldpacket) | |||
137 | || lease_expired(lease)) | 147 | || lease_expired(lease)) |
138 | ) { | 148 | ) { |
139 | packet.yiaddr = req_align; | 149 | packet.yiaddr = req_align; |
140 | /* otherwise, find a free IP */ | 150 | } |
141 | } else { | 151 | /* Otherwise, find a free IP */ |
142 | packet.yiaddr = find_free_or_expired_address(); | 152 | else { |
153 | packet.yiaddr = find_free_or_expired_address(oldpacket->chaddr); | ||
143 | } | 154 | } |
144 | 155 | ||
145 | if (!packet.yiaddr) { | 156 | if (!packet.yiaddr) { |