struct vlist_tree interfaces;
static LIST_HEAD(iface_all_users);
-static unsigned int interface_serial = 0;
enum {
IFACE_ATTR_IFNAME,
IFACE_ATTR_IP4TABLE,
IFACE_ATTR_IP6TABLE,
IFACE_ATTR_IP6CLASS,
+ IFACE_ATTR_DELEGATE,
IFACE_ATTR_MAX
};
[IFACE_ATTR_IP4TABLE] = { .name = "ip4table", .type = BLOBMSG_TYPE_STRING },
[IFACE_ATTR_IP6TABLE] = { .name = "ip6table", .type = BLOBMSG_TYPE_STRING },
[IFACE_ATTR_IP6CLASS] = { .name = "ip6class", .type = BLOBMSG_TYPE_ARRAY },
+ [IFACE_ATTR_DELEGATE] = { .name = "delegate", .type = BLOBMSG_TYPE_BOOL },
};
static const struct uci_blob_param_info iface_attr_info[IFACE_ATTR_MAX] = {
if (!blobmsg_check_attr(data, true))
return UBUS_STATUS_INVALID_ARGUMENT;
- n = calloc(1, sizeof(*n) + blob_pad_len(data));
- memcpy(n->data, data, blob_pad_len(data));
- n->node.key = blobmsg_name(data);
+ const char *name = blobmsg_name(data);
+ unsigned len = blob_pad_len(data);
+
+ o = avl_find_element(&iface->data, name, o, node);
+ if (o) {
+ if (blob_pad_len(o->data) == len && !memcmp(o->data, data, len))
+ return 0;
- o = avl_find_element(&iface->data, n->node.key, o, node);
- if (o)
interface_data_del(iface, o);
+ }
+ n = calloc(1, sizeof(*n) + len);
+ memcpy(n->data, data, len);
+ n->node.key = blobmsg_name(n->data);
avl_insert(&iface->data, &n->node);
+
+ iface->updated |= IUF_DATA;
return 0;
}
interface_proto_event(iface->proto, PROTO_CMD_TEARDOWN, force);
if (force)
interface_flush_state(iface);
+
+ if (iface->dynamic)
+ vlist_delete(&interfaces, &iface->node);
}
static void
interface_remove_user(dep);
break;
case IFEV_RELOAD:
+ case IFEV_UPDATE:
break;
}
}
switch (ev) {
case IFPEV_UP:
- if (iface->state != IFS_SETUP)
+ if (iface->state != IFS_SETUP) {
+ interface_event(iface, IFEV_UPDATE);
return;
+ }
interface_ip_set_enabled(&iface->config_ip, true);
system_flush_routes();
state->iface = iface;
}
-void
-interface_init(struct interface *iface, const char *name,
- struct blob_attr *config)
+struct interface *
+interface_alloc(const char *name, struct blob_attr *config)
{
+ struct interface *iface;
struct blob_attr *tb[IFACE_ATTR_MAX];
struct blob_attr *cur;
const char *proto_name = NULL;
+ char *iface_name;
- strncpy(iface->name, name, sizeof(iface->name) - 1);
+ iface = calloc_a(sizeof(*iface), &iface_name, strlen(name) + 1);
+ iface->name = strcpy(iface_name, name);
INIT_LIST_HEAD(&iface->errors);
INIT_LIST_HEAD(&iface->users);
INIT_LIST_HEAD(&iface->hotplug_list);
DPRINTF("Failed to resolve routing table: %s\n", (char *) blobmsg_data(cur));
}
- // Set a default exteranl routing table for IPv6 to do source-based-filtering
- struct interface *iface_old = vlist_find(&interfaces, name, iface_old, node);
- if (iface_old && iface_old->ip6table > 1000 && iface_old->ip6table < 2000)
- iface->ip6table = iface_old->ip6table;
- else
- iface->ip6table = 1000 + ++interface_serial;
-
if ((cur = tb[IFACE_ATTR_IP6TABLE])) {
if (!system_resolve_rt_table(blobmsg_data(cur), &iface->ip6table))
DPRINTF("Failed to resolve routing table: %s\n", (char *) blobmsg_data(cur));
}
+ iface->proto_ip.no_delegation = !blobmsg_get_bool_default(tb[IFACE_ATTR_DELEGATE], true);
+
iface->config_autostart = iface->autostart;
+ return iface;
+}
+
+void interface_set_dynamic(struct interface *iface)
+{
+ iface->dynamic = true;
+ iface->node.version = -1; // Don't delete on reload
}
static bool __interface_add(struct interface *iface, struct blob_attr *config, bool alias)
}
int
+interface_handle_link(struct interface *iface, const char *name, bool add)
+{
+ struct device *dev;
+ int ret;
+
+ device_lock();
+
+ dev = device_get(name, add ? 2 : 0);
+ if (!dev) {
+ ret = UBUS_STATUS_NOT_FOUND;
+ goto out;
+ }
+
+ if (add) {
+ device_set_present(dev, true);
+ if (iface->device_config)
+ device_set_config(dev, &simple_device_type, iface->config);
+
+ system_if_apply_settings(dev, &dev->settings);
+ ret = interface_add_link(iface, dev);
+ } else {
+ ret = interface_remove_link(iface, dev);
+ }
+
+out:
+ device_unlock();
+
+ return ret;
+}
+
+int
interface_set_up(struct interface *iface)
{
int ret;
void
interface_update_start(struct interface *iface)
{
+ iface->updated = 0;
interface_ip_update_start(&iface->proto_ip);
}
#undef UPDATE
if (reload) {
- D(INTERFACE, "Reload interface '%s because of config changes\n",
+ D(INTERFACE, "Reload interface '%s' because of config changes\n",
if_old->name);
interface_clear_errors(if_old);
set_config_state(if_old, IFC_RELOAD);