aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--networking/udhcp/arpping.c21
-rw-r--r--networking/udhcp/common.h6
-rw-r--r--networking/udhcp/dhcpc.c7
-rw-r--r--networking/udhcp/dhcpd.h2
-rw-r--r--networking/udhcp/leases.c12
-rw-r--r--networking/udhcp/serverpacket.c51
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
44int FAST_FUNC arpping(uint32_t test_ip, uint32_t from_ip, uint8_t *from_mac, const char *interface) 44int 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
92int udhcp_raw_socket(int ifindex) FAST_FUNC; 92int udhcp_raw_socket(int ifindex) FAST_FUNC;
93int udhcp_listen_socket(/*uint32_t ip,*/ int port, const char *inf) FAST_FUNC; 93int 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 */
95int arpping(uint32_t test_ip, uint32_t from_ip, uint8_t *from_mac, const char *interface) FAST_FUNC; 95int 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(
99int lease_expired(struct dhcpOfferedAddr *lease) FAST_FUNC; 99int lease_expired(struct dhcpOfferedAddr *lease) FAST_FUNC;
100struct dhcpOfferedAddr *find_lease_by_chaddr(const uint8_t *chaddr) FAST_FUNC; 100struct dhcpOfferedAddr *find_lease_by_chaddr(const uint8_t *chaddr) FAST_FUNC;
101struct dhcpOfferedAddr *find_lease_by_yiaddr(uint32_t yiaddr) FAST_FUNC; 101struct dhcpOfferedAddr *find_lease_by_yiaddr(uint32_t yiaddr) FAST_FUNC;
102uint32_t find_free_or_expired_address(void) FAST_FUNC; 102uint32_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 */
121static int nobody_responds_to_arp(uint32_t addr) 121static 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. */
143uint32_t FAST_FUNC find_free_or_expired_address(void) 145uint32_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) {