static volatile int do_signal = 0;
static int urandom_fd = -1;
-static bool bound = false;
+static bool bound = false, allow_slaac_only = true;
int main(_unused int argc, char* const argv[])
bool help = false, daemonize = false;
int c, request_pd = 0;
- while ((c = getopt(argc, argv, "N:P:c:r:s:hdp:")) != -1) {
+ while ((c = getopt(argc, argv, "SN:P:c:r:s:hdp:")) != -1) {
switch (c) {
+ case 'S':
+ allow_slaac_only = false;
+ break;
+
case 'N':
if (!strcmp(optarg, "force"))
ia_na_mode = IA_MODE_FORCE;
break;
case 'P':
+ allow_slaac_only = false;
request_pd = strtoul(optarg, NULL, 10);
if (request_pd == 0)
request_pd = -1;
do_signal = 0;
int res = dhcpv6_request(DHCPV6_MSG_SOLICIT);
+ odhcp6c_signal_process();
if (res < 0) {
continue; // Might happen if we got a signal
do_signal = 0;
res = dhcpv6_request(DHCPV6_MSG_INFO_REQ);
+ odhcp6c_signal_process();
if (do_signal == SIGUSR1)
continue;
else if (res < 0)
if (dhcpv6_request(DHCPV6_MSG_REQUEST) < 0)
continue;
+ odhcp6c_signal_process();
script_call("bound");
bound = true;
// Renew Cycle
// Wait for T1 to expire or until we get a reconfigure
int res = dhcpv6_poll_reconfigure();
+ odhcp6c_signal_process();
if (res >= 0) {
if (res > 0)
script_call("updated");
r = dhcpv6_request(DHCPV6_MSG_REQUEST);
else
r = dhcpv6_request(DHCPV6_MSG_RENEW);
+ odhcp6c_signal_process();
if (r > 0) // Publish updates
script_call("updated");
if (r >= 0)
// If we have IAs, try rebind otherwise restart
res = dhcpv6_request(DHCPV6_MSG_REBIND);
+ odhcp6c_signal_process();
odhcp6c_get_state(STATE_IA_PD, &ia_pd_new);
odhcp6c_get_state(STATE_IA_NA, &ia_na_new);
const char buf[] =
"Usage: odhcp6c [options] <interface>\n"
"\nFeature options:\n"
+ " -S Don't allow SLAAC-only (implied by -P)\n"
" -N <mode> Mode for requesting addresses [try|force|none]\n"
" -P <length> Request IPv6-Prefix (0 = auto)\n"
" -c <clientid> Override client-ID (base-16 encoded)\n"
{
if (len == 0)
return state_data[state] + state_len[state];
+ else if (state_len[state] + len > 1024)
+ return NULL;
uint8_t *n = realloc(state_data[state], state_len[state] + len);
if (n || state_len[state] + len == 0) {
do_signal = 0;
bool updated = ra_process();
updated |= ra_rtnl_process();
- if (updated && bound) {
+ if (updated && (bound || allow_slaac_only)) {
odhcp6c_expire();
script_call("ra-updated");
}
}
-void odhcp6c_update_entry_safe(enum odhcp6c_state state, const struct odhcp6c_entry *new, uint32_t safe)
+void odhcp6c_update_entry_safe(enum odhcp6c_state state, struct odhcp6c_entry *new, uint32_t safe)
{
size_t len;
struct odhcp6c_entry *x = odhcp6c_find_entry(state, new);
struct odhcp6c_entry *start = odhcp6c_get_state(state, &len);
if (x && x->valid > new->valid && new->valid < safe)
- return;
+ new->valid = safe;
if (new->valid > 0) {
- if (x)
- *x = *new;
- else
+ if (x) {
+ x->valid = new->valid;
+ x->preferred = new->preferred;
+ } else {
odhcp6c_add_state(state, new, sizeof(*new));
+ }
} else if (x) {
odhcp6c_remove_state(state, (x - start) * sizeof(*x), sizeof(*x));
}
}
-void odhcp6c_update_entry(enum odhcp6c_state state, const struct odhcp6c_entry *new)
+void odhcp6c_update_entry(enum odhcp6c_state state, struct odhcp6c_entry *new)
{
odhcp6c_update_entry_safe(state, new, 0);
}
odhcp6c_expire_list(STATE_RA_PREFIX, elapsed);
odhcp6c_expire_list(STATE_RA_ROUTE, elapsed);
+ odhcp6c_expire_list(STATE_RA_DNS, elapsed);
odhcp6c_expire_list(STATE_IA_NA, elapsed);
odhcp6c_expire_list(STATE_IA_PD, elapsed);
}