Magellan Linux

Diff of /trunk/mkinitrd-magellan/busybox/networking/udhcp/dhcpc.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 983 by niro, Fri Apr 24 18:33:46 2009 UTC revision 984 by niro, Sun May 30 11:32:42 2010 UTC
# Line 7  Line 7 
7   *   *
8   * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.   * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
9   */   */
   
10  #include <syslog.h>  #include <syslog.h>
   
11  /* Override ENABLE_FEATURE_PIDFILE - ifupdown needs our pidfile to always exist */  /* Override ENABLE_FEATURE_PIDFILE - ifupdown needs our pidfile to always exist */
12  #define WANT_PIDFILE 1  #define WANT_PIDFILE 1
13  #include "common.h"  #include "common.h"
# Line 20  Line 18 
18    
19  static int sockfd = -1;  static int sockfd = -1;
20    
21  #define LISTEN_NONE 0  #define LISTEN_NONE   0
22  #define LISTEN_KERNEL 1  #define LISTEN_KERNEL 1
23  #define LISTEN_RAW 2  #define LISTEN_RAW    2
24  static smallint listen_mode;  static smallint listen_mode;
25    
26    /* initial state: (re)start DHCP negotiation */
27  #define INIT_SELECTING  0  #define INIT_SELECTING  0
28    /* discover was sent, DHCPOFFER reply received */
29  #define REQUESTING      1  #define REQUESTING      1
30    /* select/renew was sent, DHCPACK reply received */
31  #define BOUND           2  #define BOUND           2
32    /* half of lease passed, want to renew it by sending unicast renew requests */
33  #define RENEWING        3  #define RENEWING        3
34    /* renew requests were not answered, lease is almost over, send broadcast renew */
35  #define REBINDING       4  #define REBINDING       4
36  #define INIT_REBOOT     5  /* manually requested renew (SIGUSR1) */
37  #define RENEW_REQUESTED 6  #define RENEW_REQUESTED 5
38  #define RELEASED        7  /* release, possibly manually requested (SIGUSR2) */
39    #define RELEASED        6
40  static smallint state;  static smallint state;
41    
42  /* struct client_config_t client_config is in bb_common_bufsiz1 */  /* struct client_config_t client_config is in bb_common_bufsiz1 */
# Line 41  static smallint state; Line 45  static smallint state;
45  /* just a little helper */  /* just a little helper */
46  static void change_listen_mode(int new_mode)  static void change_listen_mode(int new_mode)
47  {  {
48   DEBUG("entering %s listen mode",   log1("Entering listen mode: %s",
49   new_mode ? (new_mode == 1 ? "kernel" : "raw") : "none");   new_mode != LISTEN_NONE
50     ? (new_mode == LISTEN_KERNEL ? "kernel" : "raw")
51     : "none"
52     );
53    
54     listen_mode = new_mode;
55   if (sockfd >= 0) {   if (sockfd >= 0) {
56   close(sockfd);   close(sockfd);
57   sockfd = -1;   sockfd = -1;
58   }   }
59   listen_mode = new_mode;   if (new_mode == LISTEN_KERNEL)
60     sockfd = udhcp_listen_socket(/*INADDR_ANY,*/ CLIENT_PORT, client_config.interface);
61     else if (new_mode != LISTEN_NONE)
62     sockfd = udhcp_raw_socket(client_config.ifindex);
63     /* else LISTEN_NONE: sockfd stay closed */
64  }  }
65    
66    
# Line 127  int udhcpc_main(int argc UNUSED_PARAM, c Line 140  int udhcpc_main(int argc UNUSED_PARAM, c
140  {  {
141   uint8_t *temp, *message;   uint8_t *temp, *message;
142   char *str_c, *str_V, *str_h, *str_F, *str_r;   char *str_c, *str_V, *str_h, *str_F, *str_r;
143   USE_FEATURE_UDHCP_PORT(char *str_P;)   IF_FEATURE_UDHCP_PORT(char *str_P;)
144   llist_t *list_O = NULL;   llist_t *list_O = NULL;
145   int tryagain_timeout = 20;   int tryagain_timeout = 20;
146   int discover_timeout = 3;   int discover_timeout = 3;
# Line 143  int udhcpc_main(int argc UNUSED_PARAM, c Line 156  int udhcpc_main(int argc UNUSED_PARAM, c
156   int max_fd;   int max_fd;
157   int retval;   int retval;
158   struct timeval tv;   struct timeval tv;
159   struct dhcpMessage packet;   struct dhcp_packet packet;
160   fd_set rfds;   fd_set rfds;
161    
162  #if ENABLE_GETOPT_LONG  #if ENABLE_LONG_OPTS
163   static const char udhcpc_longopts[] ALIGN1 =   static const char udhcpc_longopts[] ALIGN1 =
164   "clientid\0"       Required_argument "c"   "clientid\0"       Required_argument "c"
165   "clientid-none\0"  No_argument       "C"   "clientid-none\0"  No_argument       "C"
# Line 169  int udhcpc_main(int argc UNUSED_PARAM, c Line 182  int udhcpc_main(int argc UNUSED_PARAM, c
182   "no-default-options\0" No_argument   "o"   "no-default-options\0" No_argument   "o"
183   "foreground\0"     No_argument       "f"   "foreground\0"     No_argument       "f"
184   "background\0"     No_argument       "b"   "background\0"     No_argument       "b"
185   USE_FEATURE_UDHCPC_ARPING("arping\0" No_argument       "a")   IF_FEATURE_UDHCPC_ARPING("arping\0" No_argument       "a")
186   USE_FEATURE_UDHCP_PORT("client-port\0" Required_argument "P")   IF_FEATURE_UDHCP_PORT("client-port\0" Required_argument "P")
187   ;   ;
188  #endif  #endif
189   enum {   enum {
# Line 189  int udhcpc_main(int argc UNUSED_PARAM, c Line 202  int udhcpc_main(int argc UNUSED_PARAM, c
202   OPT_s = 1 << 12,   OPT_s = 1 << 12,
203   OPT_T = 1 << 13,   OPT_T = 1 << 13,
204   OPT_t = 1 << 14,   OPT_t = 1 << 14,
205   OPT_v = 1 << 15,   OPT_S = 1 << 15,
206   OPT_S = 1 << 16,   OPT_A = 1 << 16,
207   OPT_A = 1 << 17,   OPT_O = 1 << 17,
208   OPT_O = 1 << 18,   OPT_o = 1 << 18,
209   OPT_o = 1 << 19,   OPT_f = 1 << 19,
  OPT_f = 1 << 20,  
210  /* The rest has variable bit positions, need to be clever */  /* The rest has variable bit positions, need to be clever */
211   OPTBIT_f = 20,   OPTBIT_f = 19,
212   USE_FOR_MMU(              OPTBIT_b,)   USE_FOR_MMU(             OPTBIT_b,)
213   USE_FEATURE_UDHCPC_ARPING(OPTBIT_a,)   IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,)
214   USE_FEATURE_UDHCP_PORT(   OPTBIT_P,)   IF_FEATURE_UDHCP_PORT(   OPTBIT_P,)
215   USE_FOR_MMU(              OPT_b = 1 << OPTBIT_b,)   USE_FOR_MMU(             OPT_b = 1 << OPTBIT_b,)
216   USE_FEATURE_UDHCPC_ARPING(OPT_a = 1 << OPTBIT_a,)   IF_FEATURE_UDHCPC_ARPING(OPT_a = 1 << OPTBIT_a,)
217   USE_FEATURE_UDHCP_PORT(   OPT_P = 1 << OPTBIT_P,)   IF_FEATURE_UDHCP_PORT(   OPT_P = 1 << OPTBIT_P,)
218   };   };
219    
220   /* Default options. */   /* Default options. */
221   USE_FEATURE_UDHCP_PORT(SERVER_PORT = 67;)   IF_FEATURE_UDHCP_PORT(SERVER_PORT = 67;)
222   USE_FEATURE_UDHCP_PORT(CLIENT_PORT = 68;)   IF_FEATURE_UDHCP_PORT(CLIENT_PORT = 68;)
223   client_config.interface = "eth0";   client_config.interface = "eth0";
224   client_config.script = DEFAULT_SCRIPT;   client_config.script = DEFAULT_SCRIPT;
225    
226   /* Parse command line */   /* Parse command line */
227   /* Cc: mutually exclusive; O: list; -T,-t,-A take numeric param */   /* Cc: mutually exclusive; O: list; -T,-t,-A take numeric param */
228   opt_complementary = "c--C:C--c:O::T+:t+:A+";   opt_complementary = "c--C:C--c:O::T+:t+:A+"
229   USE_GETOPT_LONG(applet_long_options = udhcpc_longopts;)  #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
230   opt = getopt32(argv, "c:CV:H:h:F:i:np:qRr:s:T:t:vSA:O:of"   ":vv"
231    #endif
232     ;
233     IF_LONG_OPTS(applet_long_options = udhcpc_longopts;)
234     opt = getopt32(argv, "c:CV:H:h:F:i:np:qRr:s:T:t:SA:O:of"
235   USE_FOR_MMU("b")   USE_FOR_MMU("b")
236   USE_FEATURE_UDHCPC_ARPING("a")   IF_FEATURE_UDHCPC_ARPING("a")
237   USE_FEATURE_UDHCP_PORT("P:")   IF_FEATURE_UDHCP_PORT("P:")
238     "v"
239   , &str_c, &str_V, &str_h, &str_h, &str_F   , &str_c, &str_V, &str_h, &str_h, &str_F
240   , &client_config.interface, &client_config.pidfile, &str_r /* i,p */   , &client_config.interface, &client_config.pidfile, &str_r /* i,p */
241   , &client_config.script /* s */   , &client_config.script /* s */
242   , &discover_timeout, &discover_retries, &tryagain_timeout /* T,t,A */   , &discover_timeout, &discover_retries, &tryagain_timeout /* T,t,A */
243   , &list_O   , &list_O
244   USE_FEATURE_UDHCP_PORT(, &str_P)   IF_FEATURE_UDHCP_PORT(, &str_P)
245    #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
246     , &dhcp_verbose
247    #endif
248   );   );
249   if (opt & OPT_c)   if (opt & OPT_c)
250   client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, str_c, 0);   client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, str_c, 0);
# Line 246  int udhcpc_main(int argc UNUSED_PARAM, c Line 266  int udhcpc_main(int argc UNUSED_PARAM, c
266   }   }
267   if (opt & OPT_r)   if (opt & OPT_r)
268   requested_ip = inet_addr(str_r);   requested_ip = inet_addr(str_r);
  if (opt & OPT_v) {  
  puts("version "BB_VER);  
  return 0;  
  }  
269  #if ENABLE_FEATURE_UDHCP_PORT  #if ENABLE_FEATURE_UDHCP_PORT
270   if (opt & OPT_P) {   if (opt & OPT_P) {
271   CLIENT_PORT = xatou16(str_P);   CLIENT_PORT = xatou16(str_P);
# Line 267  int udhcpc_main(int argc UNUSED_PARAM, c Line 283  int udhcpc_main(int argc UNUSED_PARAM, c
283   client_config.opt_mask[n >> 3] |= 1 << (n & 7);   client_config.opt_mask[n >> 3] |= 1 << (n & 7);
284   }   }
285    
286   if (udhcp_read_interface(client_config.interface, &client_config.ifindex,   if (udhcp_read_interface(client_config.interface,
287     NULL, client_config.arp))   &client_config.ifindex,
288     NULL,
289     client_config.client_mac)
290     ) {
291   return 1;   return 1;
292     }
293    
294  #if !BB_MMU  #if !BB_MMU
295   /* on NOMMU reexec (i.e., background) early */   /* on NOMMU reexec (i.e., background) early */
296   if (!(opt & OPT_f)) {   if (!(opt & OPT_f)) {
297   bb_daemonize_or_rexec(0 /* flags */, argv);   bb_daemonize_or_rexec(0 /* flags */, argv);
298   logmode = 0;   logmode = LOGMODE_NONE;
299   }   }
300  #endif  #endif
301   if (opt & OPT_S) {   if (opt & OPT_S) {
302   openlog(applet_name, LOG_PID, LOG_LOCAL0);   openlog(applet_name, LOG_PID, LOG_DAEMON);
303   logmode |= LOGMODE_SYSLOG;   logmode |= LOGMODE_SYSLOG;
304   }   }
305    
# Line 293  int udhcpc_main(int argc UNUSED_PARAM, c Line 314  int udhcpc_main(int argc UNUSED_PARAM, c
314   /* Goes to stdout (unless NOMMU) and possibly syslog */   /* Goes to stdout (unless NOMMU) and possibly syslog */
315   bb_info_msg("%s (v"BB_VER") started", applet_name);   bb_info_msg("%s (v"BB_VER") started", applet_name);
316    
317   /* if not set, and not suppressed, setup the default client ID */   /* If not set, and not suppressed, set up the default client ID */
318   if (!client_config.clientid && !(opt & OPT_C)) {   if (!client_config.clientid && !(opt & OPT_C)) {
319   client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, "", 7);   client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, "", 7);
320   client_config.clientid[OPT_DATA] = 1;   client_config.clientid[OPT_DATA] = 1;
321   memcpy(client_config.clientid + OPT_DATA+1, client_config.arp, 6);   memcpy(client_config.clientid + OPT_DATA+1, client_config.client_mac, 6);
322   }   }
323    
324   if (!client_config.vendorclass)   if (!client_config.vendorclass)
325   client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, "udhcp "BB_VER, 0);   client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, "udhcp "BB_VER, 0);
326    
327   /* setup the signal pipe */   /* Set up the signal pipe */
328   udhcp_sp_setup();   udhcp_sp_setup();
329    
330   state = INIT_SELECTING;   state = INIT_SELECTING;
# Line 318  int udhcpc_main(int argc UNUSED_PARAM, c Line 339  int udhcpc_main(int argc UNUSED_PARAM, c
339   * "continue" statements in code below jump to the top of the loop.   * "continue" statements in code below jump to the top of the loop.
340   */   */
341   for (;;) {   for (;;) {
342   unsigned timestamp_before_wait;   /* silence "uninitialized!" warning */
343     unsigned timestamp_before_wait = timestamp_before_wait;
344    
345     //bb_error_msg("sockfd:%d, listen_mode:%d", sockfd, listen_mode);
346    
347     /* Was opening raw or udp socket here
348     * if (listen_mode != LISTEN_NONE && sockfd < 0),
349     * but on fast network renew responses return faster
350     * than we open sockets. Thus this code is moved
351     * to change_listen_mode(). Thus we open listen socket
352     * BEFORE we send renew request (see "case BOUND:"). */
353    
  if (listen_mode != LISTEN_NONE && sockfd < 0) {  
  if (listen_mode == LISTEN_KERNEL)  
  sockfd = udhcp_listen_socket(/*INADDR_ANY,*/ CLIENT_PORT, client_config.interface);  
  else  
  sockfd = udhcp_raw_socket(client_config.ifindex);  
  }  
354   max_fd = udhcp_sp_fd_set(&rfds, sockfd);   max_fd = udhcp_sp_fd_set(&rfds, sockfd);
355    
356   tv.tv_sec = timeout - already_waited_sec;   tv.tv_sec = timeout - already_waited_sec;
357   tv.tv_usec = 0;   tv.tv_usec = 0;
358   retval = 0; /* If we already timed out, fall through, else... */   retval = 0; /* If we already timed out, fall through, else... */
359   if (tv.tv_sec > 0) {   if ((int)tv.tv_sec > 0) {
360   timestamp_before_wait = (unsigned)monotonic_sec();   timestamp_before_wait = (unsigned)monotonic_sec();
361   DEBUG("Waiting on select...");   log1("Waiting on select...");
362   retval = select(max_fd + 1, &rfds, NULL, NULL, &tv);   retval = select(max_fd + 1, &rfds, NULL, NULL, &tv);
363   if (retval < 0) {   if (retval < 0) {
364   /* EINTR? A signal was caught, don't panic */   /* EINTR? A signal was caught, don't panic */
365   if (errno == EINTR)   if (errno == EINTR) {
366     already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait;
367   continue;   continue;
368     }
369   /* Else: an error occured, panic! */   /* Else: an error occured, panic! */
370   bb_perror_msg_and_die("select");   bb_perror_msg_and_die("select");
371   }   }
# Line 356  int udhcpc_main(int argc UNUSED_PARAM, c Line 383  int udhcpc_main(int argc UNUSED_PARAM, c
383   if (packet_num < discover_retries) {   if (packet_num < discover_retries) {
384   if (packet_num == 0)   if (packet_num == 0)
385   xid = random_xid();   xid = random_xid();
386     /* broadcast */
387   send_discover(xid, requested_ip); /* broadcast */   send_discover(xid, requested_ip);
   
388   timeout = discover_timeout;   timeout = discover_timeout;
389   packet_num++;   packet_num++;
390   continue;   continue;
# Line 382  int udhcpc_main(int argc UNUSED_PARAM, c Line 408  int udhcpc_main(int argc UNUSED_PARAM, c
408   timeout = tryagain_timeout;   timeout = tryagain_timeout;
409   packet_num = 0;   packet_num = 0;
410   continue;   continue;
  case RENEW_REQUESTED:  
411   case REQUESTING:   case REQUESTING:
412   if (packet_num < discover_retries) {   if (packet_num < discover_retries) {
413   /* send request packet */   /* send broadcast select packet */
414   if (state == RENEW_REQUESTED) /* unicast */   send_select(xid, server_addr, requested_ip);
  send_renew(xid, server_addr, requested_ip);  
  else /* broadcast */  
  send_select(xid, server_addr, requested_ip);  
   
415   timeout = discover_timeout;   timeout = discover_timeout;
416   packet_num++;   packet_num++;
417   continue;   continue;
418   }   }
419   /* timed out, go back to init state */   /* Timed out, go back to init state.
420   if (state == RENEW_REQUESTED)   * "discover...select...discover..." loops
  udhcp_run_script(NULL, "deconfig");  
  change_listen_mode(LISTEN_RAW);  
  /* "discover...select...discover..." loops  
421   * were seen in the wild. Treat them similarly   * were seen in the wild. Treat them similarly
422   * to "no response to discover" case */   * to "no response to discover" case */
423   if (state == REQUESTING) {   change_listen_mode(LISTEN_RAW);
  state = INIT_SELECTING;  
  goto leasefail;  
  }  
424   state = INIT_SELECTING;   state = INIT_SELECTING;
425   timeout = 0;   goto leasefail;
  packet_num = 0;  
  continue;  
426   case BOUND:   case BOUND:
427   /* Half of the lease passed, time to enter renewing state */   /* 1/2 lease passed, enter renewing state */
  change_listen_mode(LISTEN_KERNEL);  
  DEBUG("Entering renew state");  
428   state = RENEWING;   state = RENEWING;
429     change_listen_mode(LISTEN_KERNEL);
430     log1("Entering renew state");
431   /* fall right through */   /* fall right through */
432     case RENEW_REQUESTED: /* manual (SIGUSR1) renew */
433     case_RENEW_REQUESTED:
434   case RENEWING:   case RENEWING:
435   if (timeout > 60) {   if (timeout > 60) {
436   /* send a request packet */   /* send an unicast renew request */
437   send_renew(xid, server_addr, requested_ip); /* unicast */   /* Sometimes observed to fail (EADDRNOTAVAIL) to bind
438     * a new UDP socket for sending inside send_renew.
439     * I hazard to guess existing listening socket
440     * is somehow conflicting with it, but why is it
441     * not deterministic then?! Strange.
442     * Anyway, it does recover by eventually failing through
443     * into INIT_SELECTING state.
444     */
445     send_renew(xid, server_addr, requested_ip);
446   timeout >>= 1;   timeout >>= 1;
447   continue;   continue;
448   }   }
449   /* Timed out, enter rebinding state */   /* Timed out, enter rebinding state */
450   DEBUG("Entering rebinding state");   log1("Entering rebinding state");
451   state = REBINDING;   state = REBINDING;
452   /* fall right through */   /* fall right through */
453   case REBINDING:   case REBINDING:
454     /* Switch to bcast receive */
455     change_listen_mode(LISTEN_RAW);
456   /* Lease is *really* about to run out,   /* Lease is *really* about to run out,
457   * try to find DHCP server using broadcast */   * try to find DHCP server using broadcast */
458   if (timeout > 0) {   if (timeout > 0) {
459   /* send a request packet */   /* send a broadcast renew request */
460   send_renew(xid, 0 /* INADDR_ANY*/, requested_ip); /* broadcast */   send_renew(xid, 0 /*INADDR_ANY*/, requested_ip);
461   timeout >>= 1;   timeout >>= 1;
462   continue;   continue;
463   }   }
464   /* Timed out, enter init state */   /* Timed out, enter init state */
465   bb_info_msg("Lease lost, entering init state");   bb_info_msg("Lease lost, entering init state");
466   udhcp_run_script(NULL, "deconfig");   udhcp_run_script(NULL, "deconfig");
  change_listen_mode(LISTEN_RAW);  
467   state = INIT_SELECTING;   state = INIT_SELECTING;
468   /*timeout = 0; - already is */   /*timeout = 0; - already is */
469   packet_num = 0;   packet_num = 0;
# Line 449  int udhcpc_main(int argc UNUSED_PARAM, c Line 473  int udhcpc_main(int argc UNUSED_PARAM, c
473   /* yah, I know, *you* say it would never happen */   /* yah, I know, *you* say it would never happen */
474   timeout = INT_MAX;   timeout = INT_MAX;
475   continue; /* back to main loop */   continue; /* back to main loop */
476     } /* if select timed out */
477    
478     /* select() didn't timeout, something happened */
479    
480     /* Is it a signal? */
481     /* note: udhcp_sp_read checks FD_ISSET before reading */
482     switch (udhcp_sp_read(&rfds)) {
483     case SIGUSR1:
484     perform_renew();
485     if (state == RENEW_REQUESTED)
486     goto case_RENEW_REQUESTED;
487     /* Start things over */
488     packet_num = 0;
489     /* Kill any timeouts, user wants this to hurry along */
490     timeout = 0;
491     continue;
492     case SIGUSR2:
493     perform_release(requested_ip, server_addr);
494     timeout = INT_MAX;
495     continue;
496     case SIGTERM:
497     bb_info_msg("Received SIGTERM");
498     if (opt & OPT_R) /* release on quit */
499     perform_release(requested_ip, server_addr);
500     goto ret0;
501   }   }
502    
  /* select() didn't timeout, something did happen. */  
503   /* Is it a packet? */   /* Is it a packet? */
504   if (listen_mode != LISTEN_NONE && FD_ISSET(sockfd, &rfds)) {   if (listen_mode == LISTEN_NONE || !FD_ISSET(sockfd, &rfds))
505     continue; /* no */
506    
507     {
508   int len;   int len;
  /* A packet is ready, read it */  
509    
510     /* A packet is ready, read it */
511   if (listen_mode == LISTEN_KERNEL)   if (listen_mode == LISTEN_KERNEL)
512   len = udhcp_recv_kernel_packet(&packet, sockfd);   len = udhcp_recv_kernel_packet(&packet, sockfd);
513   else   else
514   len = udhcp_recv_raw_packet(&packet, sockfd);   len = udhcp_recv_raw_packet(&packet, sockfd);
515   if (len == -1) { /* error is severe, reopen socket */   if (len == -1) {
516   DEBUG("error on read, %s, reopening socket", strerror(errno));   /* Error is severe, reopen socket */
517     bb_info_msg("Read error: %s, reopening socket", strerror(errno));
518   sleep(discover_timeout); /* 3 seconds by default */   sleep(discover_timeout); /* 3 seconds by default */
519   change_listen_mode(listen_mode); /* just close and reopen */   change_listen_mode(listen_mode); /* just close and reopen */
520   }   }
# Line 472  int udhcpc_main(int argc UNUSED_PARAM, c Line 524  int udhcpc_main(int argc UNUSED_PARAM, c
524   already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait;   already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait;
525   if (len < 0)   if (len < 0)
526   continue;   continue;
527     }
528    
529   if (packet.xid != xid) {   if (packet.xid != xid) {
530   DEBUG("Ignoring xid %x (our xid is %x)",   log1("xid %x (our is %x), ignoring packet",
531   (unsigned)packet.xid, (unsigned)xid);   (unsigned)packet.xid, (unsigned)xid);
532   continue;   continue;
533   }   }
534    
535   /* Ignore packets that aren't for us */   /* Ignore packets that aren't for us */
536   if (memcmp(packet.chaddr, client_config.arp, 6)) {   if (packet.hlen != 6
537   DEBUG("Packet does not have our chaddr - ignoring");   || memcmp(packet.chaddr, client_config.client_mac, 6)
538   continue;   ) {
539   }  //FIXME: need to also check that last 10 bytes are zero
540     log1("chaddr does not match, ignoring packet"); // log2?
541     continue;
542     }
543    
544   message = get_option(&packet, DHCP_MESSAGE_TYPE);   message = get_option(&packet, DHCP_MESSAGE_TYPE);
545   if (message == NULL) {   if (message == NULL) {
546   bb_error_msg("cannot get message type from packet - ignoring");   bb_error_msg("no message type option, ignoring packet");
547   continue;   continue;
548   }   }
549    
550   switch (state) {   switch (state) {
551   case INIT_SELECTING:   case INIT_SELECTING:
552   /* Must be a DHCPOFFER to one of our xid's */   /* Must be a DHCPOFFER to one of our xid's */
553   if (*message == DHCPOFFER) {   if (*message == DHCPOFFER) {
554   /* TODO: why we don't just fetch server's IP from IP header? */   /* TODO: why we don't just fetch server's IP from IP header? */
555   temp = get_option(&packet, DHCP_SERVER_ID);   temp = get_option(&packet, DHCP_SERVER_ID);
556   if (!temp) {   if (!temp) {
557   bb_error_msg("no server ID in message");   bb_error_msg("no server ID in message");
558   continue;   continue;
559   /* still selecting - this server looks bad */   /* still selecting - this server looks bad */
560   }   }
561     /* it IS unaligned sometimes, don't "optimize" */
562     move_from_unaligned32(server_addr, temp);
563     xid = packet.xid;
564     requested_ip = packet.yiaddr;
565    
566     /* enter requesting state */
567     state = REQUESTING;
568     timeout = 0;
569     packet_num = 0;
570     already_waited_sec = 0;
571     }
572     continue;
573     case REQUESTING:
574     case RENEWING:
575     case RENEW_REQUESTED:
576     case REBINDING:
577     if (*message == DHCPACK) {
578     temp = get_option(&packet, DHCP_LEASE_TIME);
579     if (!temp) {
580     bb_error_msg("no lease time with ACK, using 1 hour lease");
581     lease_seconds = 60 * 60;
582     } else {
583   /* it IS unaligned sometimes, don't "optimize" */   /* it IS unaligned sometimes, don't "optimize" */
584   server_addr = get_unaligned_u32p((uint32_t*)temp);   move_from_unaligned32(lease_seconds, temp);
585   xid = packet.xid;   lease_seconds = ntohl(lease_seconds);
586   requested_ip = packet.yiaddr;   lease_seconds &= 0x0fffffff; /* paranoia: must not be prone to overflows */
587     if (lease_seconds < 10) /* and not too small */
588   /* enter requesting state */   lease_seconds = 10;
  state = REQUESTING;  
  timeout = 0;  
  packet_num = 0;  
  already_waited_sec = 0;  
589   }   }
  continue;  
  case RENEW_REQUESTED:  
  case REQUESTING:  
  case RENEWING:  
  case REBINDING:  
  if (*message == DHCPACK) {  
  temp = get_option(&packet, DHCP_LEASE_TIME);  
  if (!temp) {  
  bb_error_msg("no lease time with ACK, using 1 hour lease");  
  lease_seconds = 60 * 60;  
  } else {  
  /* it IS unaligned sometimes, don't "optimize" */  
  lease_seconds = get_unaligned_u32p((uint32_t*)temp);  
  lease_seconds = ntohl(lease_seconds);  
  lease_seconds &= 0x0fffffff; /* paranoia: must not be prone to overflows */  
  if (lease_seconds < 10) /* and not too small */  
  lease_seconds = 10;  
  }  
590  #if ENABLE_FEATURE_UDHCPC_ARPING  #if ENABLE_FEATURE_UDHCPC_ARPING
591   if (opt & OPT_a) {   if (opt & OPT_a) {
592  /* RFC 2131 3.1 paragraph 5:  /* RFC 2131 3.1 paragraph 5:
593   * "The client receives the DHCPACK message with configuration   * "The client receives the DHCPACK message with configuration
594   * parameters. The client SHOULD perform a final check on the   * parameters. The client SHOULD perform a final check on the
# Line 542  int udhcpc_main(int argc UNUSED_PARAM, c Line 598  int udhcpc_main(int argc UNUSED_PARAM, c
598   * address is already in use (e.g., through the use of ARP),   * address is already in use (e.g., through the use of ARP),
599   * the client MUST send a DHCPDECLINE message to the server and restarts   * the client MUST send a DHCPDECLINE message to the server and restarts
600   * the configuration process..." */   * the configuration process..." */
601   if (!arpping(packet.yiaddr,   if (!arpping(packet.yiaddr,
602      (uint32_t) 0,   NULL,
603      client_config.arp,   (uint32_t) 0,
604      client_config.interface)   client_config.client_mac,
605   ) {   client_config.interface)
606   bb_info_msg("offered address is in use "   ) {
607   "(got ARP reply), declining");   bb_info_msg("Offered address is in use "
608   send_decline(xid, server_addr, packet.yiaddr);   "(got ARP reply), declining");
609     send_decline(xid, server_addr, packet.yiaddr);
610   if (state != REQUESTING)  
611   udhcp_run_script(NULL, "deconfig");   if (state != REQUESTING)
612   change_listen_mode(LISTEN_RAW);   udhcp_run_script(NULL, "deconfig");
613   state = INIT_SELECTING;   change_listen_mode(LISTEN_RAW);
614   requested_ip = 0;   state = INIT_SELECTING;
615   timeout = tryagain_timeout;   requested_ip = 0;
616   packet_num = 0;   timeout = tryagain_timeout;
617   already_waited_sec = 0;   packet_num = 0;
618   continue; /* back to main loop */   already_waited_sec = 0;
619   }   continue; /* back to main loop */
  }  
 #endif  
  /* enter bound state */  
  timeout = lease_seconds / 2;  
  {  
  struct in_addr temp_addr;  
  temp_addr.s_addr = packet.yiaddr;  
  bb_info_msg("Lease of %s obtained, lease time %u",  
  inet_ntoa(temp_addr), (unsigned)lease_seconds);  
  }  
  requested_ip = packet.yiaddr;  
  udhcp_run_script(&packet,  
  ((state == RENEWING || state == REBINDING) ? "renew" : "bound"));  
   
  state = BOUND;  
  change_listen_mode(LISTEN_NONE);  
  if (opt & OPT_q) { /* quit after lease */  
  if (opt & OPT_R) /* release on quit */  
  perform_release(requested_ip, server_addr);  
  goto ret0;  
  }  
 #if BB_MMU /* NOMMU case backgrounded earlier */  
  if (!(opt & OPT_f)) {  
  client_background();  
  /* do not background again! */  
  opt = ((opt & ~OPT_b) | OPT_f);  
620   }   }
621     }
622  #endif  #endif
623   already_waited_sec = 0;   /* enter bound state */
624   continue; /* back to main loop */   timeout = lease_seconds / 2;
625     {
626     struct in_addr temp_addr;
627     temp_addr.s_addr = packet.yiaddr;
628     bb_info_msg("Lease of %s obtained, lease time %u",
629     inet_ntoa(temp_addr), (unsigned)lease_seconds);
630   }   }
631   if (*message == DHCPNAK) {   requested_ip = packet.yiaddr;
632   /* return to init state */   udhcp_run_script(&packet, state == REQUESTING ? "bound" : "renew");
633   bb_info_msg("Received DHCP NAK");  
634   udhcp_run_script(&packet, "nak");   state = BOUND;
635   if (state != REQUESTING)   change_listen_mode(LISTEN_NONE);
636   udhcp_run_script(NULL, "deconfig");   if (opt & OPT_q) { /* quit after lease */
637   change_listen_mode(LISTEN_RAW);   if (opt & OPT_R) /* release on quit */
638   sleep(3); /* avoid excessive network traffic */   perform_release(requested_ip, server_addr);
639   state = INIT_SELECTING;   goto ret0;
  requested_ip = 0;  
  timeout = 0;  
  packet_num = 0;  
  already_waited_sec = 0;  
640   }   }
641   continue;   /* future renew failures should not exit (JM) */
642   /* case BOUND, RELEASED: - ignore all packets */   opt &= ~OPT_n;
643    #if BB_MMU /* NOMMU case backgrounded earlier */
644     if (!(opt & OPT_f)) {
645     client_background();
646     /* do not background again! */
647     opt = ((opt & ~OPT_b) | OPT_f);
648     }
649    #endif
650     already_waited_sec = 0;
651     continue; /* back to main loop */
652   }   }
653   continue; /* back to main loop */   if (*message == DHCPNAK) {
654   }   /* return to init state */
655     bb_info_msg("Received DHCP NAK");
656   /* select() didn't timeout, something did happen.   udhcp_run_script(&packet, "nak");
657   * But it wasn't a packet. It's a signal pipe then. */   if (state != REQUESTING)
658   {   udhcp_run_script(NULL, "deconfig");
659   int signo = udhcp_sp_read(&rfds);   change_listen_mode(LISTEN_RAW);
660   switch (signo) {   sleep(3); /* avoid excessive network traffic */
661   case SIGUSR1:   state = INIT_SELECTING;
662   perform_renew();   requested_ip = 0;
  /* start things over */  
  packet_num = 0;  
  /* Kill any timeouts because the user wants this to hurry along */  
663   timeout = 0;   timeout = 0;
664   break;   packet_num = 0;
665   case SIGUSR2:   already_waited_sec = 0;
  perform_release(requested_ip, server_addr);  
  timeout = INT_MAX;  
  break;  
  case SIGTERM:  
  bb_info_msg("Received SIGTERM");  
  if (opt & OPT_R) /* release on quit */  
  perform_release(requested_ip, server_addr);  
  goto ret0;  
666   }   }
667     continue;
668     /* case BOUND: - ignore all packets */
669     /* case RELEASED: - ignore all packets */
670   }   }
671     /* back to main loop */
672   } /* for (;;) - main loop ends */   } /* for (;;) - main loop ends */
673    
674   ret0:   ret0:

Legend:
Removed from v.983  
changed lines
  Added in v.984