Flesh out BUF_CMD_FLUSH support.
[dragonfly.git] / sbin / dhclient / client / dhclient.c.patch
1 $DragonFly: src/sbin/dhclient/client/Attic/dhclient.c.patch,v 1.2 2006/12/31 20:18:35 dillon Exp $
2 --- dhclient.c.orig     2004-06-10 19:59:12.000000000 +0200
3 +++ dhclient.c  2004-06-24 17:02:09.000000000 +0200
4 @@ -38,6 +38,13 @@
5  #include "dhcpd.h"
6  #include "version.h"
7  
8 +#include <sys/ioctl.h>
9 +#include <net/if_media.h>
10 +#if defined(DRAGONFLY_FUTURE)
11 +#include <net80211/ieee80211_ioctl.h>
12 +#include <net80211/ieee80211.h>
13 +#endif
14 +
15  TIME default_lease_time = 43200; /* 12 hours... */
16  TIME max_lease_time = 86400; /* 24 hours... */
17  
18 @@ -73,8 +80,11 @@
19  struct string_list *client_env=NULL;
20  int client_env_count=0;
21  int onetry=0;
22 -int quiet=0;
23 +int quiet=1;
24  int nowait=0;
25 +#ifdef ENABLE_POLLING_MODE
26 +int polling_interval = 5;
27 +#endif
28  
29  static void usage PROTO ((void));
30  
31 @@ -175,6 +185,9 @@
32                 } else if (!strcmp (argv [i], "-q")) {
33                         quiet = 1;
34                         quiet_interface_discovery = 1;
35 +               } else if (!strcmp (argv [i], "-v")) {
36 +                       quiet = 0;
37 +                       quiet_interface_discovery = 0;
38                 } else if (!strcmp (argv [i], "-s")) {
39                         if (++i == argc)
40                                 usage ();
41 @@ -188,6 +201,19 @@
42                 } else if (!strcmp (argv [i], "-n")) {
43                         /* do not start up any interfaces */
44                         interfaces_requested = 1;
45 +#ifdef ENABLE_POLLING_MODE
46 +               } else if (!strcmp (argv [i], "-i")) {
47 +                       if (++i == argc)
48 +                               usage ();
49 +                       polling_interval = (int)strtol (argv [i],
50 +                           (char **)NULL, 10);
51 +                       if (polling_interval <= 0) {
52 +                               log_info ("Incorrect polling interval %d",
53 +                                   polling_interval);
54 +                               log_info ("Using a default of 5 seconds");
55 +                               polling_interval = 5;
56 +                       }
57 +#endif
58                 } else if (!strcmp (argv [i], "-w")) {
59                         /* do not exit if there are no broadcast interfaces. */
60                         persist = 1;
61 @@ -216,7 +242,17 @@
62                     if (strlen (argv [i]) > sizeof tmp -> name)
63                             log_fatal ("%s: interface name too long (max %ld)",
64                                        argv [i], (long)strlen (argv [i]));
65 -                   strcpy (tmp -> name, argv [i]);
66 +                   strlcpy (tmp -> name, argv [i], IFNAMSIZ);
67 +#if defined(DRAGONFLY_FUTURE)
68 +                   set_ieee80211 (tmp);
69 +#endif
70 +                   /* Init some interface vars, enable polling */
71 +#ifdef ENABLE_POLLING_MODE
72 +                   tmp -> forcediscover = 0;
73 +                   tmp -> linkstate = HAVELINK;
74 +                   tmp -> polling = 1;
75 +#endif /* ifdef ENABLE_POLLING_MODE */
76 +
77                     if (interfaces) {
78                             interface_reference (&tmp -> next,
79                                                  interfaces, MDL);
80 @@ -376,6 +412,16 @@
81                                              INTERFACE_AUTOMATIC)) !=
82                              INTERFACE_REQUESTED))
83                                 continue;
84 +#if defined(DRAGONFLY_FUTURE)
85 +                       set_ieee80211 (ip);
86 +#endif
87 +#ifdef ENABLE_POLLING_MODE
88 +                       ip -> forcediscover = 0;
89 +                       if (ip -> client -> config -> media != NULL)
90 +                               ip -> havemedia = 1;
91 +                       else
92 +                               ip -> havemedia = 0;
93 +#endif
94                         script_init (ip -> client,
95                                      "PREINIT", (struct string_list *)0);
96                         if (ip -> client -> alias)
97 @@ -418,8 +464,13 @@
98                                 client -> state = S_INIT;
99                                 /* Set up a timeout to start the initialization
100                                    process. */
101 +#ifdef ENABLE_POLLING_MODE
102 +                               add_timeout (cur_time + random () % 5 + 2,
103 +                                            state_polling, client, 0, 0);
104 +#else
105                                 add_timeout (cur_time + random () % 5,
106                                              state_reboot, client, 0, 0);
107 +#endif
108                         }
109                 }
110         }
111 @@ -477,9 +528,9 @@
112         log_info (arr);
113         log_info (url);
114  
115 -       log_error ("Usage: dhclient [-1dqr] [-nw] [-p <port>] %s",
116 -                  "[-s server]");
117 -       log_error ("                [-cf config-file] [-lf lease-file]%s",
118 +       log_error ("Usage: dhclient [-1Ddqrv] [-i polling-interval] %s",
119 +                  "[-nw] [-p <port>] [-s server]");
120 +       log_error ("                [-cf config-file] [-lf lease-file] %s",
121                    "[-pf pid-file] [-e VAR=val]");
122         log_fatal ("                [-sf script-file] [interface]");
123  }
124 @@ -882,6 +933,15 @@
125         /* Write out the new lease. */
126         write_client_lease (client, client -> new, 0, 0);
127  
128 +       /*
129 +        * It's now possible that state_reboot can be called
130 +        * after a interface link went down and is up again.
131 +        * To prevent tons of equal leases saved on disk, we rewrite
132 +        * them.
133 +        */
134 +       read_client_leases ();
135 +       rewrite_client_leases ();
136 +
137         /* Replace the old active lease with the new one. */
138         if (client -> active)
139                 destroy_client_lease (client -> active);
140 @@ -896,6 +956,12 @@
141               piaddr (client -> active -> address),
142               (long)(client -> active -> renewal - cur_time));
143         client -> state = S_BOUND;
144 +#ifdef ENABLE_POLLING_MODE
145 +       /* Init some interface vars, enable polling */
146 +       client -> interface -> linkstate = HAVELINK;
147 +       client -> interface -> forcediscover = 0;
148 +       client -> interface -> polling = 1;
149 +#endif /* ifdef ENABLE_POLLING_MODE */
150         reinitialize_interfaces ();
151         go_daemon ();
152         if (client -> config -> do_forward_update) {
153 @@ -1358,6 +1424,11 @@
154         int interval;
155         int increase = 1;
156  
157 +#ifdef ENABLE_POLLING_MODE
158 +       /* Disable polling for this interface */
159 +       client -> interface -> polling = 0;
160 +#endif
161 +
162         /* Figure out how long it's been since we started transmitting. */
163         interval = cur_time - client -> first_sending;
164  
165 @@ -1463,6 +1534,9 @@
166         struct client_lease *loop;
167         struct client_lease *lp;
168  
169 +       if (client -> interface -> linkstate == NOLINK)
170 +               return;
171 +
172         loop = lp = client -> active;
173  
174         log_info ("No DHCPOFFERS received.");
175 @@ -1495,6 +1569,10 @@
176                                 log_info ("bound: renewal in %ld %s.",
177                                           (long)(client -> active -> renewal -
178                                                  cur_time), "seconds");
179 +#ifdef ENABLE_POLLING_MODE
180 +                               /* Enable polling for this interface */
181 +                               client -> interface -> polling = 1;
182 +#endif
183                                 add_timeout (client -> active -> renewal,
184                                              state_bound, client, 0, 0);
185                             } else {
186 @@ -1502,6 +1580,11 @@
187                                 log_info ("bound: immediate renewal.");
188                                 state_bound (client);
189                             }
190 +                           /*
191 +                            * Set the link status back to nolink, even
192 +                            * if we have media settings.
193 +                            */
194 +                           client -> interface -> linkstate = NOLINK;
195                             reinitialize_interfaces ();
196                             go_daemon ();
197                             return;
198 @@ -1547,6 +1630,12 @@
199         }
200  
201         log_info ("No working leases in persistent database - sleeping.");
202 +
203 +#ifdef ENABLE_POLLING_MODE
204 +       /* Enable polling for this interface */
205 +       client -> interface -> polling = 1;
206 +#endif
207 +
208         script_init (client, "FAIL", (struct string_list *)0);
209         if (client -> alias)
210                 script_write_params (client, "alias_", client -> alias);
211 @@ -1687,6 +1776,18 @@
212                         client -> packet.secs = htons (65535);
213         }
214  
215 +       /*
216 +        * Only try the first ten seconds to renew a lease from a
217 +        * given dhcp-server adress. After that, fall back to use
218 +        * state_reboot with INADDR_BROADCAST.
219 +        */
220 +       if (destination.sin_addr.s_addr != INADDR_BROADCAST &&
221 +          (client -> state == S_RENEWING || client -> state == S_REBINDING)) {
222 +               if (client -> active && client -> active -> expiry > cur_time &&
223 +                       interval >= 10)
224 +                       goto cancel;
225 +       }
226 +
227         log_info ("DHCPREQUEST on %s to %s port %d",
228               client -> name ? client -> name : client -> interface -> name,
229               inet_ntoa (destination.sin_addr),
230 @@ -1708,6 +1809,16 @@
231                                       from, &destination,
232                                       (struct hardware *)0);
233  
234 +       /*
235 +        * If sendto() for a direct request fails, fall back to use
236 +        * state_reboot with INADDR_BROADCAST.
237 +        */
238 +       if (result == -1 && destination.sin_addr.s_addr != INADDR_BROADCAST &&
239 +          (client -> state == S_RENEWING || client -> state == S_REBINDING)) {
240 +               if (client -> active && client -> active -> expiry > cur_time)
241 +                       goto cancel;
242 +       }
243 +
244         add_timeout (cur_time + client -> interval,
245                      send_request, client, 0, 0);
246  }
247 @@ -2603,6 +2714,13 @@
248                         wstatus = 0;
249                 }
250         } else {
251 +               if ((i = open(_PATH_DEVNULL, O_RDWR)) != -1) {
252 +                       dup2(i, STDIN_FILENO);
253 +                       dup2(i, STDOUT_FILENO);
254 +                       dup2(i, STDERR_FILENO);
255 +                       if (i > STDERR_FILENO)
256 +                               close(i);
257 +               }
258                 execve (scriptName, argv, envp);
259                 log_error ("execve (%s, ...): %m", scriptName);
260                 exit (0);
261 @@ -2789,8 +2907,10 @@
262                               case S_STOPPED:
263                                 break;
264                         }
265 +#ifndef ENABLE_POLLING_MODE
266                         client -> state = S_INIT;
267                         state_reboot (client);
268 +#endif
269                 }
270         }
271  }
272 @@ -3016,7 +3136,9 @@
273                     break;
274  
275                   case server_awaken:
276 +#ifndef ENABLE_POLLING_MODE
277                     state_reboot (client);
278 +#endif
279                     break;
280                 }
281             }
282 @@ -3153,3 +3275,256 @@
283         data_string_forget (&ddns_dhcid, MDL);
284         return rcode;
285  }
286 +
287 +/* Check to see if there's a wire plugged in */
288 +int
289 +interface_active(struct interface_info *ip) {
290 +       struct ifmediareq ifmr;
291 +       int *media_list, i;
292 +       char *ifname;
293 +       int sock;
294 +
295 +       ifname = ip -> name;
296 +
297 +       if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
298 +               log_fatal ("Can't create interface_active socket");
299 +
300 +       memset (&ifmr, 0, sizeof (ifmr));
301 +       strncpy (ifmr.ifm_name, ifname, sizeof (ifmr.ifm_name));
302 +
303 +       if (ioctl (sock, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
304 +               /*
305 +                * Interface doesn't support SIOCGIFMEDIA, presume okay
306 +                */
307 +               close (sock);
308 +               return (HAVELINK);
309 +       }
310 +       close (sock);
311 +
312 +       if (ifmr.ifm_count == 0) {
313 +               /*
314 +                * Assume that this means interface
315 +                * does not support SIOCGIFMEDIA
316 +                */
317 +               log_fatal ("%s: no media types?", ifname);
318 +               return (HAVELINK);
319 +       }
320 +
321 +       if (ifmr.ifm_status & IFM_AVALID) {
322 +               if (ip -> ieee80211) {
323 +                       /*
324 +                        * Wavelan devices need to be checked if they are
325 +                        * associated.
326 +                        */
327 +                       if ((IFM_TYPE(ifmr.ifm_active) == IFM_IEEE80211) &&
328 +                            (ifmr.ifm_status & IFM_ACTIVE)) {
329 +                               return (HAVELINK);
330 +                       }
331 +               } else {
332 +                       if (ifmr.ifm_status & IFM_ACTIVE) {
333 +                               return (HAVELINK);
334 +                       }
335 +               }
336 +               /*
337 +                * We really have no link.
338 +                */
339 +               return (NOLINK);
340 +       }
341 +       /*
342 +        * IFM_AVALID is not set. We cannot check
343 +        * the link state. Assume HAVELINK.
344 +        */
345 +
346 +       return (HAVELINK);
347 +}
348 +
349 +#if defined(DRAGONFLY_FUTURE)
350 +void
351 +set_ieee80211 (struct interface_info *ip) {
352 +       struct ieee80211req     ireq;
353 +       u_int8_t                data[32];
354 +       int                     associated = 0;
355 +       int *media_list, i;
356 +       char *ifname;
357 +       int sock;
358 +
359 +       ifname = ip -> name;
360 +
361 +       if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
362 +               log_fatal ("Can't create interface_active socket");
363 +
364 +       memset (&ireq, 0, sizeof (ireq));
365 +       strncpy (ireq.i_name, ifname, sizeof (ireq.i_name));
366 +       ireq.i_data = &data;
367 +       ireq.i_type = IEEE80211_IOC_SSID;
368 +       ireq.i_val = -1;
369 +       /*
370 +        * If we can't get the SSID,
371 +        * this isn't an 802.11 device.
372 +        */
373 +       if (ioctl (sock, SIOCG80211, &ireq) < 0)
374 +               ip -> ieee80211 = 0;
375 +       else {
376 +#ifdef DEBUG
377 +               printf ("Device %s has 802.11\n", ifname);
378 +#endif
379 +               ip -> ieee80211 = 1;
380 +       }
381 +       close (sock);
382 +}
383 +#endif
384 +
385 +#ifdef ENABLE_POLLING_MODE
386 +/* Go to background after some time */
387 +void state_background (void *cpp)
388 +{
389 +       go_daemon ();
390 +}
391 +
392 +/* Check the state of the NICs if we have link */
393 +void state_polling (void *cpp)
394 +{
395 +       static int doinitcheck = 0;
396 +       struct interface_info *ip;
397 +       struct client_state *client;
398 +       int result;
399 +
400 +       for (ip = interfaces; ip; ip = ip -> next) {
401 +               if (! ip -> polling)
402 +                       continue;
403 +#ifdef DEBUG
404 +               printf ("%s: Polling interface state\n", ip -> name);
405 +               for (client = ip -> client;
406 +                    client; client = client -> next) {
407 +                       printf ("%s: client state of %d\n", ip -> name, ip -> client -> state);
408 +                       printf ("%s: link = %d\n", ip -> name, ip -> linkstate);
409 +               }
410 +#endif
411 +
412 +               result = interface_active (ip);
413 +               /*
414 +                * If dhclient.conf contains media settings, we cannot
415 +                * abort if the interface is not set to active mode.
416 +                */
417 +               if (ip -> havemedia && ip -> client -> state != S_BOUND) {
418 +                       if (result == HAVELINK)
419 +                               ip -> forcediscover = 1;
420 +                       result = HAVELINK;
421 +               }
422 +
423 +               /*
424 +                * The last status of the interface tells us
425 +                * the we've got no link ...
426 +                */
427 +               if (ip -> linkstate == NOLINK || ! doinitcheck) {
428 +                       /*
429 +                        * ... but we have now link. Let's send
430 +                        * requests.
431 +                        */
432 +                       if (result == HAVELINK) {
433 +#ifdef DEBUG
434 +                               if (ip -> havemedia)
435 +                                       printf ("%s: Trying media settings on interface\n",
436 +                                               ip -> name);
437 +                               else
438 +                                       printf ("%s: Found Link on interface\n", ip -> name);
439 +#endif
440 +                               /*
441 +                                * Set the interface to state_bound. We assume that we have
442 +                                * a working link. If we cannot reach the server directly,
443 +                                * INADDR_BROADCAST is used.
444 +                                */
445 +                               for (client = ip -> client;
446 +                                    client; client = client -> next) {
447 +                                       cancel_timeout (state_init, client);
448 +                                       cancel_timeout (state_reboot, client);
449 +                                       cancel_timeout (state_selecting, client);
450 +                                       if (client -> active) {
451 +                                               add_timeout (cur_time + random () % 5,
452 +                                                  state_bound, client, 0, 0);
453 +                                       } else {
454 +                                               add_timeout (cur_time + random () % 5,
455 +                                                  state_reboot, client, 0, 0);
456 +                                       }
457 +                               }
458 +                               ip -> linkstate = HAVELINK;
459 +                       } else {
460 +#ifdef DEBUG
461 +                               printf ("%s: No link on interface\n", ip -> name);
462 +#endif
463 +                               for (client = ip -> client;
464 +                                    client; client = client -> next) {
465 +                                       /*
466 +                                        * Without this add_timout(), dhclient does
467 +                                        * not poll on a interface if there
468 +                                        * is no cable plugged in at startup
469 +                                        * time. Because we add one additional second
470 +                                        * to the time of a normal timeout, we always
471 +                                        * skip and block a running one. This prevents
472 +                                        * that polling is done twice at the same time.
473 +                                        */
474 +                                       if (client -> state == S_INIT) {
475 +                                               add_timeout (cur_time + (polling_interval + 1),
476 +                                                           state_polling, client, 0, 0);
477 +                                       }
478 +                               }
479 +                               ip -> linkstate = NOLINK;
480 +                               /*
481 +                                * Automatically go into the background after
482 +                                * some time. Do this only if there are no
483 +                                * media options available for a interface.
484 +                                */
485 +                               if (! ip -> havemedia && ! doinitcheck) {
486 +                                       add_timeout (cur_time + (polling_interval * 2),
487 +                                                   state_background, client, 0, 0);
488 +                               }
489 +                       }
490 +               }
491 +
492 +               /*
493 +                * The last status of the interface tells us
494 +                * the we previously had link.
495 +                */
496 +               if (ip -> linkstate == HAVELINK && doinitcheck) {
497 +                       if (result == NOLINK) {
498 +                               /*
499 +                                * We lost link on the interface, or it isn't
500 +                                * associated anymore.
501 +                                */
502 +#ifdef DEBUG
503 +                               printf ("%s: Lost Link on interface\n", ip -> name);
504 +#endif
505 +                               /*
506 +                                * After we lost link, cycle again through the
507 +                                * different media settings if available. Else
508 +                                * set NOLINK.
509 +                                */
510 +                               if (ip -> havemedia)
511 +                                       ip -> forcediscover = 1;
512 +                               else
513 +                                       ip -> linkstate = NOLINK;
514 +                       }
515 +                       /*
516 +                        * If we happen to have a real link, but no
517 +                        * active lease, force the interface into
518 +                        * state_reboot. Do the same if media settings
519 +                        * are available.
520 +                        */
521 +                       if (ip -> forcediscover) {
522 +                               for (client = ip -> client;
523 +                                    client; client = client -> next) {
524 +                                       if (client -> state != S_REBOOTING &&
525 +                                           client -> state != S_SELECTING) {
526 +                                               add_timeout (cur_time + random () % 5,
527 +                                                           state_reboot, client, 0, 0);
528 +                                       }
529 +                               }
530 +                               ip -> forcediscover = 0;
531 +                               ip -> linkstate = HAVELINK;
532 +                       }
533 +                       /* We still have link, do nothing. */
534 +               }
535 +       }
536 +       doinitcheck = 1;
537 +}
538 +#endif /* ifdef ENABLE_POLLING_MODE */