This should reduce memory usage for non IPv4 interfaces.
static void
arp_failure(struct interface *ifp)
{
+ const struct dhcp_state *state = D_CSTATE(ifp);
/* If we failed without a magic cookie then we need to try
* and defend our IPv4LL address. */
- if ((ifp->state->offer != NULL &&
- ifp->state->offer->cookie != htonl(MAGIC_COOKIE)) ||
- (ifp->state->new != NULL &&
- ifp->state->new->cookie != htonl(MAGIC_COOKIE)))
+ if ((state->offer != NULL &&
+ state->offer->cookie != htonl(MAGIC_COOKIE)) ||
+ (state->new != NULL &&
+ state->new->cookie != htonl(MAGIC_COOKIE)))
{
ipv4ll_handle_failure(ifp);
return;
}
- unlink(ifp->state->leasefile);
- if (!ifp->state->lease.frominfo)
+ unlink(state->leasefile);
+ if (!state->lease.frominfo)
dhcp_decline(ifp);
dhcp_close(ifp);
eloop_timeout_delete(NULL, ifp);
- if (ifp->state->lease.frominfo)
+ if (state->lease.frominfo)
start_interface(ifp);
else
eloop_timeout_add_sec(DHCP_ARP_FAIL, start_interface, ifp);
uint32_t reply_t;
uint8_t *hw_s, *hw_t;
ssize_t bytes;
- struct if_state *state = ifp->state;
+ struct dhcp_state *state;
struct if_options *opts = ifp->options;
const char *hwaddr;
struct in_addr ina;
+ state = D_STATE(ifp);
state->fail.s_addr = 0;
for(;;) {
bytes = get_raw_packet(ifp, ETHERTYPE_ARP,
arp_announce(void *arg)
{
struct interface *ifp = arg;
- struct if_state *state = ifp->state;
+ struct dhcp_state *state = D_STATE(ifp);
struct timeval tv;
if (state->new == NULL)
arp_probe(void *arg)
{
struct interface *ifp = arg;
- struct if_state *state = ifp->state;
+ struct dhcp_state *state = D_STATE(ifp);
struct in_addr addr;
struct timeval tv;
int arping = 0;
void
arp_start(struct interface *ifp)
{
+ struct dhcp_state *state = D_STATE(ifp);
- ifp->state->probes = 0;
- ifp->state->arping_index = 0;
+ state->probes = 0;
+ state->arping_index = 0;
arp_probe(ifp);
}
#include "config.h"
#include "common.h"
#include "dhcp.h"
+#include "dhcpcd.h"
#include "dhcp-common.h"
+#include "duid.h"
#include "eloop.h"
#include "ipv4.h"
#include "ipv4ll.h"
free_option_buffer(void)
{
+ free(packet);
free(opt_buffer);
}
#endif
const char *hp;
const struct dhcp_opt *opt;
const struct if_options *ifo = iface->options;
- const struct if_state *ifs = iface->state;
- const struct dhcp_lease *lease = &ifs->lease;
- time_t up = uptime() - ifs->start_uptime;
+ const struct dhcp_state *state = D_CSTATE(iface);
+ const struct dhcp_lease *lease = &state->lease;
+ time_t up = uptime() - state->start_uptime;
dhcp = xzalloc(sizeof (*dhcp));
m = (uint8_t *)dhcp;
if ((type == DHCP_INFORM || type == DHCP_RELEASE ||
(type == DHCP_REQUEST &&
- ifs->net.s_addr == lease->net.s_addr &&
- (ifs->new == NULL ||
- ifs->new->cookie == htonl(MAGIC_COOKIE)))))
+ state->net.s_addr == lease->net.s_addr &&
+ (state->new == NULL ||
+ state->new->cookie == htonl(MAGIC_COOKIE)))))
{
- dhcp->ciaddr = ifs->addr.s_addr;
+ dhcp->ciaddr = state->addr.s_addr;
/* In-case we haven't actually configured the address yet */
- if (type == DHCP_INFORM && ifs->addr.s_addr == 0)
+ if (type == DHCP_INFORM && state->addr.s_addr == 0)
dhcp->ciaddr = lease->addr.s_addr;
}
else
dhcp->secs = htons(up);
}
- dhcp->xid = htonl(ifs->xid);
+ dhcp->xid = htonl(state->xid);
dhcp->cookie = htonl(MAGIC_COOKIE);
*p++ = DHO_MESSAGETYPE;
*p++ = 1;
*p++ = type;
- if (ifs->clientid) {
+ if (state->clientid) {
*p++ = DHO_CLIENTID;
- memcpy(p, ifs->clientid, ifs->clientid[0] + 1);
- p += ifs->clientid[0] + 1;
+ memcpy(p, state->clientid, state->clientid[0] + 1);
+ p += state->clientid[0] + 1;
}
if (lease->addr.s_addr && lease->cookie == htonl(MAGIC_COOKIE)) {
if (type == DHCP_DECLINE ||
(type == DHCP_REQUEST &&
- lease->addr.s_addr != ifs->addr.s_addr))
+ lease->addr.s_addr != state->addr.s_addr))
{
PUTADDR(DHO_IPADDRESS, lease->addr);
if (lease->server.s_addr)
}
ssize_t
-write_lease(const struct interface *iface, const struct dhcp_message *dhcp)
+write_lease(const struct interface *ifp, const struct dhcp_message *dhcp)
{
int fd;
ssize_t bytes = sizeof(*dhcp);
const uint8_t *e = p + sizeof(dhcp->options);
uint8_t l;
uint8_t o = 0;
+ const struct dhcp_state *state = D_CSTATE(ifp);
/* We don't write BOOTP leases */
if (is_bootp(dhcp)) {
- unlink(iface->state->leasefile);
+ unlink(state->leasefile);
return 0;
}
syslog(LOG_DEBUG, "%s: writing lease `%s'",
- iface->name, iface->state->leasefile);
+ ifp->name, state->leasefile);
- fd = open(iface->state->leasefile, O_WRONLY | O_CREAT | O_TRUNC, 0444);
+ fd = open(state->leasefile, O_WRONLY | O_CREAT | O_TRUNC, 0444);
if (fd == -1)
return -1;
}
struct dhcp_message *
-read_lease(const struct interface *iface)
+read_lease(const struct interface *ifp)
{
int fd;
struct dhcp_message *dhcp;
+ const struct dhcp_state *state = D_CSTATE(ifp);
ssize_t bytes;
- fd = open(iface->state->leasefile, O_RDONLY);
+ fd = open(state->leasefile, O_RDONLY);
if (fd == -1) {
if (errno != ENOENT)
syslog(LOG_ERR, "%s: open `%s': %m",
- iface->name, iface->state->leasefile);
+ ifp->name, state->leasefile);
return NULL;
}
syslog(LOG_DEBUG, "%s: reading lease `%s'",
- iface->name, iface->state->leasefile);
+ ifp->name, state->leasefile);
dhcp = xmalloc(sizeof(*dhcp));
memset(dhcp, 0, sizeof(*dhcp));
bytes = read(fd, dhcp, sizeof(*dhcp));
void
dhcp_close(struct interface *ifp)
{
- struct if_state *ifs = ifp->state;
+ struct dhcp_state *state = D_STATE(ifp);
+
+ if (state == NULL)
+ return;
- if (ifs->arp_fd != -1) {
- eloop_event_delete(ifs->arp_fd);
- close(ifs->arp_fd);
- ifs->arp_fd = -1;
+ if (state->arp_fd != -1) {
+ eloop_event_delete(state->arp_fd);
+ close(state->arp_fd);
+ state->arp_fd = -1;
}
- if (ifs->raw_fd != -1) {
- eloop_event_delete(ifs->raw_fd);
- close(ifs->raw_fd);
- ifs->raw_fd = -1;
+ if (state->raw_fd != -1) {
+ eloop_event_delete(state->raw_fd);
+ close(state->raw_fd);
+ state->raw_fd = -1;
}
- if (ifs->udp_fd != -1) {
+ if (state->udp_fd != -1) {
/* we don't listen to events on the udp */
- close(ifs->udp_fd);
- ifs->udp_fd = -1;
+ close(state->udp_fd);
+ state->udp_fd = -1;
}
+
+ state->interval = 0;
}
static void
send_message(struct interface *iface, int type,
void (*callback)(void *))
{
- struct if_state *state = iface->state;
+ struct dhcp_state *state = D_STATE(iface);
struct if_options *ifo = iface->options;
struct dhcp_message *dhcp;
uint8_t *udp;
dhcp_discover(void *arg)
{
struct interface *iface = arg;
+ struct dhcp_state *state = D_STATE(iface);
struct if_options *ifo = iface->options;
int timeout = ifo->timeout;
/* If we're rebooting and we're not daemonised then we need
* to shorten the normal timeout to ensure we try correctly
* for a fallback or IPv4LL address. */
- if (iface->state->state == DHS_REBOOT &&
- !(options & DHCPCD_DAEMONISED))
- {
+ if (state->state == DHS_REBOOT && !(options & DHCPCD_DAEMONISED)) {
timeout -= ifo->reboot;
if (timeout <= 0)
timeout = 2;
}
- iface->state->state = DHS_DISCOVER;
- iface->state->xid = dhcp_xid(iface);
+ state->state = DHS_DISCOVER;
+ state->xid = dhcp_xid(iface);
eloop_timeout_delete(NULL, iface);
if (ifo->fallback)
eloop_timeout_add_sec(timeout, dhcp_fallback, iface);
else if (ifo->options & DHCPCD_IPV4LL &&
- !IN_LINKLOCAL(htonl(iface->state->addr.s_addr)))
+ !IN_LINKLOCAL(htonl(state->addr.s_addr)))
{
- if (IN_LINKLOCAL(htonl(iface->state->fail.s_addr)))
+ if (IN_LINKLOCAL(htonl(state->fail.s_addr)))
eloop_timeout_add_sec(RATE_LIMIT_INTERVAL,
ipv4ll_start, iface);
else
static void
dhcp_request(void *arg)
{
- struct interface *iface = arg;
+ struct interface *ifp = arg;
+ struct dhcp_state *state = D_STATE(ifp);
- iface->state->state = DHS_REQUEST;
- send_request(iface);
+ state->state = DHS_REQUEST;
+ send_request(ifp);
}
static void
dhcp_expire(void *arg)
{
- struct interface *iface = arg;
+ struct interface *ifp = arg;
+ struct dhcp_state *state = D_STATE(ifp);
- iface->state->interval = 0;
- if (iface->state->addr.s_addr == 0) {
+ state->interval = 0;
+ if (state->addr.s_addr == 0) {
/* We failed to reboot, so enter discovery. */
- iface->state->lease.addr.s_addr = 0;
- dhcp_discover(iface);
+ state->lease.addr.s_addr = 0;
+ dhcp_discover(ifp);
return;
}
- syslog(LOG_ERR, "%s: lease expired", iface->name);
- eloop_timeout_delete(NULL, iface);
- dhcp_drop(iface, "EXPIRE");
- unlink(iface->state->leasefile);
- if (iface->carrier != LINK_DOWN)
- start_interface(iface);
+ syslog(LOG_ERR, "%s: lease expired", ifp->name);
+ eloop_timeout_delete(NULL, ifp);
+ dhcp_drop(ifp, "EXPIRE");
+ unlink(state->leasefile);
+ if (ifp->carrier != LINK_DOWN)
+ start_interface(ifp);
}
void
-dhcp_release(struct interface *iface)
+dhcp_release(struct interface *ifp)
{
+ struct dhcp_state *state = D_STATE(ifp);
struct timespec ts;
- if (iface->state->new != NULL &&
- iface->state->new->cookie == htonl(MAGIC_COOKIE))
- {
+ if (state->new != NULL && state->new->cookie == htonl(MAGIC_COOKIE)) {
syslog(LOG_INFO, "%s: releasing lease of %s",
- iface->name, inet_ntoa(iface->state->lease.addr));
- iface->state->xid = dhcp_xid(iface);
- send_message(iface, DHCP_RELEASE, NULL);
+ ifp->name, inet_ntoa(state->lease.addr));
+ state->xid = dhcp_xid(ifp);
+ send_message(ifp, DHCP_RELEASE, NULL);
/* Give the packet a chance to go before dropping the ip */
ts.tv_sec = RELEASE_DELAY_S;
ts.tv_nsec = RELEASE_DELAY_NS;
nanosleep(&ts, NULL);
- dhcp_drop(iface, "RELEASE");
+ dhcp_drop(ifp, "RELEASE");
}
- unlink(iface->state->leasefile);
+ unlink(state->leasefile);
}
void
static void
dhcp_renew(void *arg)
{
- struct interface *iface = arg;
- struct dhcp_lease *lease = &iface->state->lease;
+ struct interface *ifp = arg;
+ struct dhcp_state *state = D_STATE(ifp);
+ struct dhcp_lease *lease = &state->lease;
syslog(LOG_INFO, "%s: renewing lease of %s",
- iface->name, inet_ntoa(lease->addr));
+ ifp->name, inet_ntoa(lease->addr));
syslog(LOG_DEBUG, "%s: rebind in %u seconds, expire in %u seconds",
- iface->name, lease->rebindtime - lease->renewaltime,
+ ifp->name, lease->rebindtime - lease->renewaltime,
lease->leasetime - lease->renewaltime);
- iface->state->state = DHS_RENEW;
- iface->state->xid = dhcp_xid(iface);
- send_renew(iface);
+ state->state = DHS_RENEW;
+ state->xid = dhcp_xid(ifp);
+ send_renew(ifp);
}
static void
dhcp_rebind(void *arg)
{
- struct interface *iface = arg;
- struct dhcp_lease *lease = &iface->state->lease;
+ struct interface *ifp = arg;
+ struct dhcp_state *state = D_STATE(ifp);
+ struct dhcp_lease *lease = &state->lease;
syslog(LOG_ERR, "%s: failed to renew, attempting to rebind",
- iface->name);
+ ifp->name);
syslog(LOG_DEBUG, "%s: expire in %u seconds",
- iface->name, lease->leasetime - lease->rebindtime);
- iface->state->state = DHS_REBIND;
- eloop_timeout_delete(send_renew, iface);
- iface->state->lease.server.s_addr = 0;
- send_rebind(iface);
+ ifp->name, lease->leasetime - lease->rebindtime);
+ state->state = DHS_REBIND;
+ eloop_timeout_delete(send_renew, ifp);
+ state->lease.server.s_addr = 0;
+ send_rebind(ifp);
}
void
dhcp_bind(void *arg)
{
struct interface *iface = arg;
- struct if_state *state = iface->state;
+ struct dhcp_state *state = D_STATE(iface);
struct if_options *ifo = iface->options;
struct dhcp_lease *lease = &state->lease;
struct timeval tv;
}
if (options & DHCPCD_TEST) {
state->reason = "TEST";
- script_run(iface);
+ script_runreason(iface, state->reason);
exit(EXIT_SUCCESS);
}
if (state->reason == NULL) {
static void
dhcp_timeout(void *arg)
{
- struct interface *iface = arg;
+ struct interface *ifp = arg;
+ struct dhcp_state *state = D_STATE(ifp);
- dhcp_bind(iface);
- iface->state->interval = 0;
- dhcp_discover(iface);
+ dhcp_bind(ifp);
+ state->interval = 0;
+ dhcp_discover(ifp);
}
struct dhcp_message *
}
static int
-handle_3rdparty(struct interface *iface)
+handle_3rdparty(struct interface *ifp)
{
struct if_options *ifo;
+ struct dhcp_state *state;
struct in_addr addr, net, dst;
- ifo = iface->options;
+ ifo = ifp->options;
if (ifo->req_addr.s_addr != INADDR_ANY)
return 0;
- if (get_address(iface->name, &addr, &net, &dst) == 1)
- ipv4_handleifa(RTM_NEWADDR, iface->name, &addr, &net, &dst);
+ if (get_address(ifp->name, &addr, &net, &dst) == 1)
+ ipv4_handleifa(RTM_NEWADDR, ifp->name, &addr, &net, &dst);
else {
syslog(LOG_INFO,
"%s: waiting for 3rd party to configure IP address",
- iface->name);
- iface->state->reason = "3RDPARTY";
- script_run(iface);
+ ifp->name);
+ state = D_STATE(ifp);
+ state->reason = "3RDPARTY";
+ script_runreason(ifp, state->reason);
}
return 1;
}
static void
-dhcp_static(struct interface *iface)
+dhcp_static(struct interface *ifp)
{
struct if_options *ifo;
+ struct dhcp_state *state;
- if (handle_3rdparty(iface))
+ if (handle_3rdparty(ifp))
return;
- ifo = iface->options;
- iface->state->offer =
- dhcp_message_new(&ifo->req_addr, &ifo->req_mask);
- eloop_timeout_delete(NULL, iface);
- dhcp_bind(iface);
+ ifo = ifp->options;
+ state = D_STATE(ifp);
+ state->offer = dhcp_message_new(&ifo->req_addr, &ifo->req_mask);
+ eloop_timeout_delete(NULL, ifp);
+ dhcp_bind(ifp);
}
void
-dhcp_inform(struct interface *iface)
+dhcp_inform(struct interface *ifp)
{
+ struct dhcp_state *state;
- if (handle_3rdparty(iface))
+ if (handle_3rdparty(ifp))
return;
+ state = D_STATE(ifp);
if (options & DHCPCD_TEST) {
- iface->state->addr.s_addr = iface->options->req_addr.s_addr;
- iface->state->net.s_addr = iface->options->req_mask.s_addr;
+ state->addr.s_addr = ifp->options->req_addr.s_addr;
+ state->net.s_addr = ifp->options->req_mask.s_addr;
} else {
- iface->options->options |= DHCPCD_STATIC;
- dhcp_static(iface);
+ ifp->options->options |= DHCPCD_STATIC;
+ dhcp_static(ifp);
}
- iface->state->state = DHS_INFORM;
- iface->state->xid = dhcp_xid(iface);
- send_inform(iface);
+ state->state = DHS_INFORM;
+ state->xid = dhcp_xid(ifp);
+ send_inform(ifp);
}
-static void
-dhcp_reboot(struct interface *iface)
+void
+dhcp_reboot(struct interface *ifp, int oldopts)
{
- struct if_options *ifo = iface->options;
+ struct if_options *ifo = ifp->options;
+ struct dhcp_state *state = D_STATE(ifp);
+
+ ifo = ifp->options;
+ state->interval = 0;
+ if ((ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC) &&
+ state->addr.s_addr != ifo->req_addr.s_addr) ||
+ (oldopts & (DHCPCD_INFORM | DHCPCD_STATIC) &&
+ !(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC))))
+ {
+ dhcp_drop(ifp, "EXPIRE");
+ } else {
+ free(state->offer);
+ state->offer = NULL;
+ }
- if (ifo->options & DHCPCD_LINK && iface->carrier == LINK_DOWN) {
- syslog(LOG_INFO, "%s: waiting for carrier", iface->name);
+ if (ifo->options & DHCPCD_LINK && ifp->carrier == LINK_DOWN) {
+ syslog(LOG_INFO, "%s: waiting for carrier", ifp->name);
return;
}
if (ifo->options & DHCPCD_STATIC) {
- dhcp_static(iface);
+ dhcp_static(ifp);
return;
}
- if (ifo->reboot == 0 || iface->state->offer == NULL) {
- dhcp_discover(iface);
+ if (ifo->reboot == 0 || state->offer == NULL) {
+ dhcp_discover(ifp);
return;
}
if (ifo->options & DHCPCD_INFORM) {
syslog(LOG_INFO, "%s: informing address of %s",
- iface->name, inet_ntoa(iface->state->lease.addr));
- } else if (iface->state->offer->cookie == 0) {
+ ifp->name, inet_ntoa(state->lease.addr));
+ } else if (state->offer->cookie == 0) {
if (ifo->options & DHCPCD_IPV4LL) {
- iface->state->claims = 0;
- arp_announce(iface);
+ state->claims = 0;
+ arp_announce(ifp);
} else
- dhcp_discover(iface);
+ dhcp_discover(ifp);
return;
} else {
syslog(LOG_INFO, "%s: rebinding lease of %s",
- iface->name, inet_ntoa(iface->state->lease.addr));
+ ifp->name, inet_ntoa(state->lease.addr));
}
- iface->state->state = DHS_REBOOT;
- iface->state->xid = dhcp_xid(iface);
- iface->state->lease.server.s_addr = 0;
- eloop_timeout_delete(NULL, iface);
+ state->state = DHS_REBOOT;
+ state->xid = dhcp_xid(ifp);
+ state->lease.server.s_addr = 0;
+ eloop_timeout_delete(NULL, ifp);
if (ifo->fallback)
- eloop_timeout_add_sec(ifo->reboot, dhcp_fallback, iface);
- else if (ifo->options & DHCPCD_LASTLEASE &&
- iface->state->lease.frominfo)
- eloop_timeout_add_sec(ifo->reboot, dhcp_timeout, iface);
+ eloop_timeout_add_sec(ifo->reboot, dhcp_fallback, ifp);
+ else if (ifo->options & DHCPCD_LASTLEASE && state->lease.frominfo)
+ eloop_timeout_add_sec(ifo->reboot, dhcp_timeout, ifp);
else if (!(ifo->options & DHCPCD_INFORM &&
options & (DHCPCD_MASTER | DHCPCD_DAEMONISED)))
- eloop_timeout_add_sec(ifo->reboot, dhcp_expire, iface);
+ eloop_timeout_add_sec(ifo->reboot, dhcp_expire, ifp);
/* Don't bother ARP checking as the server could NAK us first. */
if (ifo->options & DHCPCD_INFORM)
- dhcp_inform(iface);
+ dhcp_inform(ifp);
else
- dhcp_request(iface);
+ dhcp_request(ifp);
}
void
dhcp_drop(struct interface *iface, const char *reason)
{
+ struct dhcp_state *state = D_STATE(iface);
+ if (state == NULL)
+ return;
eloop_timeouts_delete(iface, dhcp_expire, NULL);
- free(iface->state->old);
- iface->state->old = iface->state->new;
- iface->state->new = NULL;
- iface->state->reason = reason;
+ free(state->old);
+ state->old = state->new;
+ state->new = NULL;
+ state->reason = reason;
ipv4_applyaddr(iface);
- free(iface->state->old);
- iface->state->old = NULL;
- iface->state->lease.addr.s_addr = 0;
+ free(state->old);
+ state->old = NULL;
+ state->lease.addr.s_addr = 0;
}
static void
dhcp_handle(struct interface *iface, struct dhcp_message **dhcpp,
const struct in_addr *from)
{
- struct if_state *state = iface->state;
+ struct dhcp_state *state = D_STATE(iface);
struct if_options *ifo = iface->options;
struct dhcp_message *dhcp = *dhcpp;
struct dhcp_lease *lease = &state->lease;
log_dhcp(LOG_WARNING, "NAK:", iface, dhcp, from);
if (!(options & DHCPCD_TEST)) {
dhcp_drop(iface, "NAK");
- unlink(iface->state->leasefile);
+ unlink(state->leasefile);
}
dhcp_close(iface);
/* If we constantly get NAKS then we should slowly back off */
state->new = state->offer;
state->offer = NULL;
state->reason = "TEST";
- script_run(iface);
+ script_runreason(iface, state->reason);
exit(EXIT_SUCCESS);
}
eloop_timeout_delete(send_discover, iface);
ssize_t bytes;
struct in_addr from;
int i, partialcsum = 0;
+ const struct dhcp_state *state = D_CSTATE(iface);
/* We loop through until our buffer is empty.
* The benefit is that if we get >1 DHCP packet in our buffer and
continue;
}
if (iface->flags & IFF_POINTOPOINT &&
- iface->state->dst.s_addr != from.s_addr)
+ state->dst.s_addr != from.s_addr)
{
syslog(LOG_WARNING,
"%s: server %s is not destination",
continue;
}
/* Ensure it's the right transaction */
- if (iface->state->xid != ntohl(dhcp->xid)) {
+ if (state->xid != ntohl(dhcp->xid)) {
syslog(LOG_DEBUG,
"%s: wrong xid 0x%x (expecting 0x%x) from %s",
- iface->name, ntohl(dhcp->xid), iface->state->xid,
+ iface->name, ntohl(dhcp->xid), state->xid,
inet_ntoa(from));
continue;
}
continue;
}
dhcp_handle(iface, &dhcp, &from);
- if (iface->state->raw_fd == -1)
+ if (state->raw_fd == -1)
break;
}
free(packet);
dhcp_open(struct interface *ifp)
{
int r = 0;
- struct if_state *ifs;
+ struct dhcp_state *state;
- ifs = ifp->state;
- if (ifs->raw_fd == -1) {
+ state = D_STATE(ifp);
+ if (state->raw_fd == -1) {
if ((r = open_socket(ifp, ETHERTYPE_IP)) == -1)
syslog(LOG_ERR, "%s: %s: %m", __func__, ifp->name);
else
- eloop_event_add(ifs->raw_fd, dhcp_handlepacket, ifp);
+ eloop_event_add(state->raw_fd, dhcp_handlepacket, ifp);
}
- if (ifs->udp_fd == -1 &&
- ifs->addr.s_addr != 0 &&
- ifs->new != NULL &&
- (ifs->new->cookie == htonl(MAGIC_COOKIE) ||
+ if (state->udp_fd == -1 &&
+ state->addr.s_addr != 0 &&
+ state->new != NULL &&
+ (state->new->cookie == htonl(MAGIC_COOKIE) ||
ifp->options->options & DHCPCD_INFORM))
{
if (open_udp_socket(ifp) == -1 && errno != EADDRINUSE) {
return r;
}
+int
+dhcp_dump(const char *ifname)
+{
+ struct interface *ifp;
+ struct dhcp_state *state;
+
+ ifaces = ifp = xzalloc(sizeof(*ifp));
+ ifp->if_data[IF_DATA_DHCP] = state = xzalloc(sizeof(*state));
+ ifp->options = xzalloc(sizeof(*ifp->options));
+ strlcpy(ifp->name, ifname, sizeof(ifp->name));
+ snprintf(state->leasefile, sizeof(state->leasefile),
+ LEASEFILE, ifp->name);
+ strlcpy(ifp->options->script, if_options->script,
+ sizeof(ifp->options->script));
+ state->new = read_lease(ifp);
+ if (state->new == NULL && errno == ENOENT) {
+ strlcpy(state->leasefile, ifname, sizeof(state->leasefile));
+ state->new = read_lease(ifp);
+ }
+ if (state->new == NULL) {
+ if (errno == ENOENT)
+ syslog(LOG_ERR, "%s: no lease to dump", ifname);
+ return -1;
+ }
+ state->reason = "DUMP";
+ return script_runreason(ifp, state->reason);
+}
+
+void
+dhcp_free(struct interface *ifp)
+{
+ struct dhcp_state *state = D_STATE(ifp);
+
+ if (state) {
+ free(state->old);
+ free(state->new);
+ free(state->offer);
+ free(state->buffer);
+ free(state->clientid);
+ free(state);
+ ifp->if_data[IF_DATA_DHCP] = NULL;
+ }
+}
+
+static int
+dhcp_init(struct interface *ifp)
+{
+ struct dhcp_state *state;
+ const struct if_options *ifo;
+ unsigned char *duid;
+ size_t len, ifl;
+
+ state = D_STATE(ifp);
+ if (state == NULL) {
+ ifp->if_data[IF_DATA_DHCP] = calloc(1, sizeof(*state));
+ state = D_STATE(ifp);
+ }
+ if (state == NULL)
+ return -1;
+
+ state->state = DHS_INIT;
+ state->reason = "PREINIT";
+ state->nakoff = 0;
+ snprintf(state->leasefile, sizeof(state->leasefile),
+ LEASEFILE, ifp->name);
+ /* 0 is a valid fd, so init to -1 */
+ state->raw_fd = state->udp_fd = state->arp_fd = -1;
+
+ ifo = ifp->options;
+ /* We need to drop the leasefile so that start_interface
+ * doesn't load it. */
+ if (ifo->options & DHCPCD_REQUEST)
+ unlink(state->leasefile);
+
+ free(state->clientid);
+ state->clientid = NULL;
+
+ if (*ifo->clientid) {
+ state->clientid = xmalloc(ifo->clientid[0] + 1);
+ memcpy(state->clientid, ifo->clientid, ifo->clientid[0] + 1);
+ } else if (ifo->options & DHCPCD_CLIENTID) {
+ len = 0;
+ if (ifo->options & DHCPCD_DUID) {
+ duid = xmalloc(DUID_LEN);
+ if ((len = get_duid(duid, ifp)) == 0)
+ syslog(LOG_ERR, "get_duid: %m");
+ } else
+ duid = NULL;
+ if (len > 0) {
+ state->clientid = xmalloc(len + 6);
+ state->clientid[0] = len + 5;
+ state->clientid[1] = 255; /* RFC 4361 */
+ ifl = strlen(ifp->name);
+ if (ifl < 5) {
+ memcpy(state->clientid + 2, ifp->name, ifl);
+ if (ifl < 4)
+ memset(state->clientid + 2 + ifl,
+ 0, 4 - ifl);
+ } else {
+ ifl = htonl(ifp->index);
+ memcpy(state->clientid + 2, &ifl, 4);
+ }
+ memcpy(state->clientid + 6, duid, len);
+ } else if (len == 0) {
+ len = ifp->hwlen + 1;
+ state->clientid = xmalloc(len + 1);
+ state->clientid[0] = len;
+ state->clientid[1] = ifp->family;
+ memcpy(state->clientid + 2, ifp->hwaddr,
+ ifp->hwlen);
+ }
+ free(duid);
+ }
+ if (ifo->options & DHCPCD_CLIENTID)
+ syslog(LOG_DEBUG, "%s: using ClientID %s", ifp->name,
+ hwaddr_ntoa(state->clientid + 1, state->clientid[0]));
+ else if (ifp->hwlen)
+ syslog(LOG_DEBUG, "%s: using hwaddr %s", ifp->name,
+ hwaddr_ntoa(ifp->hwaddr, ifp->hwlen));
+
+ return 0;
+}
+
void
dhcp_start(struct interface *ifp)
{
struct if_options *ifo = ifp->options;
+ struct dhcp_state *state;
struct stat st;
struct timeval now;
uint32_t l;
if (!(ifo->options & DHCPCD_IPV4))
return;
+ if (dhcp_init(ifp) == -1) {
+ syslog(LOG_ERR, "%s: dhcp_init: %m", ifp->name);
+ return;
+ }
+
+ state = D_STATE(ifp);
+ state->start_uptime = uptime();
+ free(state->offer);
+ state->offer = NULL;
+
+ if (state->arping_index < ifo->arping_len) {
+ arp_start(ifp);
+ return;
+ }
+
if (ifo->options & DHCPCD_STATIC) {
dhcp_static(ifp);
return;
return;
}
/* We don't want to read the old lease if we NAK an old test */
- nolease = ifp->state->offer && options & DHCPCD_TEST;
+ nolease = state->offer && options & DHCPCD_TEST;
if (!nolease)
- ifp->state->offer = read_lease(ifp);
- if (ifp->state->offer) {
- get_lease(&ifp->state->lease, ifp->state->offer);
- ifp->state->lease.frominfo = 1;
- if (ifp->state->offer->cookie == 0) {
- if (ifp->state->offer->yiaddr ==
- ifp->state->addr.s_addr)
- {
- free(ifp->state->offer);
- ifp->state->offer = NULL;
+ state->offer = read_lease(ifp);
+ if (state->offer) {
+ get_lease(&state->lease, state->offer);
+ state->lease.frominfo = 1;
+ if (state->offer->cookie == 0) {
+ if (state->offer->yiaddr == state->addr.s_addr) {
+ free(state->offer);
+ state->offer = NULL;
}
- } else if (ifp->state->lease.leasetime != ~0U &&
- stat(ifp->state->leasefile, &st) == 0)
+ } else if (state->lease.leasetime != ~0U &&
+ stat(state->leasefile, &st) == 0)
{
/* Offset lease times and check expiry */
gettimeofday(&now, NULL);
- if ((time_t)ifp->state->lease.leasetime <
+ if ((time_t)state->lease.leasetime <
now.tv_sec - st.st_mtime)
{
syslog(LOG_DEBUG,
"%s: discarding expired lease",
ifp->name);
- free(ifp->state->offer);
- ifp->state->offer = NULL;
- ifp->state->lease.addr.s_addr = 0;
+ free(state->offer);
+ state->offer = NULL;
+ state->lease.addr.s_addr = 0;
} else {
l = now.tv_sec - st.st_mtime;
- ifp->state->lease.leasetime -= l;
- ifp->state->lease.renewaltime -= l;
- ifp->state->lease.rebindtime -= l;
+ state->lease.leasetime -= l;
+ state->lease.renewaltime -= l;
+ state->lease.rebindtime -= l;
}
}
}
- if (ifp->state->offer == NULL)
+ if (state->offer == NULL)
dhcp_discover(ifp);
- else if (ifp->state->offer->cookie == 0 &&
+ else if (state->offer->cookie == 0 &&
ifp->options->options & DHCPCD_IPV4LL)
ipv4ll_start(ifp);
else
- dhcp_reboot(ifp);
+ dhcp_reboot(ifp, ifp->options->options);
}
#include <arpa/inet.h>
#include <netinet/in.h>
+#include <limits.h>
#include <stdint.h>
#include "common.h"
uint32_t cookie;
};
+enum DHS {
+ DHS_INIT,
+ DHS_DISCOVER,
+ DHS_REQUEST,
+ DHS_BOUND,
+ DHS_RENEW,
+ DHS_REBIND,
+ DHS_REBOOT,
+ DHS_INFORM,
+ DHS_RENEW_REQUESTED,
+ DHS_INIT_IPV4LL,
+ DHS_PROBE
+};
+
+struct dhcp_state {
+ enum DHS state;
+ struct dhcp_message *sent;
+ struct dhcp_message *offer;
+ struct dhcp_message *new;
+ struct dhcp_message *old;
+ struct dhcp_lease lease;
+ const char *reason;
+ time_t interval;
+ time_t nakoff;
+ uint32_t xid;
+ int socket;
+ int probes;
+ int claims;
+ int conflicts;
+ time_t defend;
+ struct in_addr fail;
+ size_t arping_index;
+
+ int raw_fd;
+ int udp_fd;
+ int arp_fd;
+ size_t buffer_size, buffer_len, buffer_pos;
+ unsigned char *buffer;
+
+ struct in_addr addr;
+ struct in_addr net;
+ struct in_addr dst;
+
+ char leasefile[PATH_MAX];
+ time_t start_uptime;
+
+ unsigned char *clientid;
+};
+
+#define D_STATE(ifp) \
+ ((struct dhcp_state *)(ifp)->if_data[IF_DATA_DHCP])
+#define D_CSTATE(ifp) \
+ ((const struct dhcp_state *)(ifp)->if_data[IF_DATA_DHCP])
+
#include "dhcpcd.h"
#include "if-options.h"
#include "net.h"
void dhcp_inform(struct interface *);
void dhcp_release(struct interface *);
void dhcp_bind(void *);
+void dhcp_reboot(struct interface *, int);
void dhcp_close(struct interface *);
+void dhcp_free(struct interface *);
+int dhcp_dump(const char *);
#endif
#include "control.h"
#include "dhcpcd.h"
#include "dhcp6.h"
-#include "duid.h"
#include "eloop.h"
#include "if-options.h"
#include "if-pref.h"
#include "ipv4.h"
-#include "ipv4ll.h"
#include "ipv6.h"
#include "ipv6ns.h"
#include "ipv6rs.h"
#include "script.h"
#include "signals.h"
-/* We should define a maximum for the NAK exponential backoff */
-#define NAKOFF_MAX 60
-
/* Wait N nanoseconds between sending a RELEASE and dropping the address.
* This gives the kernel enough time to actually send it. */
#define RELEASE_DELAY_S 0
char vendor[VENDORCLASSID_MAX_LEN];
int pidfd = -1;
struct interface *ifaces = NULL;
+struct if_options *if_options = NULL;
int ifac = 0;
char **ifav = NULL;
int ifdc = 0;
sigset_t dhcpcd_sigset;
static char *cffile;
-static struct if_options *if_options;
static char *pidfile;
static int linkfd = -1, ipv6rsfd = -1, ipv6nsfd = -1;
static char **ifv;
for (i = 0; i < ifdc; i++)
free(ifdv[i]);
free(ifdv);
- free(packet);
#endif
if (linkfd != -1)
static void
configure_interface1(struct interface *ifp)
{
- struct if_state *ifs = ifp->state;
struct if_options *ifo = ifp->options;
- uint8_t *duid;
- size_t len, ifl;
/* Do any platform specific configuration */
if_conf(ifp);
ifo->options |= DHCPCD_CLIENTID | DHCPCD_BROADCAST;
break;
}
-
- free(ifs->clientid);
- ifs->clientid = NULL;
- if (!(ifo->options & DHCPCD_IPV4))
- return;
-
- if (*ifo->clientid) {
- ifs->clientid = xmalloc(ifo->clientid[0] + 1);
- memcpy(ifs->clientid, ifo->clientid, ifo->clientid[0] + 1);
- } else if (ifo->options & DHCPCD_CLIENTID) {
- len = 0;
- if (ifo->options & DHCPCD_DUID) {
- duid = xmalloc(DUID_LEN);
- if ((len = get_duid(duid, ifp)) == 0)
- syslog(LOG_ERR, "get_duid: %m");
- } else
- duid = NULL;
- if (len > 0) {
- ifs->clientid = xmalloc(len + 6);
- ifs->clientid[0] = len + 5;
- ifs->clientid[1] = 255; /* RFC 4361 */
- ifl = strlen(ifp->name);
- if (ifl < 5) {
- memcpy(ifs->clientid + 2, ifp->name, ifl);
- if (ifl < 4)
- memset(ifs->clientid + 2 + ifl,
- 0, 4 - ifl);
- } else {
- ifl = htonl(ifp->index);
- memcpy(ifs->clientid + 2, &ifl, 4);
- }
- memcpy(ifs->clientid + 6, duid, len);
- } else if (len == 0) {
- len = ifp->hwlen + 1;
- ifs->clientid = xmalloc(len + 1);
- ifs->clientid[0] = len;
- ifs->clientid[1] = ifp->family;
- memcpy(ifs->clientid + 2, ifp->hwaddr,
- ifp->hwlen);
- }
- free(duid);
- }
- if (ifo->options & DHCPCD_CLIENTID)
- syslog(LOG_DEBUG, "%s: using ClientID %s", ifp->name,
- hwaddr_ntoa(ifs->clientid + 1, ifs->clientid[0]));
- else if (ifp->hwlen)
- syslog(LOG_DEBUG, "%s: using hwaddr %s", ifp->name,
- hwaddr_ntoa(ifp->hwaddr, ifp->hwlen));
}
int
goto exit;
}
if (profile != NULL) {
- strlcpy(ifp->state->profile, profile,
- sizeof(ifp->state->profile));
+ strlcpy(ifp->profile, profile, sizeof(ifp->profile));
syslog(LOG_INFO, "%s: selected profile %s",
ifp->name, profile);
} else
- *ifp->state->profile = '\0';
+ *ifp->profile = '\0';
free_options(ifp->options);
ifp->options = ifo;
if (ifp->wireless)
getifssid(ifp->name, ifp->ssid);
configure_interface(ifp, margc, margv);
- ifp->state->interval = 0;
- ifp->state->reason = "CARRIER";
- script_run(ifp);
+ script_runreason(ifp, "CARRIER");
start_interface(ifp);
}
}
return;
}
- ifp->state->start_uptime = uptime();
- free(ifp->state->offer);
- ifp->state->offer = NULL;
-
if (options & DHCPCD_IPV6RS && ifo->options & DHCPCD_IPV6RS &&
!(ifo->options & DHCPCD_INFORM))
ipv6rs_start(ifp);
- if (ifp->state->arping_index < ifo->arping_len) {
- arp_start(ifp);
- return;
- }
-
if (ifo->options & DHCPCD_IPV6) {
if (ifo->options & DHCPCD_INFORM)
nolease = dhcp6_start(ifp, 0);
static void
init_state(struct interface *ifp, int argc, char **argv)
{
- struct if_state *ifs;
-
- if (ifp->state)
- ifs = ifp->state;
- else
- ifs = ifp->state = xzalloc(sizeof(*ifs));
-
- ifs->state = DHS_INIT;
- ifs->reason = "PREINIT";
- ifs->nakoff = 0;
- snprintf(ifs->leasefile, sizeof(ifs->leasefile),
- LEASEFILE, ifp->name);
- /* 0 is a valid fd, so init to -1 */
- ifs->raw_fd = ifs->udp_fd = ifs->arp_fd = -1;
+ const char *reason = NULL;
configure_interface(ifp, argc, argv);
if (!(options & DHCPCD_TEST))
- script_run(ifp);
-
- /* We need to drop the leasefile so that start_interface
- * doesn't load it. */
- if (ifp->options->options & DHCPCD_REQUEST)
- unlink(ifs->leasefile);
+ script_runreason(ifp, "PREINIT");
if (ifp->options->options & DHCPCD_LINK) {
switch (carrier_status(ifp)) {
case 0:
ifp->carrier = LINK_DOWN;
- ifs->reason = "NOCARRIER";
+ reason = "NOCARRIER";
break;
case 1:
ifp->carrier = LINK_UP;
- ifs->reason = "CARRIER";
+ reason = "CARRIER";
break;
default:
ifp->carrier = LINK_UNKNOWN;
return;
}
- if (!(options & DHCPCD_TEST))
- script_run(ifp);
+ if (reason && !(options & DHCPCD_TEST))
+ script_runreason(ifp, reason);
} else
ifp->carrier = LINK_UNKNOWN;
}
static void
if_reboot(struct interface *ifp, int argc, char **argv)
{
- const struct if_options *ifo;
- int opt;
-
- ifo = ifp->options;
- opt = ifo->options;
+ int oldopts;
+
+ oldopts = ifp->options->options;
configure_interface(ifp, argc, argv);
- ifo = ifp->options;
- ifp->state->interval = 0;
- if ((ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC) &&
- ifp->state->addr.s_addr != ifo->req_addr.s_addr) ||
- (opt & (DHCPCD_INFORM | DHCPCD_STATIC) &&
- !(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC))))
- {
- dhcp_drop(ifp, "EXPIRE");
- } else {
- free(ifp->state->offer);
- ifp->state->offer = NULL;
- }
+ dhcp_reboot(ifp, oldopts);
start_interface(ifp);
}
if (ifn) {
if (action)
if_reboot(ifn, argc, argv);
- else if (ifn->state->new)
+ else
ipv4_applyaddr(ifn);
free_interface(ifp);
} else {
case SIGUSR1:
syslog(LOG_INFO, "received SIGUSR, reconfiguring");
for (ifp = ifaces; ifp; ifp = ifp->next)
- if (ifp->state->new)
- ipv4_applyaddr(ifp);
+ ipv4_applyaddr(ifp);
return;
case SIGPIPE:
syslog(LOG_WARNING, "received SIGPIPE");
main(int argc, char **argv)
{
struct interface *iface;
- struct if_state *ifs;
uint16_t family = 0;
int opt, oi = 0, sig = 0, i, control_fd;
size_t len;
syslog(LOG_ERR, "dumplease requires an interface");
exit(EXIT_FAILURE);
}
- ifaces = iface = xzalloc(sizeof(*iface));
- iface->state = ifs = xzalloc(sizeof(*iface->state));
- iface->options = xzalloc(sizeof(*iface->options));
- strlcpy(iface->name, argv[optind], sizeof(iface->name));
- snprintf(ifs->leasefile, sizeof(ifs->leasefile),
- LEASEFILE, iface->name);
- strlcpy(iface->options->script, if_options->script,
- sizeof(iface->options->script));
- iface->state->new = read_lease(iface);
- if (iface->state->new == NULL && errno == ENOENT) {
- strlcpy(ifs->leasefile, argv[optind],
- sizeof(ifs->leasefile));
- iface->state->new = read_lease(iface);
- }
- if (iface->state->new == NULL) {
- if (errno == ENOENT)
- syslog(LOG_ERR, "%s: no lease to dump",
- iface->name);
+ if (dhcp_dump(argv[optind]) == -1)
exit(EXIT_FAILURE);
- }
- iface->state->reason = "DUMP";
- script_run(iface);
exit(EXIT_SUCCESS);
}
#define IF_SSIDSIZE 33
#define PROFILE_LEN 64
-enum DHS {
- DHS_INIT,
- DHS_DISCOVER,
- DHS_REQUEST,
- DHS_BOUND,
- DHS_RENEW,
- DHS_REBIND,
- DHS_REBOOT,
- DHS_INFORM,
- DHS_RENEW_REQUESTED,
- DHS_INIT_IPV4LL,
- DHS_PROBE
-};
-
#define LINK_UP 1
#define LINK_UNKNOWN 0
#define LINK_DOWN -1
#define IF_DATA_DHCP6 2
#define IF_DATA_MAX 3
-struct if_state {
- enum DHS state;
- char profile[PROFILE_LEN];
- struct dhcp_message *sent;
- struct dhcp_message *offer;
- struct dhcp_message *new;
- struct dhcp_message *old;
- struct dhcp_lease lease;
- const char *reason;
- time_t interval;
- time_t nakoff;
- uint32_t xid;
- int socket;
- int probes;
- int claims;
- int conflicts;
- time_t defend;
- struct in_addr fail;
- size_t arping_index;
-
- int raw_fd;
- int udp_fd;
- int arp_fd;
- size_t buffer_size, buffer_len, buffer_pos;
- unsigned char *buffer;
-
- struct in_addr addr;
- struct in_addr net;
- struct in_addr dst;
-
- char leasefile[PATH_MAX];
- time_t start_uptime;
-
- unsigned char *clientid;
-};
-
struct interface {
char name[IF_NAMESIZE];
- struct if_state *state;
- void *if_data[IF_DATA_MAX];
-
unsigned int index;
int flags;
sa_family_t family;
int wireless;
char ssid[IF_SSIDSIZE];
+ char profile[PROFILE_LEN];
struct if_options *options;
-
+ void *if_data[IF_DATA_MAX];
struct interface *next;
};
extern char **ifav;
extern int ifdc;
extern char **ifdv;
+extern struct if_options *if_options;
extern struct interface *ifaces;
pid_t daemonise(void);
{
struct nlmr *nlm;
int retval = 0;
- struct if_state *ifs;
+ struct dhcp_state *state;
nlm = xzalloc(sizeof(*nlm));
nlm->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
nlm->rt.rtm_family = AF_INET;
nlm->rt.rtm_table = RT_TABLE_MAIN;
- ifs = rt->iface->state;
+ state = D_STATE(rt->iface);
if (action == -1 || action == -2)
nlm->rt.rtm_scope = RT_SCOPE_NOWHERE;
else {
nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
/* We only change route metrics for kernel routes */
- if (rt->dest.s_addr == (ifs->addr.s_addr & ifs->net.s_addr) &&
- rt->net.s_addr == ifs->net.s_addr)
+ if (rt->dest.s_addr ==
+ (state->addr.s_addr & state->net.s_addr) &&
+ rt->net.s_addr == state->net.s_addr)
nlm->rt.rtm_protocol = RTPROT_KERNEL;
else
nlm->rt.rtm_protocol = RTPROT_BOOT;
&rt->dest.s_addr, sizeof(rt->dest.s_addr));
if (nlm->rt.rtm_protocol == RTPROT_KERNEL) {
add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_PREFSRC,
- &ifs->addr.s_addr, sizeof(ifs->addr.s_addr));
+ &state->addr.s_addr, sizeof(state->addr.s_addr));
}
/* If destination == gateway then don't add the gateway */
if (rt->dest.s_addr != rt->gate.s_addr ||
#include <sys/types.h>
#include "config.h"
-#include "dhcpcd.h"
+#include "dhcp.h"
#include "if-pref.h"
#include "net.h"
/* Interface comparer for working out ordering. */
static int
-ifcmp(struct interface *si, struct interface *ti)
+ifcmp(const struct interface *si, const struct interface *ti)
{
int sill, till;
+ const struct dhcp_state *sis, *tis;
- if (si->state && !ti->state)
+ sis = D_CSTATE(si);
+ tis = D_CSTATE(ti);
+ if (sis && !tis)
return -1;
- if (!si->state && ti->state)
+ if (!sis && tis)
return 1;
- if (!si->state && !ti->state)
+ if (!sis && !tis)
return 0;
/* If one has a lease and the other not, it takes precedence. */
- if (si->state->new && !ti->state->new)
+ if (sis->new && !tis->new)
return -1;
- if (!si->state->new && ti->state->new)
+ if (!sis->new && tis->new)
return 1;
/* If we are either, they neither have a lease, or they both have.
* We need to check for IPv4LL and make it non-preferred. */
- if (si->state->new && ti->state->new) {
- sill = (si->state->new->cookie == htonl(MAGIC_COOKIE));
- till = (ti->state->new->cookie == htonl(MAGIC_COOKIE));
+ if (sis->new && tis->new) {
+ sill = (sis->new->cookie == htonl(MAGIC_COOKIE));
+ till = (tis->new->cookie == htonl(MAGIC_COOKIE));
if (!sill && till)
return 1;
if (sill && !till)
static int
n_route(struct rt *rt)
{
- struct if_state *s;
+ const struct dhcp_state *s;
/* Don't set default routes if not asked to */
if (rt->dest.s_addr == 0 &&
if (!add_route(rt))
return 0;
if (errno == EEXIST) {
- s = rt->iface->state;
+ s = D_CSTATE(rt->iface);
/* Pretend we added the subnet route */
if (rt->dest.s_addr == (s->addr.s_addr & s->net.s_addr) &&
rt->net.s_addr == s->net.s_addr &&
add_subnet_route(struct rt *rt, const struct interface *iface)
{
struct rt *r;
- struct if_state *s;
+ const struct dhcp_state *s;
- s = iface->state;
+ s = D_CSTATE(iface);
if (s->net.s_addr == INADDR_BROADCAST ||
s->net.s_addr == INADDR_ANY ||
(iface->options->options &
return nrt;
}
- return get_option_routes(ifp, ifp->state->new);
+ return get_option_routes(ifp, D_STATE(ifp)->new);
}
/* Some DHCP servers add set host routes by setting the gateway
struct rt *r;
for (r = rt; r; r = r->next) {
- if (r->gate.s_addr == ifp->state->addr.s_addr &&
+ if (r->gate.s_addr == D_CSTATE(ifp)->addr.s_addr &&
r->net.s_addr == INADDR_BROADCAST)
r->gate.s_addr = r->dest.s_addr;
}
r = xmalloc(sizeof(*r));
r->dest.s_addr = INADDR_ANY;
r->net.s_addr = INADDR_ANY;
- r->gate.s_addr = iface->state->dst.s_addr;
+ r->gate.s_addr = D_CSTATE(iface)->dst.s_addr;
r->next = rt;
return r;
}
{
struct rt *nrs = NULL, *dnr, *or, *rt, *rtn, *rtl, *lrt = NULL;
struct interface *ifp;
+ const struct dhcp_state *state;
for (ifp = ifaces; ifp; ifp = ifp->next) {
- if (ifp->state->new == NULL)
+ state = D_CSTATE(ifp);
+ if (state == NULL || state->new == NULL)
continue;
dnr = get_routes(ifp);
dnr = massage_host_routes(dnr, ifp);
/* Is this route already in our table? */
if ((find_route(nrs, rt, NULL, NULL)) != NULL)
continue;
- rt->src.s_addr = ifp->state->addr.s_addr;
+ rt->src.s_addr = state->addr.s_addr;
/* Do we already manage it? */
if ((or = find_route(routes, rt, &rtl, NULL))) {
if (or->iface != ifp ||
- or->src.s_addr != ifp->state->addr.s_addr ||
+ or->src.s_addr != state->addr.s_addr ||
rt->gate.s_addr != or->gate.s_addr ||
rt->metric != or->metric)
{
{
int retval;
struct if_options *ifo;
+ struct dhcp_state *state;
+ state = D_STATE(iface);
ifo = iface->options;
if (ifo->options & DHCPCD_INFORM ||
(ifo->options & DHCPCD_STATIC && ifo->req_addr.s_addr == 0))
return 0;
syslog(LOG_DEBUG, "%s: deleting IP address %s/%d",
- iface->name,
- inet_ntoa(iface->state->addr),
- inet_ntocidr(iface->state->net));
- retval = del_address(iface, &iface->state->addr, &iface->state->net);
+ iface->name, inet_ntoa(state->addr), inet_ntocidr(state->net));
+ retval = del_address(iface, &state->addr, &state->net);
if (retval == -1 && errno != EADDRNOTAVAIL)
syslog(LOG_ERR, "del_address: %m");
- iface->state->addr.s_addr = 0;
- iface->state->net.s_addr = 0;
+ state->addr.s_addr = 0;
+ state->net.s_addr = 0;
return retval;
}
void
ipv4_applyaddr(void *arg)
{
- struct interface *iface = arg;
- struct dhcp_message *dhcp = iface->state->new;
- struct dhcp_lease *lease = &iface->state->lease;
- struct if_options *ifo = iface->options;
+ struct interface *ifp = arg;
+ struct dhcp_state *state = D_STATE(ifp);
+ struct dhcp_message *dhcp;
+ struct dhcp_lease *lease;
+ struct if_options *ifo = ifp->options;
struct rt *rt;
/* As we are now adjusting an interface, we need to ensure
* we have them in the right order for routing and configuration. */
sort_interfaces();
+ if (state == NULL)
+ return;
+ dhcp = state->new;
+ lease = &state->lease;
+
if (dhcp == NULL) {
if (!(ifo->options & DHCPCD_PERSISTENT)) {
ipv4_buildroutes();
- if (iface->state->addr.s_addr != 0)
- delete_address(iface);
- script_run(iface);
+ if (state->addr.s_addr != 0)
+ delete_address(ifp);
+ script_runreason(ifp, state->reason);
}
return;
}
/* This also changes netmask */
if (!(ifo->options & DHCPCD_INFORM) ||
- !has_address(iface->name, &lease->addr, &lease->net))
+ !has_address(ifp->name, &lease->addr, &lease->net))
{
syslog(LOG_DEBUG, "%s: adding IP address %s/%d",
- iface->name, inet_ntoa(lease->addr),
+ ifp->name, inet_ntoa(lease->addr),
inet_ntocidr(lease->net));
- if (add_address(iface,
+ if (add_address(ifp,
&lease->addr, &lease->net, &lease->brd) == -1 &&
errno != EEXIST)
{
}
/* Now delete the old address if different */
- if (iface->state->addr.s_addr != lease->addr.s_addr &&
- iface->state->addr.s_addr != 0)
- delete_address(iface);
+ if (state->addr.s_addr != lease->addr.s_addr &&
+ state->addr.s_addr != 0)
+ delete_address(ifp);
- iface->state->addr.s_addr = lease->addr.s_addr;
- iface->state->net.s_addr = lease->net.s_addr;
+ state->addr.s_addr = lease->addr.s_addr;
+ state->net.s_addr = lease->net.s_addr;
/* We need to delete the subnet route to have our metric or
* prefer the interface. */
rt = get_subnet_route(dhcp);
if (rt != NULL) {
- rt->iface = iface;
+ rt->iface = ifp;
rt->metric = 0;
if (!find_route(routes, rt, NULL, NULL))
del_route(rt);
}
ipv4_buildroutes();
- if (!iface->state->lease.frominfo &&
+ if (!state->lease.frominfo &&
!(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC)))
- if (write_lease(iface, dhcp) == -1)
+ if (write_lease(ifp, dhcp) == -1)
syslog(LOG_ERR, "%s: write_lease: %m", __func__);
- script_run(iface);
+ script_runreason(ifp, state->reason);
}
void
{
struct interface *ifp;
struct if_options *ifo;
+ struct dhcp_state *state;
int i;
if (addr->s_addr == INADDR_ANY)
if (ifp == NULL)
return;
+ state = D_STATE(ifp);
if (type == RTM_DELADDR) {
- if (ifp->state->new &&
- ifp->state->new->yiaddr == addr->s_addr)
+ if (state->new &&
+ state->new->yiaddr == addr->s_addr)
syslog(LOG_INFO, "%s: removing IP address %s/%d",
- ifp->name, inet_ntoa(ifp->state->lease.addr),
- inet_ntocidr(ifp->state->lease.net));
+ ifp->name, inet_ntoa(state->lease.addr),
+ inet_ntocidr(state->lease.net));
return;
}
ifo->req_addr.s_addr != INADDR_ANY)
return;
- free(ifp->state->old);
- ifp->state->old = ifp->state->new;
- ifp->state->new = dhcp_message_new(addr, net);
- ifp->state->dst.s_addr = dst ? dst->s_addr : INADDR_ANY;
+ free(state->old);
+ state->old = state->new;
+ state->new = dhcp_message_new(addr, net);
+ state->dst.s_addr = dst ? dst->s_addr : INADDR_ANY;
if (dst) {
for (i = 1; i < 255; i++)
if (i != DHO_ROUTER && has_option_mask(ifo->dstmask,i))
- dhcp_message_add_addr(ifp->state->new, i, *dst);
+ dhcp_message_add_addr(state->new, i, *dst);
}
- ifp->state->reason = "STATIC";
+ state->reason = "STATIC";
ipv4_buildroutes();
- script_run(ifp);
+ script_runreason(ifp, state->reason);
if (ifo->options & DHCPCD_INFORM) {
- ifp->state->state = DHS_INFORM;
- ifp->state->xid = dhcp_xid(ifp);
- ifp->state->lease.server.s_addr =
- dst ? dst->s_addr : INADDR_ANY;
- ifp->state->addr = *addr;
- ifp->state->net = *net;
+ state->state = DHS_INFORM;
+ state->xid = dhcp_xid(ifp);
+ state->lease.server.s_addr = dst ? dst->s_addr : INADDR_ANY;
+ state->addr = *addr;
+ state->net = *net;
dhcp_inform(ifp);
}
}
#include "arp.h"
#include "common.h"
-#include "dhcpcd.h"
+#include "dhcp.h"
#include "eloop.h"
#include "if-options.h"
#include "ipv4ll.h"
ipv4ll_start(void *arg)
{
struct interface *ifp = arg;
+ struct dhcp_state *state = D_STATE(ifp);
uint32_t addr;
eloop_timeout_delete(NULL, ifp);
- ifp->state->probes = 0;
- ifp->state->claims = 0;
- if (ifp->state->addr.s_addr) {
- ifp->state->conflicts = 0;
- if (IN_LINKLOCAL(htonl(ifp->state->addr.s_addr))) {
+ state->probes = 0;
+ state->claims = 0;
+ if (state->addr.s_addr) {
+ state->conflicts = 0;
+ if (IN_LINKLOCAL(htonl(state->addr.s_addr))) {
arp_announce(ifp);
return;
}
}
- if (ifp->state->offer == NULL)
+ if (state->offer == NULL)
addr = 0;
else {
- addr = ifp->state->offer->yiaddr;
- free(ifp->state->offer);
+ addr = state->offer->yiaddr;
+ free(state->offer);
}
/* We maybe rebooting an IPv4LL address. */
if (!IN_LINKLOCAL(htonl(addr))) {
addr = 0;
}
if (addr == 0)
- ifp->state->offer = ipv4ll_find_lease(addr);
+ state->offer = ipv4ll_find_lease(addr);
else
- ifp->state->offer = ipv4ll_make_lease(addr);
- ifp->state->lease.frominfo = 0;
+ state->offer = ipv4ll_make_lease(addr);
+ state->lease.frominfo = 0;
arp_probe(ifp);
}
ipv4ll_handle_failure(void *arg)
{
struct interface *ifp = arg;
+ struct dhcp_state *state = D_STATE(ifp);
time_t up;
- if (ifp->state->fail.s_addr == ifp->state->addr.s_addr) {
+ if (state->fail.s_addr == state->addr.s_addr) {
up = uptime();
- if (ifp->state->defend + DEFEND_INTERVAL > up) {
+ if (state->defend + DEFEND_INTERVAL > up) {
syslog(LOG_DEBUG,
"%s: IPv4LL %d second defence failed",
ifp->name, DEFEND_INTERVAL);
dhcp_drop(ifp, "EXPIRE");
- ifp->state->conflicts = -1;
+ state->conflicts = -1;
} else {
syslog(LOG_DEBUG, "%s: defended IPv4LL address",
ifp->name);
- ifp->state->defend = up;
+ state->defend = up;
return;
}
}
dhcp_close(ifp);
- free(ifp->state->offer);
- ifp->state->offer = NULL;
+ free(state->offer);
+ state->offer = NULL;
eloop_timeout_delete(NULL, ifp);
- if (++ifp->state->conflicts > MAX_CONFLICTS) {
+ if (++state->conflicts > MAX_CONFLICTS) {
syslog(LOG_ERR, "%s: failed to acquire an IPv4LL address",
ifp->name);
- ifp->state->interval = RATE_LIMIT_INTERVAL / 2;
+ state->interval = RATE_LIMIT_INTERVAL / 2;
dhcp_discover(ifp);
} else {
eloop_timeout_add_sec(PROBE_WAIT, ipv4ll_start, ifp);
};
int
-open_socket(struct interface *iface, int protocol)
+open_socket(struct interface *ifp, int protocol)
{
int s;
union sockunion {
} su;
struct sock_fprog pf;
int *fd;
+ struct dhcp_state *state;
#ifdef PACKET_AUXDATA
int n;
#endif
memset(&su, 0, sizeof(su));
su.sll.sll_family = PF_PACKET;
su.sll.sll_protocol = htons(protocol);
- su.sll.sll_ifindex = iface->index;
+ su.sll.sll_ifindex = ifp->index;
/* Install the DHCP filter */
memset(&pf, 0, sizeof(pf));
if (protocol == ETHERTYPE_ARP) {
goto eexit;
if (bind(s, &su.sa, sizeof(su)) == -1)
goto eexit;
+ state = D_STATE(ifp);
if (protocol == ETHERTYPE_ARP)
- fd = &iface->state->arp_fd;
+ fd = &state->arp_fd;
else
- fd = &iface->state->raw_fd;
+ fd = &state->raw_fd;
if (*fd != -1)
close(*fd);
*fd = s;
}
ssize_t
-send_raw_packet(const struct interface *iface, int protocol,
+send_raw_packet(const struct interface *ifp, int protocol,
const void *data, ssize_t len)
{
+ const struct dhcp_state *state;
union sockunion {
struct sockaddr sa;
struct sockaddr_ll sll;
memset(&su, 0, sizeof(su));
su.sll.sll_family = AF_PACKET;
su.sll.sll_protocol = htons(protocol);
- su.sll.sll_ifindex = iface->index;
- su.sll.sll_hatype = htons(iface->family);
- su.sll.sll_halen = iface->hwlen;
- if (iface->family == ARPHRD_INFINIBAND)
+ su.sll.sll_ifindex = ifp->index;
+ su.sll.sll_hatype = htons(ifp->family);
+ su.sll.sll_halen = ifp->hwlen;
+ if (ifp->family == ARPHRD_INFINIBAND)
memcpy(&su.sll.sll_addr,
&ipv4_bcast_addr, sizeof(ipv4_bcast_addr));
else
- memset(&su.sll.sll_addr, 0xff, iface->hwlen);
+ memset(&su.sll.sll_addr, 0xff, ifp->hwlen);
+ state = D_CSTATE(ifp);
if (protocol == ETHERTYPE_ARP)
- fd = iface->state->arp_fd;
+ fd = state->arp_fd;
else
- fd = iface->state->raw_fd;
+ fd = state->raw_fd;
return sendto(fd, data, len, 0, &su.sa, sizeof(su));
}
ssize_t
-get_raw_packet(struct interface *iface, int protocol,
+get_raw_packet(struct interface *ifp, int protocol,
void *data, ssize_t len, int *partialcsum)
{
struct iovec iov = {
.msg_iov = &iov,
.msg_iovlen = 1,
};
+ struct dhcp_state *state;
#ifdef PACKET_AUXDATA
unsigned char cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
struct cmsghdr *cmsg;
msg.msg_controllen = sizeof(cmsgbuf);
#endif
+ state = D_STATE(ifp);
if (protocol == ETHERTYPE_ARP)
- fd = iface->state->arp_fd;
+ fd = state->arp_fd;
else
- fd = iface->state->raw_fd;
+ fd = state->raw_fd;
bytes = recvmsg(fd, &msg, 0);
if (bytes == -1)
return errno == EAGAIN ? 0 : -1;
if (ifp == NULL)
return;
+ dhcp_free(ifp);
dhcp6_free(ifp);
ipv6rs_free(ifp);
free_options(ifp->options);
- if (ifp->state) {
- free(ifp->state->old);
- free(ifp->state->new);
- free(ifp->state->offer);
- free(ifp->state->buffer);
- free(ifp->state->clientid);
- free(ifp->state);
- }
free(ifp);
}
int s;
struct sockaddr_in sin;
int n;
+ struct dhcp_state *state;
#ifdef SO_BINDTODEVICE
struct ifreq ifr;
char *p;
n = 1;
if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n)) == -1)
goto eexit;
+ state = D_STATE(iface);
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(DHCP_CLIENT_PORT);
- sin.sin_addr.s_addr = iface->state->addr.s_addr;
+ sin.sin_addr.s_addr = state->addr.s_addr;
if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) == -1)
goto eexit;
- iface->state->udp_fd = s;
+ state->udp_fd = s;
set_cloexec(s);
return 0;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = to.s_addr;
sin.sin_port = htons(DHCP_SERVER_PORT);
- return sendto(iface->state->udp_fd, data, len, 0,
+ return sendto(D_CSTATE(iface)->udp_fd, data, len, 0,
(struct sockaddr *)&sin, sizeof(sin));
}
const struct if_options *ifo = ifp->options;
const struct interface *ifp2;
int dhcp, dhcp6, ra;
+ const struct dhcp_state *state;
const struct dhcp6_state *d6_state;
dhcp = dhcp6 = ra = 0;
- d6_state = D6_STATE(ifp);
+ state = D_STATE(ifp);
+ d6_state = D6_CSTATE(ifp);
if (strcmp(reason, "TEST") == 0) {
if (d6_state && d6_state->new)
dhcp6 = 1;
if (strcmp(reason, "TEST") == 0) {
env[8] = strdup("if_up=false");
env[9] = strdup("if_down=false");
- } else if ((dhcp && ifp->state->new) ||
- (dhcp6 && d6_state->new) ||
+ } else if ((dhcp && state && state->new) ||
+ (dhcp6 && d6_state && d6_state->new) ||
(ra && ipv6rs_has_ra(ifp)))
{
env[8] = strdup("if_up=true");
env[8] = strdup("if_up=false");
env[9] = strdup("if_down=true");
}
- if (*ifp->state->profile) {
- e = strlen("profile=") + strlen(ifp->state->profile) + 2;
+ if (*ifp->profile) {
+ e = strlen("profile=") + strlen(ifp->profile) + 2;
env[elen] = xmalloc(e);
- snprintf(env[elen++], e, "profile=%s", ifp->state->profile);
+ snprintf(env[elen++], e, "profile=%s", ifp->profile);
}
if (ifp->wireless) {
e = strlen("new_ssid=") + strlen(ifp->ssid) + 2;
- if (ifp->state->new != NULL ||
- strcmp(ifp->state->reason, "CARRIER") == 0)
- {
+ if (strcmp(reason, "CARRIER") == 0) {
env = xrealloc(env, sizeof(char *) * (elen + 2));
env[elen] = xmalloc(e);
snprintf(env[elen++], e, "new_ssid=%s", ifp->ssid);
}
- if (ifp->state->old != NULL ||
- strcmp(ifp->state->reason, "NOCARRIER") == 0)
- {
+ else if (strcmp(reason, "NOCARRIER") == 0) {
env = xrealloc(env, sizeof(char *) * (elen + 2));
env[elen] = xmalloc(e);
snprintf(env[elen++], e, "old_ssid=%s", ifp->ssid);
}
}
- if (dhcp && ifp->state->old) {
- e = configure_env(NULL, NULL, ifp->state->old, ifp);
+ if (dhcp && state && state->old) {
+ e = configure_env(NULL, NULL, state->old, ifp);
if (e > 0) {
env = xrealloc(env, sizeof(char *) * (elen + e + 1));
elen += configure_env(env + elen, "old",
- ifp->state->old, ifp);
+ state->old, ifp);
}
append_config(&env, &elen, "old",
(const char *const *)ifo->config);
}
- if (dhcp6 && d6_state->old) {
+ if (dhcp6 && d6_state && d6_state->old) {
e = dhcp6_env(NULL, NULL, ifp,
d6_state->old, d6_state->old_len);
if (e > 0) {
}
dumplease:
- if (dhcp && ifp->state->new) {
- e = configure_env(NULL, NULL, ifp->state->new, ifp);
+ if (dhcp && state && state->new) {
+ e = configure_env(NULL, NULL, state->new, ifp);
if (e > 0) {
env = xrealloc(env, sizeof(char *) * (elen + e + 1));
elen += configure_env(env + elen, "new",
- ifp->state->new, ifp);
+ state->new, ifp);
}
append_config(&env, &elen, "new",
(const char *const *)ifo->config);
}
- if (dhcp6 && d6_state->new) {
+ if (dhcp6 && d6_state && d6_state->new) {
e = dhcp6_env(NULL, NULL, ifp,
d6_state->new, d6_state->new_len);
if (e > 0) {
send_interface(int fd, const struct interface *iface)
{
int retval = 0;
- if (send_interface1(fd, iface, iface->state->reason) == -1)
+ const struct dhcp_state *state = D_CSTATE(iface);
+
+ if (state && send_interface1(fd, iface, state->reason) == -1)
retval = -1;
if (ipv6rs_has_ra(iface)) {
if (send_interface1(fd, iface, "ROUTERADVERT") == -1)
strcmp(ifp->options->script, "/dev/null") == 0)
return 0;
- if (reason == NULL)
- reason = ifp->state->reason;
+ if (reason == NULL) {
+ const struct dhcp_state *state = D_CSTATE(ifp);
+ if (state)
+ reason = state->reason;
+ }
syslog(LOG_DEBUG, "%s: executing `%s', reason %s",
ifp->name, argv[0], reason);
int send_interface(int, const struct interface *);
int script_runreason(const struct interface *, const char *);
-#define script_run(ifp) script_runreason(ifp, (ifp)->state->reason);
#endif