]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Enable DHCP_INFORM support via the -S option
authorRoy Marples <roy@marples.name>
Fri, 11 May 2007 19:55:00 +0000 (19:55 +0000)
committerRoy Marples <roy@marples.name>
Fri, 11 May 2007 19:55:00 +0000 (19:55 +0000)
ChangeLog
client.c
configure.c
dhcp.c
dhcpcd.8
dhcpcd.c
dhcpcd.h
info.c
interface.c
interface.h

index 301c268c5704dfdf1286aee7a4d0590d47d110f4..cfacbff875a9187798a9fbbbd306bbffa6ce6d69 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,4 @@
+Enable DHCP_INFORM support via the -S option (requires -s ipaddr too)
 Use the DUID stored to create an RFC 4361 conformant client identifier
 if none is specified instead of just using the MAC address.
 Create a DUID-LLT according to RFC 3315 and store it in peristent file.
index 693790f3bb8e420a647a38090200b8de79decde5..59cadf905bc1cc091eabd5cbd2284e5108ee21d5 100644 (file)
--- a/client.c
+++ b/client.c
 
 /* We need this for our maximum timeout as FreeBSD's select cannot handle
    any higher than this. Is there a better way of working this out? */
-#define SELECT_MAX 100000000 
+#define SELECT_MAX              100000000
 
 /* This is out mini timeout.
    Basically we resend the last request every TIMEOUT_MINI seconds. */
-#define TIMEOUT_MINI           3
+#define TIMEOUT_MINI            3
 /* Except for an infinite timeout. We keep adding TIMEOUT_MINI to
    ourself until TIMEOUT_MINI_INF is reached. */
-#define TIMEOUT_MINI_INF       60
+#define TIMEOUT_MINI_INF        60
 
-#define STATE_INIT             0
-#define STATE_REQUESTING       1
-#define STATE_BOUND            2
-#define STATE_RENEWING         3
-#define STATE_REBINDING                4
-#define STATE_REBOOT           5
-#define STATE_RENEW_REQUESTED  6
-#define STATE_RELEASED         7
+#define STATE_INIT              0
+#define STATE_REQUESTING        1
+#define STATE_BOUND             2
+#define STATE_RENEWING          3
+#define STATE_REBINDING         4
+#define STATE_REBOOT            5
+#define STATE_RENEW_REQUESTED   6
+#define STATE_RELEASED          7
 
-#define SOCKET_CLOSED          0
-#define SOCKET_OPEN            1
+#define SOCKET_CLOSED           0
+#define SOCKET_OPEN             1
 
 #define SOCKET_MODE(_mode) { \
        if (iface->fd >= 0) close (iface->fd); \
@@ -160,23 +160,39 @@ int dhcp_run (const options_t *options)
        unsigned char *buffer = NULL;
        int buffer_len = 0;
        int buffer_pos = 0;
+       struct in_addr netmask;
+       struct in_addr broadcast;
 
        if (! options || (iface = (read_interface (options->interface,
                                                                                           options->metric))) == NULL)
                return -1;
 
+       dhcp = xmalloc (sizeof (dhcp_t));
+       memset (dhcp, 0, sizeof (dhcp_t));
+
+       memset (&netmask, 0, sizeof (struct in_addr));
+       memset (&broadcast, 0, sizeof (struct in_addr));
+       
        /* Remove all existing addresses.
           After all, we ARE a DHCP client whose job it is to configure the
           interface. We only do this on start, so persistent addresses can be added
           afterwards by the user if needed. */
-       flush_addresses (iface->name);
-
-       dhcp = xmalloc (sizeof (dhcp_t));
-       memset (dhcp, 0, sizeof (dhcp_t));
-
-       if (options->requestaddress.s_addr != 0)
+       if (! options->doinform)
+               flush_addresses (iface->name);
+       else {
                dhcp->address.s_addr = options->requestaddress.s_addr;
 
+               /* The inform address HAS to be configured for it to work with most
+                * DHCP servers */
+               if (options->doinform && has_address (iface->name, dhcp->address) < 1) {
+                       netmask.s_addr = get_netmask (dhcp->address.s_addr);
+                       broadcast.s_addr = dhcp->address.s_addr | ~netmask.s_addr;
+                       add_address (iface->name, dhcp->address, netmask, broadcast);
+                       iface->previous_address = dhcp->address;
+                       iface->previous_netmask = netmask;
+               }
+       }
+
        signal_setup ();
 
        while (1) {
@@ -298,7 +314,7 @@ int dhcp_run (const options_t *options)
                        /* timed out */
                        switch (state) {
                                case STATE_INIT:
-                                       if (iface->previous_address.s_addr != 0) {
+                                       if (iface->previous_address.s_addr != 0 && ! options->doinform) {
                                                logger (LOG_ERR, "lost lease");
                                                xid = 0;
                                                SOCKET_MODE (SOCKET_CLOSED);
@@ -380,6 +396,11 @@ int dhcp_run (const options_t *options)
                                        if (dhcp->address.s_addr == 0) {
                                                logger (LOG_INFO, "broadcasting for a lease");
                                                SEND_MESSAGE (DHCP_DISCOVER);
+                                       } else if (options->doinform) {
+                                               logger (LOG_INFO, "broadcasting inform for %s",
+                                                               inet_ntoa (dhcp->address));
+                                               SEND_MESSAGE (DHCP_INFORM);
+                                               state = STATE_REQUESTING;
                                        } else {
                                                logger (LOG_INFO, "broadcasting for a lease of %s",
                                                                inet_ntoa (dhcp->address));
@@ -412,7 +433,7 @@ int dhcp_run (const options_t *options)
                                        state = STATE_REQUESTING;
                                        break;
                                case STATE_REQUESTING:
-                                       if (iface->previous_address.s_addr != 0)
+                                       if (iface->previous_address.s_addr != 0 && ! options->doinform)
                                                logger (LOG_ERR, "lost lease");
                                        else
                                                logger (LOG_ERR, "timed out");
@@ -423,7 +444,8 @@ int dhcp_run (const options_t *options)
                                        SOCKET_MODE (SOCKET_CLOSED);
                                        timeout = 0;
                                        xid = 0;
-                                       DROP_CONFIG;
+                                       if (! options->doinform)
+                                               DROP_CONFIG;
                                        break;
 
                                case STATE_RELEASED:
@@ -549,11 +571,20 @@ int dhcp_run (const options_t *options)
                                                }
 #endif
 
-                                               if (dhcp->leasetime == (unsigned) -1) {
+                                               if (options->doinform) {
+                                                       dhcp->address = options->requestaddress;
+                                                       logger (LOG_INFO, "received approval for %s",
+                                                                       inet_ntoa (dhcp->address));
+                                                       timeout = options->leasetime;
+                                                       if (timeout == 0)
+                                                               timeout = DEFAULT_LEASETIME;
+                                                       state = STATE_INIT;
+                                               } else if (dhcp->leasetime == (unsigned) -1) {
                                                        dhcp->renewaltime = dhcp->rebindtime = dhcp->leasetime;
                                                        timeout = 1; /* So we select on infinity */
                                                        logger (LOG_INFO, "leased %s for infinity",
                                                                        inet_ntoa (dhcp->address));
+                                                       state = STATE_BOUND;
                                                } else {
                                                        if (! dhcp->leasetime) {
                                                                dhcp->leasetime = DEFAULT_LEASETIME;
@@ -597,9 +628,9 @@ int dhcp_run (const options_t *options)
                                                                                dhcp->rebindtime);
 
                                                        timeout = dhcp->renewaltime;
+                                                       state = STATE_BOUND;
                                                }
 
-                                               state = STATE_BOUND;
                                                xid = 0;
 
                                                if (configure (options, iface, dhcp) < 0 && ! daemonised) {
index 8690ea094931ce9de2d09e6f08c9ec2e8329d750..d121c4261d10a3d98a52e554c2d2121aa900527d 100644 (file)
@@ -378,10 +378,12 @@ int configure (const options_t *options, interface_t *iface,
 
                /* Only reset things if we had set them before */
                if (iface->previous_address.s_addr != 0) {
-                       del_address (iface->name, iface->previous_address,
-                                                iface->previous_netmask);
-                       memset (&iface->previous_address, 0, sizeof (struct in_addr));
-                       memset (&iface->previous_netmask, 0, sizeof (struct in_addr));
+                       if (! options->keep_address) {
+                               del_address (iface->name, iface->previous_address,
+                                                        iface->previous_netmask);
+                               memset (&iface->previous_address, 0, sizeof (struct in_addr));
+                               memset (&iface->previous_netmask, 0, sizeof (struct in_addr));
+                       }
 
                        restore_resolv (iface->name);
 
@@ -405,13 +407,15 @@ int configure (const options_t *options, interface_t *iface,
                }
        }
 
-       if (add_address (iface->name, dhcp->address, dhcp->netmask,
-                                        dhcp->broadcast) < 0 && errno != EEXIST)
-               return -1;
+       if (! options->doinform || ! has_address (iface->name, dhcp->address))
+               if (add_address (iface->name, dhcp->address, dhcp->netmask,
+                                                dhcp->broadcast) < 0 && errno != EEXIST)
+                       return -1;
 
        /* Now delete the old address if different */
-       if (iface->previous_address.s_addr != dhcp->address.s_addr
-               && iface->previous_address.s_addr != 0)
+       if (iface->previous_address.s_addr != dhcp->address.s_addr &&
+               iface->previous_address.s_addr != 0 &&
+               ! options->keep_address)
                del_address (iface->name, iface->previous_address, iface->previous_netmask);
 
 #ifdef __linux__
diff --git a/dhcp.c b/dhcp.c
index a4688be5ce98881b2170c33c7c93497d0c75fb75..eb38ef9b1b574b888df8c22b0c345a89c4d347df 100644 (file)
--- a/dhcp.c
+++ b/dhcp.c
@@ -86,6 +86,10 @@ size_t send_message (const interface_t *iface, const dhcp_t *dhcp,
        {
                message.ciaddr = iface->previous_address.s_addr;
                from.s_addr = iface->previous_address.s_addr;
+
+               /* Just incase we haven't actually configured the address yet */
+               if (type == DHCP_INFORM && iface->previous_address.s_addr == 0)
+                       message.ciaddr = dhcp->address.s_addr;
        }
 
        message.op = DHCP_BOOTREQUEST;
@@ -130,6 +134,7 @@ size_t send_message (const interface_t *iface, const dhcp_t *dhcp,
                p += 2;
        }
 
+       if (type != DHCP_INFORM) {
 #define PUTADDR(_type, _val) \
        { \
                *p++ = _type; \
@@ -145,6 +150,7 @@ size_t send_message (const interface_t *iface, const dhcp_t *dhcp,
                (iface->previous_address.s_addr == 0 || type == DHCP_RELEASE))
                PUTADDR (DHCP_SERVERIDENTIFIER, dhcp->serveraddress);
 #undef PUTADDR
+       }
 
        if (type == DHCP_REQUEST || type == DHCP_DISCOVER) {
                if (options->leasetime != 0) {
@@ -168,8 +174,10 @@ size_t send_message (const interface_t *iface, const dhcp_t *dhcp,
                if (type == DHCP_DISCOVER)
                        *p++ = DHCP_DNSSERVER;
                else {
-                       *p++ = DHCP_RENEWALTIME;
-                       *p++ = DHCP_REBINDTIME;
+                       if (type != DHCP_INFORM) {
+                               *p++ = DHCP_RENEWALTIME;
+                               *p++ = DHCP_REBINDTIME;
+                       }
                        *p++ = DHCP_NETMASK;
                        *p++ = DHCP_BROADCAST;
                        *p++ = DHCP_CSR;
@@ -284,26 +292,6 @@ size_t send_message (const interface_t *iface, const dhcp_t *dhcp,
                                                sizeof (struct udphdr));
 }
 
-static unsigned long getnetmask (unsigned long ip_in)
-{
-       unsigned long t, p = ntohl (ip_in);
-
-       if (IN_CLASSA (p))
-               t = ~IN_CLASSA_NET;
-       else {
-               if (IN_CLASSB (p))
-                       t = ~IN_CLASSB_NET;
-               else {
-                       if (IN_CLASSC (p))
-                               t = ~IN_CLASSC_NET;
-                       else
-                               t = 0;
-               }
-       }
-       while (t & p) t >>= 1;
-       return htonl (~t);
-}
-
 /* Decode an RFC3397 DNS search order option into a space
    seperated string. Returns length of string (including 
    terminating zero) or zero on error. out may be NULL
@@ -664,7 +652,7 @@ int parse_dhcpmessage (dhcp_t *dhcp, const dhcpmessage_t *message)
                                        memcpy (&static_routesp->destination.s_addr, p + i, 4);
                                        memcpy (&static_routesp->gateway.s_addr, p + i + 4, 4);
                                        static_routesp->netmask.s_addr =
-                                               getnetmask (static_routesp->destination.s_addr); 
+                                               get_netmask (static_routesp->destination.s_addr); 
                                }
                                break;
 
@@ -697,7 +685,7 @@ int parse_dhcpmessage (dhcp_t *dhcp, const dhcpmessage_t *message)
 eexit:
        /* Fill in any missing fields */
        if (! dhcp->netmask.s_addr)
-               dhcp->netmask.s_addr = getnetmask (dhcp->address.s_addr);
+               dhcp->netmask.s_addr = get_netmask (dhcp->address.s_addr);
        if (! dhcp->broadcast.s_addr)
                dhcp->broadcast.s_addr = dhcp->address.s_addr | ~dhcp->netmask.s_addr;
 
index 1878198467f4ac0a8183499be07a71f8ecb1b46b..75ab1d8025f542713756203105581a121a8aef07 100644 (file)
--- a/dhcpcd.8
+++ b/dhcpcd.8
@@ -1,6 +1,6 @@
 .\" $Id$
 .\"
-.TH DHCPCD 8 "18 April 2007" "dhcpcd 3.0"
+.TH DHCPCD 8 "11 May 2007" "dhcpcd 3.1"
 
 .SH NAME
 dhcpcd \- DHCP client daemon
@@ -9,7 +9,7 @@ dhcpcd \- DHCP client daemon
 .in +.5i
 .ti -.5i
 dhcpcd
-\%[\-adknpGHMNRTY]
+\%[\-adknpGHMNRSTY]
 \%[\-c\ script]
 \%[\-h\ hostname]
 \%[\-i\ vendorClassID]
@@ -151,7 +151,7 @@ message requesting to lease IP address ipaddr.
 The ipaddr parameter must be in the form xxx.xxx.xxx.xxx.
 This effectively doubles the timeout period, as if we fail to get
 this IP address then we enter the INIT state and try to get any
-IP address.
+IP address. To send a DHCP_INFORM message use the -S option.
 .TP
 .BI \-t \ timeout
 Specifies (in seconds ) for how long
@@ -215,7 +215,8 @@ file.
 Specifies the client identifier string. If not specified then
 .B dhcpcd
 will attempt to create a client identifier according to \fBRFC 4361\fR
-and store the DUID part in /var/lib/dhcpcd/dhcpcd.duid, otherwise
+and store the DUID part in
+.I /var/lib/dhcpcd/dhcpcd.duid\fR, otherwise
 .B dhcpcd
 uses the MAC address of the network interface. If \fB-I\fR is not given
 an option then we use the MAC address of the network interface.
@@ -238,6 +239,14 @@ from replacing
 .I /etc/resolv.conf
 or using resolvconf.
 .TP
+.BI \-S
+Sends a DHCP_INFORM message instead of a DHCP_REQUEST message when using the
+.BI \-s
+option. When we DHCP_INFORM, we don't request or respect any lease times.
+However, we do re-inform by the lease time specified by
+.BI \-l
+if given.
+.TP
 .BI \-T
 Will read 
 .I /var/lib/dhcpcd/dhcpcd-<interface>.info
index 4997e4059dcf69671e312db45de612237df7505e..417b3d43104ecce47f6970a59e1c9fe8ca3922dc 100644 (file)
--- a/dhcpcd.c
+++ b/dhcpcd.c
@@ -91,9 +91,9 @@ void make_pid (const char *pidfile)
 
 static void usage ()
 {
-       printf ("usage: "PACKAGE" [-adknpGHLMNRY] [-c script] [-h hostame] [-i classID]\n"
+       printf ("usage: "PACKAGE" [-adknpEGHMNRSY] [-c script] [-h hostame] [-i classID]\n"
                "              [-l leasetime] [-m metric] [-s ipaddress] [-t timeout]\n"
-               "              [-u userclass] [-F [none | ptr | both]] [-I clientID]\n");
+               "              [-u userclass] [-F [none | ptr | both]] [-I [clientID]]\n");
 }
 
 int main(int argc, char **argv)
@@ -110,31 +110,32 @@ int main(int argc, char **argv)
        int i;
 
        const struct option longopts[] = {
-        {"arp",         no_argument,        NULL, 'a'},
-        {"script",      required_argument,  NULL, 'c'},
-        {"debug",       no_argument,        NULL, 'd'},
-        {"hostname",    required_argument,  NULL, 'h'},
-        {"classid",     required_argument,  NULL, 'i'},
-        {"release",     no_argument,        NULL, 'k'},
-        {"leasetime",   required_argument,  NULL, 'l'},
-        {"metric",      required_argument,  NULL, 'm'},
-        {"renew",       no_argument,        NULL, 'n'},
-        {"persistent",  no_argument,        NULL, 'p'},
-        {"request",     required_argument,  NULL, 's'},
-        {"timeout",     required_argument,  NULL, 't'},
-        {"userclass",   required_argument,  NULL, 'u'},
-        {"lastlease",   no_argument,        NULL, 'E'},
+               {"arp",         no_argument,        NULL, 'a'},
+               {"script",      required_argument,  NULL, 'c'},
+               {"debug",       no_argument,        NULL, 'd'},
+               {"hostname",    required_argument,  NULL, 'h'},
+               {"classid",     required_argument,  NULL, 'i'},
+               {"release",     no_argument,        NULL, 'k'},
+               {"leasetime",   required_argument,  NULL, 'l'},
+               {"metric",      required_argument,  NULL, 'm'},
+               {"renew",       no_argument,        NULL, 'n'},
+               {"persistent",  no_argument,        NULL, 'p'},
+               {"request",     required_argument,  NULL, 's'},
+               {"timeout",     required_argument,  NULL, 't'},
+               {"userclass",   required_argument,  NULL, 'u'},
+               {"lastlease",   no_argument,        NULL, 'E'},
                {"fqdn",        optional_argument,  NULL, 'F'},
-        {"nogateway",   no_argument,        NULL, 'G'},
-        {"sethostname", no_argument,        NULL, 'H'},
-        {"clientid",    optional_argument,  NULL, 'I'},
-        {"nomtu",       no_argument,        NULL, 'M'},
-        {"nontp",       no_argument,        NULL, 'N'},
-        {"nodns",       no_argument,        NULL, 'R'},
+               {"nogateway",   no_argument,        NULL, 'G'},
+               {"sethostname", no_argument,        NULL, 'H'},
+               {"clientid",    optional_argument,  NULL, 'I'},
+               {"nomtu",       no_argument,        NULL, 'M'},
+               {"nontp",       no_argument,        NULL, 'N'},
+               {"nodns",       no_argument,        NULL, 'R'},
+               {"inform",      no_argument,        NULL, 'S'},
                {"nonis",       no_argument,        NULL, 'Y'},
-        {"help",        no_argument,        &dohelp, 1},
-        {"version",     no_argument,        &doversion, 1},
-        {NULL,          0,                  NULL, 0}
+               {"help",        no_argument,        &dohelp, 1},
+               {"version",     no_argument,        &doversion, 1},
+               {NULL,          0,                  NULL, 0}
        };
 
        /* Close any un-needed fd's */
@@ -154,9 +155,10 @@ int main(int argc, char **argv)
        options.dontp = true;
        options.dogateway = true;
        options.daemonise = true;
+       options.doinform = false;
        options.timeout = DEFAULT_TIMEOUT;
 
-       while ((ch = getopt_long(argc, argv, "ac:dh:i:kl:m:nps:t:u:EF::GHI::MNRY", longopts,
+       while ((ch = getopt_long(argc, argv, "ac:dh:i:kl:m:nps::t:u:EF::GHI::MNRSY", longopts,
                                                         &option_index)) != -1)
        {
                switch (ch) {
@@ -187,7 +189,7 @@ int main(int argc, char **argv)
                                break;
                        case 'h':
                                if (strlen (optarg) > sizeof (options.hostname)) {
-                                       logger (LOG_ERR, "`%s' too long for HostName string, max is %d",
+                                       logger (LOG_ERR, "`%s' too long for HostName string, max is %lu",
                                                        optarg, sizeof (options.hostname));
                                        exit (EXIT_FAILURE);
                                } else
@@ -221,7 +223,7 @@ int main(int argc, char **argv)
                                options.persistent = true;
                                break;
                        case 's':
-                               if (! inet_aton (optarg, &options.requestaddress)) {
+                               if (! inet_aton (optarg, &options.requestaddress)) { 
                                        logger (LOG_ERR, "`%s' is not a valid IP address", optarg);
                                        exit (EXIT_FAILURE);
                                }
@@ -294,6 +296,9 @@ int main(int argc, char **argv)
                        case 'R':
                                options.dodns = false;
                                break;
+                       case 'S':
+                               options.doinform = true;
+                               break;
                        case 'Y':
                                options.donis = false;
                                break;
@@ -340,7 +345,15 @@ int main(int argc, char **argv)
                        options.fqdn = FQDN_BOTH;
        } else
                options.fqdn = FQDN_DISABLE;
-       
+
+       if (options.doinform && options.requestaddress.s_addr == 0) {
+               if ((options.requestaddress.s_addr = get_address (options.interface)) == 0) {
+                       logger (LOG_ERR, "no existing address to inform");
+                       exit (EXIT_FAILURE);
+               }
+               options.keep_address = true;
+       }
+
        if (geteuid ()) {
                logger (LOG_ERR, "you need to be root to run "PACKAGE);
                exit (EXIT_FAILURE);
index a5be73b03b9e520cae042abc414960f07d9a7dd8..ff17bbc1715dd97654cec71d25e905c6bc2fefeb 100644 (file)
--- a/dhcpcd.h
+++ b/dhcpcd.h
@@ -60,9 +60,11 @@ typedef struct options_t {
        bool donis;
        bool dontp;
        bool dolastlease;
+       bool doinform;
 
        int signal;
        bool persistent;
+       bool keep_address;
        bool daemonise;
 
        char *script;
diff --git a/info.c b/info.c
index e9f0a2f88c7f2e7fa90d25e050e1c2ead1deb50a..55e79b454c475af7b19b5ee6cfa12d208c615204 100644 (file)
--- a/info.c
+++ b/info.c
@@ -165,10 +165,12 @@ bool write_info(const interface_t *iface, const dhcp_t *dhcp,
 
        fprintf (f, "DHCPSID='%s'\n", inet_ntoa (dhcp->serveraddress));
        fprintf (f, "DHCPSNAME='%s'\n", cleanmetas (dhcp->servername));
-       fprintf (f, "LEASEDFROM='%u'\n", dhcp->leasedfrom);
-       fprintf (f, "LEASETIME='%u'\n", dhcp->leasetime);
-       fprintf (f, "RENEWALTIME='%u'\n", dhcp->renewaltime);
-       fprintf (f, "REBINDTIME='%u'\n", dhcp->rebindtime);
+       if (! options->doinform) {
+               fprintf (f, "LEASEDFROM='%u'\n", dhcp->leasedfrom);
+               fprintf (f, "LEASETIME='%u'\n", dhcp->leasetime);
+               fprintf (f, "RENEWALTIME='%u'\n", dhcp->renewaltime);
+               fprintf (f, "REBINDTIME='%u'\n", dhcp->rebindtime);
+       }
        fprintf (f, "INTERFACE='%s'\n", iface->name);
        fprintf (f, "CLASSID='%s'\n", cleanmetas (options->classid));
        if (options->clientid_len > 0)
index 3b05999f394ebf7b9e769371b8ada3195e515c8f..bdd9a565e640b384007e5f75126ef2e9924b13c1 100644 (file)
@@ -111,6 +111,24 @@ int inet_ntocidr (struct in_addr address)
        return (cidr);
 }
 
+unsigned long get_netmask (unsigned long addr)
+{
+       unsigned long dst;
+
+       if (addr == 0)
+               return (0);
+
+       dst = htonl (addr);
+       if (IN_CLASSA (dst))
+               return (ntohl (IN_CLASSA_NET));
+       if (IN_CLASSB (dst))
+               return (ntohl (IN_CLASSB_NET));
+       if (IN_CLASSC (dst))
+               return (ntohl (IN_CLASSC_NET));
+
+       return (0);
+}
+
 char *hwaddr_ntoa (const unsigned char *hwaddr, int hwlen)
 {
        static char buffer[128];
@@ -862,7 +880,7 @@ int del_route (const char *ifname, struct in_addr destination,
 }
 
 #ifdef HAVE_IFADDRS_H
-int flush_addresses (const char *ifname)
+static int _do_addresses (const char *ifname, struct in_addr *addr, bool flush, bool get)
 {
        struct ifaddrs *ifap;
        struct ifaddrs *p;
@@ -886,16 +904,30 @@ int flush_addresses (const char *ifname)
                us_a.sa = p->ifa_addr;
                us_m.sa = p->ifa_netmask;
 
-               if (us_a.sin->sin_family == AF_INET)
-                       if (del_address (ifname, us_a.sin->sin_addr, us_m.sin->sin_addr) < 0)
-                               retval = -1;
+               if (us_a.sin->sin_family == AF_INET) {
+                       if (flush) {
+                               if (del_address (ifname, us_a.sin->sin_addr, us_m.sin->sin_addr)
+                                       < 0)
+                                       retval = -1;
+                       } else if (get) {
+                               addr->s_addr = us_a.sin->sin_addr.s_addr;
+                               retval = 1;
+                               break;
+                       } else {
+                               if (us_a.sin->sin_addr.s_addr == addr->s_addr) {
+                                       retval = 1;
+                                       break;
+                               }
+                       }
+               }
        }
        freeifaddrs (ifap);
 
        return retval;
 }
+
 #else
-int flush_addresses (const char *ifname)
+static int _do_addresses (const char *ifname, struct in_addr address, bool flush)
 {
        int s;
        struct ifconf ifc;
@@ -936,8 +968,15 @@ int flush_addresses (const char *ifname)
 
                if (ifr->ifr_addr.sa_family == AF_INET
                        && strcmp (ifname, ifr->ifr_name) == 0)
-                       if (del_address (ifname, addr->sin_addr, netm->sin_addr) < 0)
-                               retval = -1;
+               {
+                       if (flush) {
+                               if (del_address (ifname, addr->sin_addr, netm->sin_addr) < 0)
+                                       retval = -1;
+                       } else if (addr->sin_addr.s_addr == address.s_addr) {
+                               retval = 1;
+                               break;
+                       }
+               }
                ifr++;
        }
 
@@ -945,3 +984,23 @@ int flush_addresses (const char *ifname)
        return retval;
 }
 #endif
+
+int flush_addresses (const char *ifname)
+{
+       struct in_addr address;
+       return (_do_addresses (ifname, &address, true, false));
+}
+
+unsigned long get_address (const char *ifname)
+{
+       struct in_addr address;
+       if (_do_addresses (ifname, &address, false, true) > 0)
+               return (address.s_addr);
+       return (0);
+}
+
+int has_address (const char *ifname, struct in_addr address)
+{
+       return (_do_addresses (ifname, &address, false, false));
+}
+
index a5064852043801c2fd2d7d838442d96114f95429..b3696ec2966da7ddf0175cd8036d517090307d0e 100644 (file)
@@ -98,6 +98,9 @@ typedef struct interface_t
 
 void free_address (address_t *addresses);
 void free_route (route_t *routes);
+unsigned long get_netmask (unsigned long addr);
+char *hwaddr_ntoa (const unsigned char *hwaddr, int hwlen);
+
 interface_t *read_interface (const char *ifname, int metric);
 int get_mtu (const char *ifname);
 int set_mtu (const char *ifname, short int mtu);
@@ -106,7 +109,10 @@ int add_address (const char *ifname, struct in_addr address,
                                 struct in_addr netmask, struct in_addr broadcast);
 int del_address (const char *ifname, struct in_addr address,
                                 struct in_addr netmask);
+
 int flush_addresses (const char *ifname);
+unsigned long get_address (const char *ifname);
+int has_address (const char *ifname, struct in_addr address);
 
 int add_route (const char *ifname, struct in_addr destination,
                           struct in_addr netmask, struct in_addr gateway, int metric);
@@ -116,6 +122,5 @@ int del_route (const char *ifname, struct in_addr destination,
                           struct in_addr netmask, struct in_addr gateway, int metric);
 
 int inet_ntocidr (struct in_addr address);
-char *hwaddr_ntoa (const unsigned char *hwaddr, int hwlen);
 
 #endif