]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Add the ability to arping an address and select a profile based on the
authorRoy Marples <roy@marples.name>
Tue, 31 Mar 2009 08:35:38 +0000 (08:35 +0000)
committerRoy Marples <roy@marples.name>
Tue, 31 Mar 2009 08:35:38 +0000 (08:35 +0000)
hardware address replied with or the ip address.

arp.c
arp.h
configure.c
dhcpcd.c
dhcpcd.conf.5.in
dhcpcd.h
if-options.c
if-options.h

diff --git a/arp.c b/arp.c
index 93bd3ea4c7a17c303206b5cccec28aa7a361b1c0..4a22eeaefebc8388b8b78b1a0276b470a49bed11 100644 (file)
--- a/arp.c
+++ b/arp.c
@@ -104,6 +104,9 @@ handle_arp_packet(void *arg)
        uint8_t *hw_s, *hw_t;
        ssize_t bytes;
        struct if_state *state = iface->state;
+       struct if_options *opts = state->options;
+       const char *hwaddr;
+       struct in_addr ina;
 
        state->fail.s_addr = 0;
        for(;;) {
@@ -139,6 +142,28 @@ handle_arp_packet(void *arg)
                memcpy(&reply_s, hw_s + ar.ar_hln, ar.ar_pln);
                memcpy(&reply_t, hw_t + ar.ar_hln, ar.ar_pln);
 
+               /* Check for arping */
+               if (state->arping_index &&
+                   state->arping_index <= opts->arping_len &&
+                   (reply_s == opts->arping[state->arping_index - 1] ||
+                       (reply_s == 0 &&
+                           reply_t == opts->arping[state->arping_index - 1])))
+               {
+                       ina.s_addr = reply_s;
+                       hwaddr = hwaddr_ntoa((unsigned char *)hw_s,
+                           (size_t)ar.ar_hln);
+                       syslog(LOG_INFO,
+                           "%s: found %s on hardware address %s",
+                           iface->name, inet_ntoa(ina), hwaddr);
+                       if (select_profile(iface, hwaddr) == -1 &&
+                           errno == ENOENT)
+                               select_profile(iface, inet_ntoa(ina));
+                       close_sockets(iface);
+                       delete_timeout(NULL, iface);
+                       start_interface(iface);
+                       return;
+               }
+
                /* Check for conflict */
                if (state->offer &&
                    (reply_s == state->offer->yiaddr ||
@@ -216,8 +241,13 @@ send_arp_probe(void *arg)
        struct if_state *state = iface->state;
        struct in_addr addr;
        struct timeval tv;
+       int arping = 0;
 
-       if (state->offer) {
+       if (state->probes == 0 &&
+           state->arping_index < state->options->arping_len) {
+               addr.s_addr = state->options->arping[state->arping_index++];
+               arping = 1;
+       } else if (state->offer) {
                if (state->offer->yiaddr)
                        addr.s_addr = state->offer->yiaddr;
                else
@@ -230,9 +260,12 @@ send_arp_probe(void *arg)
                add_event(iface->arp_fd, handle_arp_packet, iface);
        }
        if (state->probes == 0) {
-               syslog(LOG_INFO, "%s: checking %s is available"
-                   " on attached networks",
-                   iface->name, inet_ntoa(addr));
+               if (arping)
+                       syslog(LOG_INFO, "%s: searching for %s",
+                           iface->name, inet_ntoa(addr));
+               else
+                       syslog(LOG_INFO, "%s: checking for %s",
+                           iface->name, inet_ntoa(addr));
        }
        if (++state->probes < PROBE_NUM) {
                tv.tv_sec = PROBE_MIN;
@@ -242,7 +275,14 @@ send_arp_probe(void *arg)
        } else {
                tv.tv_sec = ANNOUNCE_WAIT;
                tv.tv_usec = 0;
-               add_timeout_tv(&tv, bind_interface, iface);
+               if (arping) {
+                       state->probes = 0;
+                       if (state->arping_index < state->options->arping_len)
+                               add_timeout_tv(&tv, send_arp_probe, iface);
+                       else
+                               add_timeout_tv(&tv, start_interface, iface);
+               } else
+                       add_timeout_tv(&tv, bind_interface, iface);
        }
        syslog(LOG_DEBUG,
            "%s: sending ARP probe (%d of %d), next in %0.2f seconds",
@@ -250,3 +290,11 @@ send_arp_probe(void *arg)
        if (send_arp(iface, ARPOP_REQUEST, 0, addr.s_addr) == -1)
                syslog(LOG_ERR, "send_arp: %m");
 }
+
+void
+start_arping(struct interface *iface)
+{
+       iface->state->probes = 0;
+       iface->state->arping_index = 0;
+       send_arp_probe(iface);
+}
diff --git a/arp.h b/arp.h
index c9bc9e4964499f2dd2aa9fd2dc7e3aa6d131f9f7..924d22f932d3eb5f7a00419dc215a0ff63612908 100644 (file)
--- a/arp.h
+++ b/arp.h
@@ -41,6 +41,9 @@
 #define RATE_LIMIT_INTERVAL    60
 #define DEFEND_INTERVAL                10
 
+#include "dhcpcd.h"
+
 void send_arp_announce(void *);
 void send_arp_probe(void *);
+void start_arping(struct interface *);
 #endif
index dbb9118d464b35e3274042123f38b0978051a243..5d8b6b410e8355b4b959c7ac2ab384e55658b801 100644 (file)
@@ -202,6 +202,11 @@ make_env(const struct interface *iface, char ***argv)
                e--;
        }
        *--p = '\0';
+       if (*iface->state->profile) {
+               e = strlen("profile=") + strlen(iface->state->profile) + 2;
+               env[elen] = xmalloc(e);
+               snprintf(env[elen++], e, "profile=%s", iface->state->profile);
+       }
        if (iface->wireless) {
                e = strlen("new_ssid=") + strlen(iface->ssid) + 2;
                if (iface->state->new != NULL ||
index f3b96a9dfa3d2d803e0d177751b165f2b10a09c8..f32e0459baf8910f040c0678b1fa87a5d41e7a14 100644 (file)
--- a/dhcpcd.c
+++ b/dhcpcd.c
@@ -677,16 +677,13 @@ send_release(struct interface *iface)
 }
 
 static void
-configure_interface(struct interface *iface, int argc, char **argv)
+configure_interface1(struct interface *iface)
 {
        struct if_state *ifs = iface->state;
-       struct if_options *ifo;
+       struct if_options *ifo = ifs->options;
        uint8_t *duid;
        size_t len = 0, ifl;
 
-       free_options(ifs->options);
-       ifo = ifs->options = read_config(cffile, iface->name, iface->ssid);
-       add_options(ifo, argc, argv);
        if (iface->flags & IFF_POINTOPOINT && !(ifo->options & DHCPCD_INFORM))
                ifo->options |= DHCPCD_STATIC;
        if (iface->flags & IFF_NOARP ||
@@ -739,11 +736,42 @@ configure_interface(struct interface *iface, int argc, char **argv)
        }
 }
 
+int
+select_profile(struct interface *iface, const char *profile)
+{
+       struct if_options *ifo;
+
+       ifo = read_config(cffile, iface->name, iface->ssid, profile);
+       if (ifo == NULL) {
+               syslog(LOG_DEBUG, "%s: no profile %s", iface->name, profile);
+               return -1;
+       }
+       if (profile != NULL) {
+               strlcpy(iface->state->profile, profile,
+                   sizeof(iface->state->profile));
+               syslog(LOG_INFO, "%s: selected profile %s",
+                   iface->name, profile);
+       } else
+               *iface->state->profile = '\0';
+       free_options(iface->state->options);
+       iface->state->options = ifo;
+       configure_interface1(iface);
+       return 0;
+}
+
+static void
+configure_interface(struct interface *iface, int argc, char **argv)
+{
+       select_profile(iface, NULL);
+       add_options(iface->state->options, argc, argv);
+       configure_interface1(iface);
+}
+
+
 static void
 handle_carrier(const char *ifname)
 {
        struct interface *iface;
-       char ssid[IF_SSIDSIZE];
 
        for (iface = ifaces; iface; iface = iface->next)
                if (strcmp(iface->name, ifname) == 0)
@@ -767,15 +795,9 @@ handle_carrier(const char *ifname)
                if (iface->carrier != LINK_UP) {
                        iface->carrier = LINK_UP;
                        syslog(LOG_INFO, "%s: carrier acquired", iface->name);
-                       if (iface->wireless) {
-                               /* We need to reconfigre for if ssid changed */
-                               memset(ssid, 0, sizeof(ssid));
-                               getifssid(iface->name, ssid);
-                               if (strcmp(iface->ssid, ssid) != 0) {
-                                       strlcpy(iface->ssid, ssid, sizeof(iface->ssid));
-                                       configure_interface(iface, margc, margv);
-                               }
-                       }
+                       if (iface->wireless)
+                               getifssid(iface->name, iface->ssid);
+                       configure_interface(iface, margc, margv);
                        iface->state->interval = 0;
                        iface->state->reason = "CARRIER";
                        run_script(iface);
@@ -982,6 +1004,10 @@ start_interface(void *arg)
                start_discover(iface);
                return;
        }
+       if (iface->state->arping_index < ifo->arping_len) {
+               start_arping(iface);
+               return;
+       }
        if (ifo->options & DHCPCD_STATIC) {
                start_static(iface);
                return;
@@ -1179,7 +1205,7 @@ handle_ifa(int type, const char *ifname,
                        ifp->state->state = DHS_INFORM;
                        ifp->state->xid = arc4random();
                        ifp->state->lease.server.s_addr =
-                               dst ? dst->s_addr : INADDR_ANY;
+                           dst ? dst->s_addr : INADDR_ANY;
                        ifp->addr = *addr;
                        ifp->net = *net;
                        open_sockets(ifp);
@@ -1488,7 +1514,7 @@ main(int argc, char **argv)
 
        margv = argv;
        margc = argc;
-       ifo = read_config(cffile, NULL, NULL);
+       ifo = read_config(cffile, NULL, NULL, NULL);
        opt = add_options(ifo, argc, argv);
        if (opt != 1) {
                if (opt == 0)
index 988d74e96a61b521083ff6b08220fa571df822c3..51793773f068fad71b3aa2a1c20b604db606caf6 100644 (file)
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd March 19, 2009
+.Dd March 31, 2009
 .Dt DHCPCD.CONF 5 SMM
 .Os
 .Sh NAME
@@ -57,13 +57,25 @@ When discovering interfaces, the interface name must not match
 .Ar pattern
 which is a space or comma separated list of patterns passed to
 .Xr fnmatch 3 .
+.It Ic arping Ar address Op address
+.Nm dhcpcd
+will arping each address in order.
+If an address is found, we will select the replying hardware address as the
+profile, otherwise the ip address.
+Example:
+.Pp
+.D1 interface bge0
+.D1 arping 192.168.0.1
+.Pp
+.D1 profile 192.168.0.1
+.D1 static ip_address=192.168.0.10/24
 .It Ic background
 Background immediately.
 This is useful for startup scripts which don't disable link messages for
 carrier status.
-.It Ic blacklist Ar address Ns Op Ar /cidr
+.It Ic blacklist Ar address Ns Op /cidr
 Ignores all packets from
-.Ar address Ns Op Ar /cidr .
+.Ar address Ns Op /cidr .
 .It Ic clientid Ar string
 Send the
 .Ar clientid .
@@ -149,6 +161,9 @@ If
 detects an address added to a point to point interface (PPP, TUN, etc) then
 it will set the listed DHCP options to the destination address of the
 interface.
+.It Ic profile Ar name
+Subsequent options are only parsed for this profile
+.Ar name .
 .It Ic quiet
 Supress any dhcpcd output to the console, except for errors.
 .It Ic reboot Ar seconds
index a65e8633159f67ebb9039e3d033cffe28f46c149..e353a33f28e245aefa07800487749f7f692efa6a 100644 (file)
--- a/dhcpcd.h
+++ b/dhcpcd.h
@@ -39,6 +39,7 @@
 
 #define HWADDR_LEN 20
 #define IF_SSIDSIZE 33
+#define PROFILE_LEN 32
 
 enum DHS {
        DHS_INIT,
@@ -60,6 +61,7 @@ enum DHS {
 
 struct if_state {
        enum DHS state;
+       char profile[PROFILE_LEN];
        struct if_options *options;
        struct dhcp_message *sent;
        struct dhcp_message *offer;
@@ -76,6 +78,7 @@ struct if_state {
        int conflicts;
        time_t defend;
        struct in_addr fail;
+       size_t arping_index;
 };
 
 struct interface {
@@ -134,5 +137,6 @@ void start_expire(void *);
 void send_decline(struct interface *);
 void close_sockets(struct interface *);
 void drop_config(struct interface *, const char *);
+int select_profile(struct interface *, const char *);
 
 #endif
index 4ef78b799ae5b353583e5767043477e460ee6675..c10240cccdbca13f14d04c2c2380be75f84e0645 100644 (file)
@@ -46,6 +46,7 @@
 #include "net.h"
 
 const struct option cf_options[] = {
+       {"arping",          required_argument, NULL, 'a'},
        {"background",      no_argument,       NULL, 'b'},
        {"script",          required_argument, NULL, 'c'},
        {"debug",           no_argument,       NULL, 'd'},
@@ -311,6 +312,13 @@ parse_option(struct if_options *ifo, int opt, const char *arg)
        struct rt *rt;
 
        switch(opt) {
+       case 'a':
+               if (parse_addr(&addr, NULL, arg) != 0)
+                       return -1;
+               ifo->arping = xrealloc(ifo->arping,
+                   sizeof(in_addr_t) * (ifo->arping_len + 1));
+               ifo->arping[ifo->arping_len++] = addr.s_addr;
+               break;
        case 'e': /* FALLTHROUGH */
        case 'n': /* FALLTHROUGH */
        case 'x': /* FALLTHROUGH */
@@ -693,12 +701,13 @@ parse_config_line(struct if_options *ifo, const char *opt, char *line)
 }
 
 struct if_options *
-read_config(const char *file, const char *ifname, const char *ssid)
+read_config(const char *file,
+    const char *ifname, const char *ssid, const char *profile)
 {
        struct if_options *ifo;
        FILE *f;
        char *line, *option, *p;
-       int skip = 0;
+       int skip = 0, have_profile = 0;
 
        /* Seed our default options */
        ifo = xzalloc(sizeof(*ifo));
@@ -749,16 +758,30 @@ read_config(const char *file, const char *ifname, const char *ssid)
                                skip = 1;
                        continue;
                }
+               /* Start of a profile block, skip if not ours */
+               if (strcmp(option, "profile") == 0) {
+                       if (profile && line && strcmp(line, profile) == 0) {
+                               skip = 0;
+                               have_profile = 1;
+                       } else
+                               skip = 1;
+                       continue;
+               }
                if (skip)
                        continue;
-               if (parse_config_line(ifo, option, line) != 1) {
+               if (parse_config_line(ifo, option, line) != 1)
                        break;
-               }
        }
        fclose(f);
 
+       if (profile && !have_profile) {
+               free_options(ifo);
+               errno = ENOENT;
+               ifo = NULL;
+       }
+
        /* Terminate the encapsulated options */
-       if (ifo->vendor[0]) {
+       if (ifo && ifo->vendor[0]) {
                ifo->vendor[0]++;
                ifo->vendor[ifo->vendor[0]] = DHO_END;
        }
index 64c8bdea6c886a2405e1b0ec702c8167079ef844..7fad0e5dc7d3e020e94e8b1c162bfb34b5237760 100644 (file)
@@ -37,7 +37,7 @@
 
 /* Don't set any optional arguments here so we retain POSIX
  * compatibility with getopt */
-#define IF_OPTS "bc:def:h:i:kl:m:no:pqr:s:t:u:v:xy:z:ABC:DEF:GI:KLN:O:Q:TVX:Z:"
+#define IF_OPTS "a:bc:def:h:i:kl:m:no:pqr:s:t:u:v:xy:z:ABC:DEF:GI:KLN:O:Q:TVX:Z:"
 
 #define DEFAULT_TIMEOUT                30
 #define DEFAULT_REBOOT         10
@@ -100,9 +100,12 @@ struct if_options {
 
        size_t blacklist_len;
        in_addr_t *blacklist;
+       size_t arping_len;
+       in_addr_t *arping;
 };
 
-struct if_options *read_config(const char *, const char *, const char *);
+struct if_options *read_config(const char *,
+    const char *, const char *, const char *);
 int add_options(struct if_options *, int, char **);
 void free_options(struct if_options *);