offsetof(struct device_prefix, addr));
}
-static int
-prefix_assignment_cmp(const void *k1, const void *k2, void *ptr)
-{
- return strcmp((const char*)k1, (const char*)k2);
-}
-
static void
interface_handle_subnet_route(struct interface *iface, struct device_addr *addr, bool add)
{
addr.valid_until = assignment->prefix->valid_until;
if (!add) {
- if (assignment->enabled)
- system_del_address(l3_downlink, &addr);
+ if (assignment->enabled) {
+ time_t now = system_get_rtime();
+ addr.preferred_until = now;
+ if (addr.valid_until - now > 7200)
+ addr.valid_until = now + 7200;
+ system_add_address(l3_downlink, &addr);
+ }
} else {
system_add_address(l3_downlink, &addr);
} else if (node_old) {
if (iface)
interface_set_prefix_address(iface, false, old);
- free(old->name);
free(old);
} else if (node_new) {
struct device_prefix *prefix = new->prefix;
interface_ip_set_prefix_assignment(struct device_prefix *prefix,
struct interface *iface, uint8_t length)
{
+ struct device_prefix_assignment *assignment;
+
if (!length || length > 64) {
- struct device_prefix_assignment *assignment = vlist_find(
- prefix->assignments, &iface, assignment, node);
+ assignment = vlist_find(prefix->assignments, iface->name, assignment, node);
if (assignment)
interface_set_prefix_address(iface, false, assignment);
} else {
- uint8_t length = iface->proto_ip.assignment_length;
uint64_t want = 1ULL << (64 - length);
+ char *name;
+
if (prefix->avail < want && prefix->avail > 0) {
do {
want = 1ULL << (64 - ++length);
if (prefix->avail < want)
return;
- // Assignment
- struct device_prefix_assignment *assignment = calloc(1, sizeof(*assignment));
+ assignment = calloc_a(sizeof(*assignment),
+ &name, strlen(iface->name) + 1);
assignment->prefix = prefix;
assignment->length = length;
- assignment->name = strdup(iface->name);
+ assignment->name = strcpy(name, iface->name);
vlist_add(prefix->assignments, &assignment->node, assignment->name);
}
// Update all assignments
struct device_prefix_assignment *assignment;
struct vlist_tree *assignments = prefix_new->assignments;
- vlist_for_each_element(assignments, assignment, node)
+ vlist_for_each_element(assignments, assignment, node) {
+ assignment->prefix = prefix_new;
assignments->update(assignments,
&assignment->node, &assignment->node);
+ }
} else if (node_new) {
prefix_new->avail = 1ULL << (64 - prefix_new->length);
prefix_new->assignments = calloc(1, sizeof(*prefix_new->assignments));
- vlist_init(prefix_new->assignments, prefix_assignment_cmp,
+ vlist_init(prefix_new->assignments, avl_strcmp,
interface_update_prefix_assignments);
// Create initial assignments for interfaces
interface_ip_set_prefix_assignment(prefix_new, iface,
iface->proto_ip.assignment_length);
- list_add(&prefix_new->head, &prefixes);
-
// Set null-route to avoid routing loops
system_add_route(NULL, &route);
}
}
free(prefix_old);
}
+
+ if (node_new)
+ list_add(&prefix_new->head, &prefixes);
}
void
interface_ip_set_ula_prefix(const char *prefix)
{
char buf[INET6_ADDRSTRLEN + 4] = {0}, *saveptr;
- strncpy(buf, prefix, sizeof(buf) - 1);
+ if (prefix)
+ strncpy(buf, prefix, sizeof(buf) - 1);
char *prefixaddr = strtok_r(buf, "/", &saveptr);
struct in6_addr addr;
- if (!prefixaddr || inet_pton(AF_INET6, prefixaddr, &addr) < 1)
+ if (!prefixaddr || inet_pton(AF_INET6, prefixaddr, &addr) < 1) {
+ if (ula_prefix) {
+ interface_update_prefix(NULL, NULL, &ula_prefix->node);
+ ula_prefix = NULL;
+ }
return;
+ }
int length;
char *prefixlen = strtok_r(NULL, ",", &saveptr);