static LIST_HEAD(iface_all_users);
enum {
- IFACE_ATTR_IFNAME,
+ IFACE_ATTR_DEVICE,
+ IFACE_ATTR_IFNAME, /* Backward compatibility */
IFACE_ATTR_PROTO,
IFACE_ATTR_AUTO,
IFACE_ATTR_JAIL,
+ IFACE_ATTR_JAIL_DEVICE,
IFACE_ATTR_JAIL_IFNAME,
+ IFACE_ATTR_HOST_DEVICE,
IFACE_ATTR_DEFAULTROUTE,
IFACE_ATTR_PEERDNS,
IFACE_ATTR_DNS,
};
static const struct blobmsg_policy iface_attrs[IFACE_ATTR_MAX] = {
+ [IFACE_ATTR_DEVICE] = { .name = "device", .type = BLOBMSG_TYPE_STRING },
[IFACE_ATTR_PROTO] = { .name = "proto", .type = BLOBMSG_TYPE_STRING },
[IFACE_ATTR_IFNAME] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING },
[IFACE_ATTR_AUTO] = { .name = "auto", .type = BLOBMSG_TYPE_BOOL },
[IFACE_ATTR_JAIL] = { .name = "jail", .type = BLOBMSG_TYPE_STRING },
+ [IFACE_ATTR_JAIL_DEVICE] = { .name = "jail_device", .type = BLOBMSG_TYPE_STRING },
[IFACE_ATTR_JAIL_IFNAME] = { .name = "jail_ifname", .type = BLOBMSG_TYPE_STRING },
+ [IFACE_ATTR_HOST_DEVICE] = { .name = "host_device", .type = BLOBMSG_TYPE_STRING },
[IFACE_ATTR_DEFAULTROUTE] = { .name = "defaultroute", .type = BLOBMSG_TYPE_BOOL },
[IFACE_ATTR_PEERDNS] = { .name = "peerdns", .type = BLOBMSG_TYPE_BOOL },
[IFACE_ATTR_METRIC] = { .name = "metric", .type = BLOBMSG_TYPE_INT32 },
}
}
+static bool
+interface_force_link(struct interface *iface)
+{
+ struct device *dev = iface->main_dev.dev;
+
+ if (dev && dev->settings.auth)
+ return false;
+
+ return iface->force_link;
+}
+
static void
interface_clear_errors(struct interface *iface)
{
case IFEV_UP:
interface_error_flush(iface);
adev = iface->l3_dev.dev;
- /* fall through */
+ fallthrough;
case IFEV_DOWN:
case IFEV_UP_FAILED:
alias_notify_device(iface->name, adev);
case IFS_DOWN:
if (iface->main_dev.dev)
device_release(&iface->main_dev);
+ break;
case IFS_TEARDOWN:
default:
break;
static void
interface_check_state(struct interface *iface)
{
- bool link_state = iface->link_state || iface->force_link;
+ bool link_state = iface->link_state || interface_force_link(iface);
switch (iface->state) {
case IFS_UP:
iface->link_state = new_state;
interface_check_state(iface);
- if (new_state && iface->force_link && iface->state == IFS_UP && !iface->link_up_event) {
+ if (new_state && interface_force_link(iface) &&
+ iface->state == IFS_UP && !iface->link_up_event) {
interface_event(iface, IFEV_LINK_UP);
iface->link_up_event = true;
}
case DEV_EVENT_DOWN:
interface_set_enabled(iface, false);
break;
+ case DEV_EVENT_AUTH_UP:
case DEV_EVENT_LINK_UP:
- interface_set_link_state(iface, true);
- break;
case DEV_EVENT_LINK_DOWN:
- interface_set_link_state(iface, false);
+ interface_set_link_state(iface, device_link_active(dep->dev));
break;
case DEV_EVENT_TOPO_CHANGE:
interface_proto_event(iface->proto, PROTO_CMD_RENEW, false);
if (iface->parent_iface.iface)
interface_remove_user(&iface->parent_iface);
- device_lock();
-
if (iface->parent_ifname) {
parent = vlist_find(&interfaces, iface->parent_ifname, parent, node);
iface->parent_iface.cb = interface_alias_cb;
interface_add_user(&iface->parent_iface, parent);
- } else if (iface->ifname &&
+ } else if (iface->device &&
!(iface->proto_handler->flags & PROTO_FLAG_NODEV)) {
- dev = device_get(iface->ifname, true);
+ dev = device_get(iface->device, true);
interface_set_device_config(iface, dev);
} else {
dev = iface->ext_dev.dev;
if (dev)
interface_set_main_dev(iface, dev);
- device_unlock();
-
if (iface->proto_handler->flags & PROTO_FLAG_INIT_AVAILABLE)
interface_set_available(iface, true);
}
avl_delete(&interfaces.avl, &iface->node.avl);
if (iface->jail)
free(iface->jail);
- if (iface->jail_ifname)
- free(iface->jail_ifname);
+ if (iface->jail_device)
+ free(iface->jail_device);
+ if (iface->host_device)
+ free(iface->host_device);
free(iface);
}
iface->autostart = false;
}
- iface->jail_ifname = NULL;
- if ((cur = tb[IFACE_ATTR_JAIL_IFNAME]))
- iface->jail_ifname = strdup(blobmsg_get_string(cur));
+ iface->jail_device = NULL;
+ if ((cur = tb[IFACE_ATTR_JAIL_DEVICE]))
+ iface->jail_device = strdup(blobmsg_get_string(cur));
+ else if ((cur = tb[IFACE_ATTR_JAIL_IFNAME]))
+ iface->jail_device = strdup(blobmsg_get_string(cur));
+
+ iface->host_device = NULL;
+ if ((cur = tb[IFACE_ATTR_HOST_DEVICE]))
+ iface->host_device = strdup(blobmsg_get_string(cur));
return iface;
}
if (!iface->parent_ifname)
return false;
} else {
- if ((cur = tb[IFACE_ATTR_IFNAME]))
- iface->ifname = blobmsg_data(cur);
+ cur = tb[IFACE_ATTR_DEVICE];
+ if (!cur)
+ cur = tb[IFACE_ATTR_IFNAME];
+ if (cur)
+ iface->device = blobmsg_data(cur);
}
if (iface->dynamic) {
}
static int
-interface_remove_link(struct interface *iface, struct device *dev)
+interface_remove_link(struct interface *iface, struct device *dev,
+ struct blob_attr *vlan)
{
struct device *mdev = iface->main_dev.dev;
if (mdev && mdev->hotplug_ops)
- return mdev->hotplug_ops->del(mdev, dev);
+ return mdev->hotplug_ops->del(mdev, dev, vlan);
if (dev == iface->ext_dev.dev)
device_remove_user(&iface->ext_dev);
struct blob_attr *vlan, bool add, bool link_ext)
{
struct device *dev;
- int ret;
-
- device_lock();
dev = device_get(name, add ? (link_ext ? 2 : 1) : 0);
- if (!dev) {
- ret = UBUS_STATUS_NOT_FOUND;
- goto out;
- }
+ if (!dev)
+ return UBUS_STATUS_NOT_FOUND;
- if (add) {
- interface_set_device_config(iface, dev);
- device_set_present(dev, true);
+ if (!add)
+ return interface_remove_link(iface, dev, vlan);
- ret = interface_add_link(iface, dev, vlan, link_ext);
- } else {
- ret = interface_remove_link(iface, dev);
- }
-
-out:
- device_unlock();
+ interface_set_device_config(iface, dev);
+ if (!link_ext)
+ device_set_present(dev, true);
- return ret;
+ return interface_add_link(iface, dev, vlan, link_ext);
}
void
}
void
-interface_start_jail(const char *jail, const pid_t netns_pid)
+interface_start_jail(int netns_fd, const char *jail)
{
struct interface *iface;
- int netns_fd;
- int wstatus;
- pid_t pr = 0;
-
- netns_fd = system_netns_open(netns_pid);
- if (netns_fd < 0)
- return;
vlist_for_each_element(&interfaces, iface, node) {
if (!iface->jail || strcmp(iface->jail, jail))
continue;
- system_link_netns_move(iface->main_dev.dev, netns_fd, iface->jail_ifname);
+ system_link_netns_move(iface->main_dev.dev, netns_fd, iface->jail_device);
}
-
- close(netns_fd);
-
- pr = fork();
- if (pr) {
- waitpid(pr, &wstatus, WUNTRACED | WCONTINUED);
- return;
- }
-
- /* child process */
- netns_fd = system_netns_open(netns_pid);
- if (netns_fd < 0)
- return;
-
- system_netns_set(netns_fd);
- system_init();
- vlist_for_each_element(&interfaces, iface, node) {
- if (!iface->jail || strcmp(iface->jail, jail))
- continue;
-
- /*
- * The interface has already been renamed and is inside target
- * namespace, hence overwrite ifname with jail_ifname for
- * interface_set_up().
- * We are inside a fork which got it's own copy of the interfaces
- * list, so we can mess with it :)
- */
- if (iface->jail_ifname)
- iface->ifname = iface->jail_ifname;
-
- interface_do_reload(iface);
- interface_set_up(iface);
- }
-
- close(netns_fd);
- _exit(0);
}
void
-interface_stop_jail(const char *jail, const pid_t netns_pid)
+interface_stop_jail(int netns_fd)
{
struct interface *iface;
- int netns_fd, root_netns;
- int wstatus;
- pid_t parent_pid = getpid();
- pid_t pr = 0;
- const char *orig_ifname;
-
- pr = fork();
- if (pr) {
- waitpid(pr, &wstatus, WUNTRACED | WCONTINUED);
- return;
- }
-
- /* child process */
- root_netns = system_netns_open(parent_pid);
- if (root_netns < 0)
- return;
+ char *orig_ifname;
- netns_fd = system_netns_open(netns_pid);
- if (netns_fd < 0)
- return;
-
- system_netns_set(netns_fd);
- system_init();
vlist_for_each_element(&interfaces, iface, node) {
- if (!iface->jail || strcmp(iface->jail, jail))
- continue;
-
- orig_ifname = iface->ifname;
- if (iface->jail_ifname)
- iface->ifname = iface->jail_ifname;
-
- interface_do_reload(iface);
+ orig_ifname = iface->host_device;
interface_set_down(iface);
- system_link_netns_move(iface->main_dev.dev, root_netns, orig_ifname);
+ system_link_netns_move(iface->main_dev.dev, netns_fd, orig_ifname);
}
-
- close(root_netns);
- close(netns_fd);
- _exit(0);
}
static void
if (!reload && interface_device_config_changed(if_old, if_new))
reload = true;
- if (FIELD_CHANGED_STR(ifname) ||
+ if (FIELD_CHANGED_STR(device) ||
if_old->proto_handler != if_new->proto_handler)
reload = true;
if (if_old->jail)
if_old->autostart = false;
- if (if_old->jail_ifname)
- free(if_old->jail_ifname);
+ if (if_old->jail_device)
+ free(if_old->jail_device);
+
+ if_old->jail_device = if_new->jail_device;
+
+ if (if_old->host_device)
+ free(if_old->host_device);
- if_old->jail_ifname = if_new->jail_ifname;
+ if_old->host_device = if_new->host_device;
- if_old->ifname = if_new->ifname;
+ if_old->device = if_new->device;
if_old->parent_ifname = if_new->parent_ifname;
if_old->dynamic = if_new->dynamic;
if_old->proto_handler = if_new->proto_handler;