]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Improve INFORM and STATIC support.
authorRoy Marples <roy@marples.name>
Thu, 5 Mar 2009 16:35:03 +0000 (16:35 +0000)
committerRoy Marples <roy@marples.name>
Thu, 5 Mar 2009 16:35:03 +0000 (16:35 +0000)
It's now possible to flip between DHCP, INFORM and STATIC on already
running instances.

bind.c
dhcpcd.c
dhcpcd.h
if-options.c
if-options.h

diff --git a/bind.c b/bind.c
index 98873d76371fc53ee3f755c8e3bc393efeba2499..9595996f5fafe6e44b641c6fd4f6fecfea88be1f 100644 (file)
--- a/bind.c
+++ b/bind.c
@@ -137,7 +137,7 @@ bind_interface(void *arg)
                syslog(LOG_INFO, "%s: using static address %s",
                    iface->name, inet_ntoa(lease->addr));
                lease->leasetime = ~0U;
-               lease->net.s_addr = ifo->request_netmask.s_addr;
+               lease->net.s_addr = ifo->req_mask.s_addr;
                state->reason = "STATIC";
        } else if (IN_LINKLOCAL(htonl(state->new->yiaddr))) {
                syslog(LOG_INFO, "%s: using IPv4LL address %s",
@@ -145,8 +145,8 @@ bind_interface(void *arg)
                lease->leasetime = ~0U;
                state->reason = "IPV4LL";
        } else if (ifo->options & DHCPCD_INFORM) {
-               if (ifo->request_address.s_addr != 0)
-                       lease->addr.s_addr = ifo->request_address.s_addr;
+               if (ifo->req_addr.s_addr != 0)
+                       lease->addr.s_addr = ifo->req_addr.s_addr;
                else
                        lease->addr.s_addr = iface->addr.s_addr;
                syslog(LOG_INFO, "%s: received approval for %s", iface->name,
index 0436104d5bbe24d987d33db2d2161e5c0f844cc9..664d0d11804bc4950f2a4ee2bb314e10288d7240 100644 (file)
--- a/dhcpcd.c
+++ b/dhcpcd.c
@@ -437,7 +437,7 @@ handle_dhcp(struct interface *iface, struct dhcp_message **dhcpp)
                if (get_option_addr(&addr.s_addr, dhcp, DHO_SERVERID) != 0)
                        addr.s_addr = 0;
                for (i = 0; i < ifo->blacklist_len; i += 2) {
-               if (ifo->blacklist[i] ==
+                       if (ifo->blacklist[i] ==
                            (addr.s_addr & ifo->blacklist[i + 1]))
                        {
                                if (dhcp->servername[0])
@@ -832,6 +832,49 @@ start_timeout(void *arg)
        start_discover(iface);
 }
 
+static struct dhcp_message *
+dhcp_message_new(struct in_addr *addr, struct in_addr *mask)
+{
+       struct dhcp_message *dhcp;
+       uint8_t *p;
+
+       dhcp = xzalloc(sizeof(*dhcp));
+       dhcp->yiaddr = addr->s_addr;
+       p = dhcp->options;
+       if (mask && mask->s_addr != INADDR_ANY) {
+               *p++ = DHO_SUBNETMASK;
+               *p++ = sizeof(mask->s_addr);
+               memcpy(p, &mask->s_addr, sizeof(mask->s_addr));
+       }
+       *p++ = DHO_END;
+       return dhcp;
+}
+
+static void
+start_static(struct interface *iface)
+{
+       struct if_options *ifo = iface->state->options;
+
+       iface->state->offer = dhcp_message_new(&ifo->req_addr, &ifo->req_mask);
+       delete_timeout(NULL, iface);
+       bind_interface(iface);
+}
+
+static void
+start_inform(struct interface *iface)
+{
+       struct if_options *ifo = iface->state->options;
+
+       ifo->options |= DHCPCD_STATIC;
+       start_static(iface);
+       ifo->options &= ~DHCPCD_STATIC;
+
+       iface->state->state = DHS_INFORM;
+       iface->state->xid = arc4random();
+       open_sockets(iface);
+       send_inform(iface);
+}
+
 void
 start_reboot(struct interface *iface)
 {
@@ -841,6 +884,10 @@ start_reboot(struct interface *iface)
                syslog(LOG_INFO, "%s: waiting for carrier", iface->name);
                return;
        }
+       if (ifo->options & DHCPCD_STATIC) {
+               start_static(iface);
+               return;
+       }
        if (ifo->reboot == 0) {
                start_discover(iface);
                return;
@@ -866,7 +913,8 @@ start_reboot(struct interface *iface)
        delete_timeout(NULL, iface);
        if (ifo->options & DHCPCD_LASTLEASE && iface->state->lease.frominfo)
                add_timeout_sec(ifo->reboot, start_timeout, iface);
-       else
+       else if (!(ifo->options & DHCPCD_INFORM &&
+               options & (DHCPCD_MASTER | DHCPCD_DAEMONISED)))
                add_timeout_sec(ifo->reboot, start_expire, iface);
        open_sockets(iface);
        /* Don't bother ARP checking as the server could NAK us first. */
@@ -876,28 +924,6 @@ start_reboot(struct interface *iface)
                send_request(iface);
 }
 
-static void
-start_static(struct interface *iface)
-{
-       struct dhcp_message *dhcp;
-       struct if_options *ifo = iface->state->options;
-       uint8_t *p;
-       uint32_t u32;
-
-       dhcp = xzalloc(sizeof(*dhcp));
-       dhcp->yiaddr = ifo->request_address.s_addr;
-       p = dhcp->options;
-       *p++ = DHO_SUBNETMASK;
-       *p++ = sizeof(u32);
-       u32 = ifo->request_netmask.s_addr;
-       memcpy(p, &u32, sizeof(u32));
-       *p++ = DHO_END;
-
-       iface->state->offer = dhcp;
-       delete_timeout(NULL, iface);
-       bind_interface(iface);
-}
-
 void
 start_interface(void *arg)
 {
@@ -924,27 +950,24 @@ start_interface(void *arg)
                start_static(iface);
                return;
        }
-       if (ifo->request_address.s_addr) {
-               /* This also changes netmask */
-               if (iface->state->options->options & DHCPCD_INFORM &&
-                   !has_address(iface->name, &ifo->request_address,
-                       &ifo->request_netmask))
-               {
-                       syslog(LOG_DEBUG, "%s: adding IP address %s/%d",
-                           iface->name, inet_ntoa(ifo->request_address),
-                           inet_ntocidr(ifo->request_netmask));
-                       if (add_address(iface, &ifo->request_address,
-                               &ifo->request_netmask, NULL) == -1 &&
-                           errno != EEXIST)
-                       {
-                               syslog(LOG_ERR, "add_address: %m");
-                       }
-               }
-               iface->state->offer = xzalloc(sizeof(*iface->state->offer));
-               iface->state->offer->yiaddr = ifo->request_address.s_addr;
-               *iface->state->offer->options = DHO_END;
+       if (ifo->options & DHCPCD_INFORM) {
+               start_inform(iface);
+               return;
+       }
+       if (ifo->req_addr.s_addr) {
+               iface->state->offer = dhcp_message_new(&ifo->req_addr,
+                   &ifo->req_mask);
                if (ifo->options & DHCPCD_REQUEST)
-                       ifo->request_address.s_addr = 0;
+                       ifo->req_addr.s_addr = 0;
+               else {
+                       iface->state->reason = "STATIC";
+                       iface->state->new = iface->state->offer;
+                       iface->state->offer = NULL;
+                       get_lease(&iface->state->lease, iface->state->new);
+                       configure(iface);
+                       start_inform(iface);
+                       return;
+               }
        } else
                iface->state->offer = read_lease(iface);
        if (iface->state->offer) {
@@ -1131,6 +1154,30 @@ handle_signal(_unused void *arg)
        exit(EXIT_FAILURE);
 }
 
+static void
+reconf_reboot(struct interface *iface, int argc, char **argv)
+{
+       const struct if_options *ifo;
+       int opt;
+       
+       ifo = iface->state->options;
+       opt = ifo->options;
+       configure_interface(iface, argc, argv);
+       ifo = iface->state->options;
+       iface->state->interval = 0;
+       if ((ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC) &&
+               iface->addr.s_addr != ifo->req_addr.s_addr) ||
+           (opt & (DHCPCD_INFORM | DHCPCD_STATIC) &&
+               !(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC))))
+       {
+               drop_config(iface, "EXPIRE");
+       } else {
+               free(iface->state->offer);
+               iface->state->offer = NULL;
+       }
+       start_interface(iface);
+}
+
 int
 handle_args(struct fd_list *fd, int argc, char **argv)
 {
@@ -1256,11 +1303,9 @@ handle_args(struct fd_list *fd, int argc, char **argv)
                                ifl = ifn;
                        }
                        if (ifn) {
-                               if (do_reboot) {
-                                       configure_interface(ifn, argc, argv);
-                                       start_reboot(ifn);
-                               }
-                               free(ifp);
+                               if (do_reboot)
+                                       reconf_reboot(ifn, argc, argv);
+                               free_interface(ifp);
                        } else {
                                ifp->next = NULL;
                                init_state(ifp, argc, argv);
index 834406913294b0368bc269edfb0148c140e03a3f..d8a5fabd9076ef16e247caa9ae6847ce49969580 100644 (file)
--- a/dhcpcd.h
+++ b/dhcpcd.h
@@ -48,6 +48,7 @@ enum DHS {
        DHS_RENEW,
        DHS_REBIND,
        DHS_REBOOT,
+       DHS_INFORM,
        DHS_RENEW_REQUESTED,
        DHS_INIT_IPV4LL,
        DHS_PROBE
index 1e4ff9814a09dd15ea9fa0636b64574abc02bea1..7e79633abcd2e5c2e4b4100af49a1787bc02507d 100644 (file)
@@ -271,8 +271,13 @@ parse_addr(struct in_addr *addr, struct in_addr *net, const char *arg)
        char *p;
        int i;
 
-       if (arg == NULL || *arg == '\0')
+       if (arg == NULL || *arg == '\0') {
+               if (addr != NULL)
+                       addr->s_addr = 0;
+               if (net != NULL)
+                       net->s_addr = 0;
                return 0;
+       }
        if ((p = strchr(arg, '/')) != NULL) {
                *p++ = '\0';
                if (net != NULL &&
@@ -282,13 +287,16 @@ parse_addr(struct in_addr *addr, struct in_addr *net, const char *arg)
                        syslog(LOG_ERR, "`%s' is not a valid CIDR", p);
                        return -1;
                }
-       }
+       } 
+
        if (addr != NULL && inet_aton(arg, addr) == 0) {
                syslog(LOG_ERR, "`%s' is not a valid IP address", arg);
                return -1;
        }
-       if (p)
+       if (p != NULL)
                *--p = '/';
+       else if (net != NULL)
+               net->s_addr = get_netmask(addr->s_addr);
        return 0;
 }
 
@@ -382,23 +390,24 @@ parse_option(struct if_options *ifo, int opt, const char *arg)
        case 'q':
                ifo->options |= DHCPCD_QUIET;
                break;
+       case 'r':
+               ifo->options |= DHCPCD_REQUEST;
+               if (parse_addr(&ifo->req_addr, NULL, arg) != 0)
+                       return -1;
+               ifo->req_mask.s_addr = 0;
+               break;
        case 's':
                ifo->options |= DHCPCD_INFORM | DHCPCD_PERSISTENT;
                ifo->options &= ~DHCPCD_ARP;
-               if (!arg || *arg == '\0') {
-                       ifo->request_address.s_addr = 0;
-               } else {
-                       if (parse_addr(&ifo->request_address,
-                               &ifo->request_netmask,
+               if (arg && *arg != '\0') {
+                       if (parse_addr(&ifo->req_addr, &ifo->req_mask,
                                arg) != 0)
                                return -1;
+               } else {
+                       ifo->req_addr.s_addr = 0;
+                       ifo->req_mask.s_addr = 0;
                }
                break;
-       case 'r':
-               ifo->options |= DHCPCD_REQUEST;
-               if (parse_addr(&ifo->request_address, NULL, arg) != 0)
-                       return -1;
-               break;
        case 't':
                ifo->timeout = atoint(arg);
                if (ifo->timeout < 0) {
@@ -559,8 +568,7 @@ parse_option(struct if_options *ifo, int opt, const char *arg)
                }
                p++;
                if (strncmp(arg, "ip_address=", strlen("ip_address=")) == 0) {
-                       if (parse_addr(&ifo->request_address,
-                               &ifo->request_netmask, p) != 0)
+                       if (parse_addr(&ifo->req_addr, &ifo->req_mask, p) != 0)
                                return -1;
 
                        ifo->options |= DHCPCD_STATIC;
index 9b75f68e79738bd99e1259168ed61a0e4d2ad74b..98c2f9516019dbb35de41bff2efeade045f4683f 100644 (file)
@@ -82,8 +82,8 @@ struct if_options {
        time_t reboot;
        int options;
 
-       struct in_addr request_address;
-       struct in_addr request_netmask;
+       struct in_addr req_addr;
+       struct in_addr req_mask;
        struct rt *routes;
        char **config;