aboutsummaryrefslogtreecommitdiff
path: root/networking/udhcp/dhcpc.c
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2010-03-22 13:43:12 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2010-03-22 13:43:12 +0100
commit501e35c47441722c69c62bd52841a9a6fd64932c (patch)
treeb44be8066c38222867175586ef5084a4fc662223 /networking/udhcp/dhcpc.c
parent6b24d5354bc166f6962b6b42de4ab9c7e6470225 (diff)
downloadbusybox-w32-501e35c47441722c69c62bd52841a9a6fd64932c.tar.gz
busybox-w32-501e35c47441722c69c62bd52841a9a6fd64932c.tar.bz2
busybox-w32-501e35c47441722c69c62bd52841a9a6fd64932c.zip
udhcp: merge clientpacket.c into dhcpc.c
function old new delta udhcpc_main 2569 2855 +286 perform_release 122 124 +2 client_background 31 32 +1 init_packet 156 88 -68 send_decline 114 - -114 send_discover 121 - -121 send_select 130 - -130 ------------------------------------------------------------------------------ (add/remove: 0/4 grow/shrink: 3/1 up/down: 289/-433) Total: -144 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'networking/udhcp/dhcpc.c')
-rw-r--r--networking/udhcp/dhcpc.c245
1 files changed, 239 insertions, 6 deletions
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index a03e25ca4..d51d8b82f 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -63,6 +63,245 @@ static smallint state;
63/* struct client_config_t client_config is in bb_common_bufsiz1 */ 63/* struct client_config_t client_config is in bb_common_bufsiz1 */
64 64
65 65
66/* Create a random xid */
67static uint32_t random_xid(void)
68{
69 static smallint initialized;
70
71 if (!initialized) {
72 srand(monotonic_us());
73 initialized = 1;
74 }
75 return rand();
76}
77
78/* Initialize the packet with the proper defaults */
79static void init_packet(struct dhcp_packet *packet, char type)
80{
81 udhcp_init_header(packet, type);
82 memcpy(packet->chaddr, client_config.client_mac, 6);
83 if (client_config.clientid)
84 add_option_string(packet->options, client_config.clientid);
85 if (client_config.hostname)
86 add_option_string(packet->options, client_config.hostname);
87 if (client_config.fqdn)
88 add_option_string(packet->options, client_config.fqdn);
89 if (type != DHCPDECLINE
90 && type != DHCPRELEASE
91 && client_config.vendorclass
92 ) {
93 add_option_string(packet->options, client_config.vendorclass);
94 }
95}
96
97/* Add a parameter request list for stubborn DHCP servers. Pull the data
98 * from the struct in options.c. Don't do bounds checking here because it
99 * goes towards the head of the packet. */
100static void add_param_req_option(struct dhcp_packet *packet)
101{
102 uint8_t c;
103 int end = end_option(packet->options);
104 int i, len = 0;
105
106 for (i = 0; (c = dhcp_options[i].code) != 0; i++) {
107 if (( (dhcp_options[i].flags & OPTION_REQ)
108 && !client_config.no_default_options
109 )
110 || (client_config.opt_mask[c >> 3] & (1 << (c & 7)))
111 ) {
112 packet->options[end + OPT_DATA + len] = c;
113 len++;
114 }
115 }
116 if (len) {
117 packet->options[end + OPT_CODE] = DHCP_PARAM_REQ;
118 packet->options[end + OPT_LEN] = len;
119 packet->options[end + OPT_DATA + len] = DHCP_END;
120 }
121}
122
123/* RFC 2131
124 * 4.4.4 Use of broadcast and unicast
125 *
126 * The DHCP client broadcasts DHCPDISCOVER, DHCPREQUEST and DHCPINFORM
127 * messages, unless the client knows the address of a DHCP server.
128 * The client unicasts DHCPRELEASE messages to the server. Because
129 * the client is declining the use of the IP address supplied by the server,
130 * the client broadcasts DHCPDECLINE messages.
131 *
132 * When the DHCP client knows the address of a DHCP server, in either
133 * INIT or REBOOTING state, the client may use that address
134 * in the DHCPDISCOVER or DHCPREQUEST rather than the IP broadcast address.
135 * The client may also use unicast to send DHCPINFORM messages
136 * to a known DHCP server. If the client receives no response to DHCP
137 * messages sent to the IP address of a known DHCP server, the DHCP
138 * client reverts to using the IP broadcast address.
139 */
140
141static int raw_bcast_from_client_config_ifindex(struct dhcp_packet *packet)
142{
143 return udhcp_send_raw_packet(packet,
144 /*src*/ INADDR_ANY, CLIENT_PORT,
145 /*dst*/ INADDR_BROADCAST, SERVER_PORT, MAC_BCAST_ADDR,
146 client_config.ifindex);
147}
148
149/* Broadcast a DHCP discover packet to the network, with an optionally requested IP */
150static int send_discover(uint32_t xid, uint32_t requested)
151{
152 struct dhcp_packet packet;
153
154 init_packet(&packet, DHCPDISCOVER);
155 packet.xid = xid;
156 if (requested)
157 add_simple_option(packet.options, DHCP_REQUESTED_IP, requested);
158 /* Explicitly saying that we want RFC-compliant packets helps
159 * some buggy DHCP servers to NOT send bigger packets */
160 add_simple_option(packet.options, DHCP_MAX_SIZE, htons(576));
161 add_param_req_option(&packet);
162
163 bb_info_msg("Sending discover...");
164 return raw_bcast_from_client_config_ifindex(&packet);
165}
166
167/* Broadcast a DHCP request message */
168/* RFC 2131 3.1 paragraph 3:
169 * "The client _broadcasts_ a DHCPREQUEST message..."
170 */
171static int send_select(uint32_t xid, uint32_t server, uint32_t requested)
172{
173 struct dhcp_packet packet;
174 struct in_addr addr;
175
176 init_packet(&packet, DHCPREQUEST);
177 packet.xid = xid;
178 add_simple_option(packet.options, DHCP_REQUESTED_IP, requested);
179 add_simple_option(packet.options, DHCP_SERVER_ID, server);
180 add_param_req_option(&packet);
181
182 addr.s_addr = requested;
183 bb_info_msg("Sending select for %s...", inet_ntoa(addr));
184 return raw_bcast_from_client_config_ifindex(&packet);
185}
186
187/* Unicast or broadcast a DHCP renew message */
188static int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr)
189{
190 struct dhcp_packet packet;
191
192 init_packet(&packet, DHCPREQUEST);
193 packet.xid = xid;
194 packet.ciaddr = ciaddr;
195 add_param_req_option(&packet);
196
197 bb_info_msg("Sending renew...");
198 if (server)
199 return udhcp_send_kernel_packet(&packet,
200 ciaddr, CLIENT_PORT,
201 server, SERVER_PORT);
202 return raw_bcast_from_client_config_ifindex(&packet);
203}
204
205#if ENABLE_FEATURE_UDHCPC_ARPING
206/* Broadcast a DHCP decline message */
207static int send_decline(uint32_t xid, uint32_t server, uint32_t requested)
208{
209 struct dhcp_packet packet;
210
211 init_packet(&packet, DHCPDECLINE);
212 packet.xid = xid;
213 add_simple_option(packet.options, DHCP_REQUESTED_IP, requested);
214 add_simple_option(packet.options, DHCP_SERVER_ID, server);
215
216 bb_info_msg("Sending decline...");
217 return raw_bcast_from_client_config_ifindex(&packet);
218}
219#endif
220
221/* Unicast a DHCP release message */
222static int send_release(uint32_t server, uint32_t ciaddr)
223{
224 struct dhcp_packet packet;
225
226 init_packet(&packet, DHCPRELEASE);
227 packet.xid = random_xid();
228 packet.ciaddr = ciaddr;
229
230 add_simple_option(packet.options, DHCP_SERVER_ID, server);
231
232 bb_info_msg("Sending release...");
233 return udhcp_send_kernel_packet(&packet, ciaddr, CLIENT_PORT, server, SERVER_PORT);
234}
235
236/* Returns -1 on errors that are fatal for the socket, -2 for those that aren't */
237static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd)
238{
239 int bytes;
240 struct ip_udp_dhcp_packet packet;
241 uint16_t check;
242
243 memset(&packet, 0, sizeof(packet));
244 bytes = safe_read(fd, &packet, sizeof(packet));
245 if (bytes < 0) {
246 log1("Packet read error, ignoring");
247 /* NB: possible down interface, etc. Caller should pause. */
248 return bytes; /* returns -1 */
249 }
250
251 if (bytes < (int) (sizeof(packet.ip) + sizeof(packet.udp))) {
252 log1("Packet is too short, ignoring");
253 return -2;
254 }
255
256 if (bytes < ntohs(packet.ip.tot_len)) {
257 /* packet is bigger than sizeof(packet), we did partial read */
258 log1("Oversized packet, ignoring");
259 return -2;
260 }
261
262 /* ignore any extra garbage bytes */
263 bytes = ntohs(packet.ip.tot_len);
264
265 /* make sure its the right packet for us, and that it passes sanity checks */
266 if (packet.ip.protocol != IPPROTO_UDP || packet.ip.version != IPVERSION
267 || packet.ip.ihl != (sizeof(packet.ip) >> 2)
268 || packet.udp.dest != htons(CLIENT_PORT)
269 /* || bytes > (int) sizeof(packet) - can't happen */
270 || ntohs(packet.udp.len) != (uint16_t)(bytes - sizeof(packet.ip))
271 ) {
272 log1("Unrelated/bogus packet, ignoring");
273 return -2;
274 }
275
276 /* verify IP checksum */
277 check = packet.ip.check;
278 packet.ip.check = 0;
279 if (check != udhcp_checksum(&packet.ip, sizeof(packet.ip))) {
280 log1("Bad IP header checksum, ignoring");
281 return -2;
282 }
283
284 /* verify UDP checksum. IP header has to be modified for this */
285 memset(&packet.ip, 0, offsetof(struct iphdr, protocol));
286 /* ip.xx fields which are not memset: protocol, check, saddr, daddr */
287 packet.ip.tot_len = packet.udp.len; /* yes, this is needed */
288 check = packet.udp.check;
289 packet.udp.check = 0;
290 if (check && check != udhcp_checksum(&packet, bytes)) {
291 log1("Packet with bad UDP checksum received, ignoring");
292 return -2;
293 }
294
295 memcpy(dhcp_pkt, &packet.data, bytes - (sizeof(packet.ip) + sizeof(packet.udp)));
296
297 if (dhcp_pkt->cookie != htonl(DHCP_MAGIC)) {
298 bb_info_msg("Packet with bad magic, ignoring");
299 return -2;
300 }
301 log1("Got valid DHCP packet");
302 udhcp_dump_packet(dhcp_pkt);
303 return bytes - (sizeof(packet.ip) + sizeof(packet.udp));
304}
66 305
67static int udhcp_raw_socket(int ifindex) 306static int udhcp_raw_socket(int ifindex)
68{ 307{
@@ -135,7 +374,6 @@ static int udhcp_raw_socket(int ifindex)
135 return fd; 374 return fd;
136} 375}
137 376
138
139/* just a little helper */ 377/* just a little helper */
140static void change_listen_mode(int new_mode) 378static void change_listen_mode(int new_mode)
141{ 379{
@@ -157,7 +395,6 @@ static void change_listen_mode(int new_mode)
157 /* else LISTEN_NONE: sockfd stays closed */ 395 /* else LISTEN_NONE: sockfd stays closed */
158} 396}
159 397
160
161/* perform a renew */ 398/* perform a renew */
162static void perform_renew(void) 399static void perform_renew(void)
163{ 400{
@@ -181,7 +418,6 @@ static void perform_renew(void)
181 } 418 }
182} 419}
183 420
184
185/* perform a release */ 421/* perform a release */
186static void perform_release(uint32_t requested_ip, uint32_t server_addr) 422static void perform_release(uint32_t requested_ip, uint32_t server_addr)
187{ 423{
@@ -204,7 +440,6 @@ static void perform_release(uint32_t requested_ip, uint32_t server_addr)
204 state = RELEASED; 440 state = RELEASED;
205} 441}
206 442
207
208#if BB_MMU 443#if BB_MMU
209static void client_background(void) 444static void client_background(void)
210{ 445{
@@ -215,7 +450,6 @@ static void client_background(void)
215} 450}
216#endif 451#endif
217 452
218
219static uint8_t* alloc_dhcp_option(int code, const char *str, int extra) 453static uint8_t* alloc_dhcp_option(int code, const char *str, int extra)
220{ 454{
221 uint8_t *storage; 455 uint8_t *storage;
@@ -227,7 +461,6 @@ static uint8_t* alloc_dhcp_option(int code, const char *str, int extra)
227 return storage; 461 return storage;
228} 462}
229 463
230
231int udhcpc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 464int udhcpc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
232int udhcpc_main(int argc UNUSED_PARAM, char **argv) 465int udhcpc_main(int argc UNUSED_PARAM, char **argv)
233{ 466{