drop_config(struct if_state *state, const char *reason,
const struct options *options)
{
- configure(state->interface, reason, NULL, state->new,
- &state->lease, options, 0);
- free(state->old);
- state->old = NULL;
- free(state->new);
- state->new = NULL;
-
+ if (state->new) {
+ configure(state->interface, reason, NULL, state->new,
+ &state->lease, options, 0);
+ free(state->old);
+ state->old = NULL;
+ free(state->new);
+ state->new = NULL;
+ }
state->lease.addr.s_addr = 0;
}
case STATE_INIT:
do_socket(state, SOCKET_OPEN);
state->xid = arc4random();
- state->nakoff = 1;
iface->start_uptime = uptime();
break;
}
struct in_addr server;
int r;
- server.s_addr = dhcp->yiaddr;
- addr = xstrdup(inet_ntoa(server));
+ if (strcmp(msg, "NAK:") == 0)
+ addr = get_option_string(dhcp, DHCP_MESSAGE);
+ else {
+ server.s_addr = dhcp->yiaddr;
+ addr = xstrdup(inet_ntoa(server));
+ }
r = get_option_addr(&server.s_addr, dhcp, DHCP_SERVERID);
if (dhcp->servername[0] && r == 0)
logger(lvl, "%s %s from %s `%s'", msg,
struct dhcp_message *dhcp = *dhcpp;
struct interface *iface = state->interface;
struct dhcp_lease *lease = &state->lease;
- char *addr;
uint8_t type;
if (get_option_uint8(&type, dhcp, DHCP_MESSAGETYPE) == -1) {
/* We should restart on a NAK */
if (type == DHCP_NAK) {
- addr = get_option_string(dhcp, DHCP_MESSAGE);
- log_dhcp(LOG_WARNING, "NAK for", dhcp);
- free(addr);
- free(dhcp);
+ log_dhcp(LOG_WARNING, "NAK:", dhcp);
+ drop_config(state, "EXPIRE", options);
+ do_socket(state, SOCKET_CLOSED);
state->state = STATE_INIT;
- timerclear(&state->timeout);
- lease->addr.s_addr = 0;
-
/* If we constantly get NAKS then we should slowly back off */
- if (state->nakoff > 0) {
+ if (state->nakoff == 0) {
+ state->nakoff = 1;
+ timerclear(&state->timeout);
+ } else {
tv.tv_sec = state->nakoff;
tv.tv_usec = 0;
state->nakoff *= 2;
if (state->nakoff > NAKOFF_MAX)
state->nakoff = NAKOFF_MAX;
- get_time(&state->stop);
- timeradd(&state->stop, &tv, &state->stop);
- } else
- timerclear(&state->stop);
-
+ get_time(&state->timeout);
+ timeradd(&state->timeout, &tv, &state->timeout);
+ }
return 0;
}
if (state->options & DHCPCD_TEST) {
exec_script(options, iface->name, "TEST", dhcp, NULL);
- free(dhcp);
return 0;
}
- free(dhcp);
state->state = STATE_REQUESTING;
timerclear(&state->timeout);
- return 0;
+ return 1;
}
if (type == DHCP_OFFER) {
log_dhcp(LOG_INFO, "ignoring offer of", dhcp);
- free(dhcp);
return 0;
}
/* We should only be dealing with acks */
if (type != DHCP_ACK) {
log_dhcp(LOG_ERR, "not ACK or OFFER", dhcp);
- free(dhcp);
return 0;
}
state->probes = 0;
state->conflicts = 0;
timerclear(&state->stop);
- return 0;
+ return 1;
}
#endif
{
uint8_t *packet;
struct interface *iface = state->interface;
- struct dhcp_message *dhcp;
+ struct dhcp_message *dhcp = NULL;
const uint8_t *pp;
uint8_t *p;
ssize_t bytes;
* The benefit is that if we get >1 DHCP packet in our buffer and
* the first one fails for any reason, we can use the next. */
packet = xmalloc(udp_dhcp_len);
- dhcp = xmalloc(sizeof(*dhcp));
for(;;) {
bytes = get_raw_packet(iface, ETHERTYPE_IP,
packet, udp_dhcp_len);
logger(LOG_ERR, "packet greater than DHCP size");
continue;
}
+ if (!dhcp)
+ dhcp = xmalloc(sizeof(*dhcp));
memcpy(dhcp, pp, bytes);
if (dhcp->cookie != htonl(MAGIC_COOKIE)) {
logger(LOG_DEBUG, "bogus cookie, ignoring");
if (*p != DHCP_END)
*++p = DHCP_END;
}
- free(packet);
- if (handle_dhcp(state, &dhcp, options) == 0) {
- /* Fake the fact we forked so we return 0 to userland */
- if (state->options & DHCPCD_TEST)
- state->options |= DHCPCD_FORKED;
- else
- return 0;
- }
- if (state->options & DHCPCD_FORKED)
- return -1;
+ retval = handle_dhcp(state, &dhcp, options);
+ if (retval == 0 && state->options & DHCPCD_TEST)
+ state->options |= DHCPCD_FORKED;
+ break;
}
free(packet);
retval = handle_link(state);
} else if (fd_hasdata(iface->raw_fd) == 1) {
retval = handle_dhcp_packet(state, options);
- if (retval == 0 &&
- (state->state == STATE_REQUESTING ||
- state->state == STATE_INIT ||
- state->state == STATE_PROBING))
- /* Fallthrough to handle_timeout */
- continue;
#ifdef ENABLE_ARP
} else if (fd_hasdata(iface->arp_fd) == 1) {
retval = handle_arp_packet(state);