From: Roy Marples Date: Thu, 5 Mar 2009 16:35:03 +0000 (+0000) Subject: Improve INFORM and STATIC support. X-Git-Tag: v5.0.0~47 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2f7cb97c9b78099a721cbfe750f1274b7367cfc5;p=thirdparty%2Fdhcpcd.git Improve INFORM and STATIC support. It's now possible to flip between DHCP, INFORM and STATIC on already running instances. --- diff --git a/bind.c b/bind.c index 98873d76..9595996f 100644 --- 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, diff --git a/dhcpcd.c b/dhcpcd.c index 0436104d..664d0d11 100644 --- 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); diff --git a/dhcpcd.h b/dhcpcd.h index 83440691..d8a5fabd 100644 --- 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 diff --git a/if-options.c b/if-options.c index 1e4ff981..7e79633a 100644 --- a/if-options.c +++ b/if-options.c @@ -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; diff --git a/if-options.h b/if-options.h index 9b75f68e..98c2f951 100644 --- a/if-options.h +++ b/if-options.h @@ -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;