#include <limits.h>
#include <arpa/inet.h>
-#include <netinet/ether.h>
#include <netinet/in.h>
+#include <netinet/ether.h>
#include <linux/rtnetlink.h>
#include <linux/neighbour.h>
static int __system_del_ip_tunnel(const char *name, struct blob_attr **tb);
static char dev_buf[256];
+static const char *proc_path = "/proc";
+static const char *sysfs_path = "/sys";
static void
handler_nl_event(struct uloop_fd *u, unsigned int events)
return 0;
}
-static void system_set_sysctl(const char *path, const char *val)
+static void write_file(const char *path, const char *val)
{
int fd;
close(fd);
}
-static void system_set_dev_sysctl(const char *path, const char *device, const char *val)
+static int read_file(const char *path, char *buf, const size_t buf_sz)
+{
+ int fd = -1, ret = -1;
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0)
+ goto out;
+
+ ssize_t len = read(fd, buf, buf_sz - 1);
+ if (len < 0)
+ goto out;
+
+ ret = buf[len] = 0;
+
+out:
+ if (fd >= 0)
+ close(fd);
+
+ return ret;
+}
+
+
+static const char *
+dev_sysctl_path(const char *prefix, const char *ifname, const char *file)
+{
+ snprintf(dev_buf, sizeof(dev_buf), "%s/sys/net/%s/%s/%s", proc_path, prefix, ifname, file);
+
+ return dev_buf;
+}
+
+static const char *
+dev_sysfs_path(const char *ifname, const char *file)
+{
+ snprintf(dev_buf, sizeof(dev_buf), "%s/class/net/%s/%s", sysfs_path, ifname, file);
+
+ return dev_buf;
+}
+
+static void
+system_set_dev_sysctl(const char *prefix, const char *file, const char *ifname,
+ const char *val)
+{
+ write_file(dev_sysctl_path(prefix, ifname, file), val);
+}
+
+static int
+system_get_dev_sysctl(const char *prefix, const char *file, const char *ifname,
+ char *buf, size_t buf_sz)
+{
+ return read_file(dev_sysctl_path(prefix, ifname, file), buf, buf_sz);
+}
+
+static void
+system_set_dev_sysfs(const char *file, const char *ifname, const char *val)
+{
+ if (!val)
+ return;
+
+ write_file(dev_sysfs_path(ifname, file), val);
+}
+
+static void
+system_set_dev_sysfs_int(const char *file, const char *ifname, int val)
{
- snprintf(dev_buf, sizeof(dev_buf), path, device);
- system_set_sysctl(dev_buf, val);
+ char buf[16];
+
+ snprintf(buf, sizeof(buf), "%d", val);
+ system_set_dev_sysfs(file, ifname, buf);
+}
+
+static int
+system_get_dev_sysfs(const char *file, const char *ifname, char *buf, size_t buf_sz)
+{
+ return read_file(dev_sysfs_path(ifname, file), buf, buf_sz);
}
static void system_set_disable_ipv6(struct device *dev, const char *val)
{
- system_set_dev_sysctl("/proc/sys/net/ipv6/conf/%s/disable_ipv6", dev->ifname, val);
+ system_set_dev_sysctl("ipv6/conf", "disable_ipv6", dev->ifname, val);
+}
+
+static void system_set_ip6segmentrouting(struct device *dev, const char *val)
+{
+ system_set_dev_sysctl("ipv6/conf", "seg6_enabled", dev->ifname, val);
}
static void system_set_rpfilter(struct device *dev, const char *val)
{
- system_set_dev_sysctl("/proc/sys/net/ipv4/conf/%s/rp_filter", dev->ifname, val);
+ system_set_dev_sysctl("ipv4/conf", "rp_filter", dev->ifname, val);
}
static void system_set_acceptlocal(struct device *dev, const char *val)
{
- system_set_dev_sysctl("/proc/sys/net/ipv4/conf/%s/accept_local", dev->ifname, val);
+ system_set_dev_sysctl("ipv4/conf", "accept_local", dev->ifname, val);
}
static void system_set_igmpversion(struct device *dev, const char *val)
{
- system_set_dev_sysctl("/proc/sys/net/ipv4/conf/%s/force_igmp_version", dev->ifname, val);
+ system_set_dev_sysctl("ipv4/conf", "force_igmp_version", dev->ifname, val);
}
static void system_set_mldversion(struct device *dev, const char *val)
{
- system_set_dev_sysctl("/proc/sys/net/ipv6/conf/%s/force_mld_version", dev->ifname, val);
+ system_set_dev_sysctl("ipv6/conf", "force_mld_version", dev->ifname, val);
}
static void system_set_neigh4reachabletime(struct device *dev, const char *val)
{
- system_set_dev_sysctl("/proc/sys/net/ipv4/neigh/%s/base_reachable_time_ms", dev->ifname, val);
+ system_set_dev_sysctl("ipv4/neigh", "base_reachable_time_ms", dev->ifname, val);
}
static void system_set_neigh6reachabletime(struct device *dev, const char *val)
{
- system_set_dev_sysctl("/proc/sys/net/ipv6/neigh/%s/base_reachable_time_ms", dev->ifname, val);
+ system_set_dev_sysctl("ipv6/neigh", "base_reachable_time_ms", dev->ifname, val);
}
static void system_set_neigh4gcstaletime(struct device *dev, const char *val)
{
- system_set_dev_sysctl("/proc/sys/net/ipv4/neigh/%s/gc_stale_time", dev->ifname, val);
+ system_set_dev_sysctl("ipv4/neigh", "gc_stale_time", dev->ifname, val);
}
static void system_set_neigh6gcstaletime(struct device *dev, const char *val)
{
- system_set_dev_sysctl("/proc/sys/net/ipv6/neigh/%s/gc_stale_time", dev->ifname, val);
+ system_set_dev_sysctl("ipv6/neigh", "gc_stale_time", dev->ifname, val);
}
static void system_set_neigh4locktime(struct device *dev, const char *val)
{
- system_set_dev_sysctl("/proc/sys/net/ipv4/neigh/%s/locktime", dev->ifname, val);
+ system_set_dev_sysctl("ipv4/neigh", "locktime", dev->ifname, val);
}
static void system_set_dadtransmits(struct device *dev, const char *val)
{
- system_set_dev_sysctl("/proc/sys/net/ipv6/conf/%s/dad_transmits", dev->ifname, val);
+ system_set_dev_sysctl("ipv6/conf", "dad_transmits", dev->ifname, val);
+}
+
+static void system_set_sendredirects(struct device *dev, const char *val)
+{
+ system_set_dev_sysctl("ipv4/conf", "send_redirects", dev->ifname, val);
+}
+
+static void system_set_drop_v4_unicast_in_l2_multicast(struct device *dev, const char *val)
+{
+ system_set_dev_sysctl("ipv4/conf", "drop_unicast_in_l2_multicast", dev->ifname, val);
+}
+
+static void system_set_drop_v6_unicast_in_l2_multicast(struct device *dev, const char *val)
+{
+ system_set_dev_sysctl("ipv6/conf", "drop_unicast_in_l2_multicast", dev->ifname, val);
+}
+
+static void system_set_drop_gratuitous_arp(struct device *dev, const char *val)
+{
+ system_set_dev_sysctl("ipv4/conf", "drop_gratuitous_arp", dev->ifname, val);
+}
+
+static void system_set_drop_unsolicited_na(struct device *dev, const char *val)
+{
+ system_set_dev_sysctl("ipv6/conf", "drop_unsolicited_na", dev->ifname, val);
+}
+
+static void system_set_arp_accept(struct device *dev, const char *val)
+{
+ system_set_dev_sysctl("ipv4/conf", "arp_accept", dev->ifname, val);
}
static void system_bridge_set_multicast_to_unicast(struct device *dev, const char *val)
{
- system_set_dev_sysctl("/sys/class/net/%s/brport/multicast_to_unicast", dev->ifname, val);
+ system_set_dev_sysfs("brport/multicast_to_unicast", dev->ifname, val);
}
static void system_bridge_set_multicast_fast_leave(struct device *dev, const char *val)
{
- system_set_dev_sysctl("/sys/class/net/%s/brport/multicast_fast_leave", dev->ifname, val);
+ system_set_dev_sysfs("brport/multicast_fast_leave", dev->ifname, val);
}
static void system_bridge_set_hairpin_mode(struct device *dev, const char *val)
{
- system_set_dev_sysctl("/sys/class/net/%s/brport/hairpin_mode", dev->ifname, val);
+ system_set_dev_sysfs("brport/hairpin_mode", dev->ifname, val);
+}
+
+static void system_bridge_set_proxyarp_wifi(struct device *dev, const char *val)
+{
+ system_set_dev_sysfs("brport/proxyarp_wifi", dev->ifname, val);
+}
+
+static void system_bridge_set_bpdu_filter(struct device *dev, const char *val)
+{
+ system_set_dev_sysfs("brport/bpdu_filter", dev->ifname, val);
}
static void system_bridge_set_isolated(struct device *dev, const char *val)
{
- system_set_dev_sysctl("/sys/class/net/%s/brport/isolated", dev->ifname, val);
+ system_set_dev_sysfs("brport/isolated", dev->ifname, val);
}
static void system_bridge_set_multicast_router(struct device *dev, const char *val, bool bridge)
{
- system_set_dev_sysctl(bridge ? "/sys/class/net/%s/bridge/multicast_router" :
- "/sys/class/net/%s/brport/multicast_router",
+ system_set_dev_sysfs(bridge ? "bridge/multicast_router" :
+ "brport/multicast_router",
dev->ifname, val);
}
static void system_bridge_set_robustness(struct device *dev, const char *val)
{
- system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/multicast_startup_query_count",
+ system_set_dev_sysfs("bridge/multicast_startup_query_count",
dev->ifname, val);
- system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/multicast_last_member_count",
+ system_set_dev_sysfs("bridge/multicast_last_member_count",
dev->ifname, val);
}
static void system_bridge_set_query_interval(struct device *dev, const char *val)
{
- system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/multicast_query_interval",
+ system_set_dev_sysfs("bridge/multicast_query_interval",
dev->ifname, val);
}
static void system_bridge_set_query_response_interval(struct device *dev, const char *val)
{
- system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/multicast_query_response_interval",
+ system_set_dev_sysfs("bridge/multicast_query_response_interval",
dev->ifname, val);
}
static void system_bridge_set_last_member_interval(struct device *dev, const char *val)
{
- system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/multicast_last_member_interval",
+ system_set_dev_sysfs("bridge/multicast_last_member_interval",
dev->ifname, val);
}
static void system_bridge_set_membership_interval(struct device *dev, const char *val)
{
- system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/multicast_membership_interval",
+ system_set_dev_sysfs("bridge/multicast_membership_interval",
dev->ifname, val);
}
static void system_bridge_set_other_querier_timeout(struct device *dev, const char *val)
{
- system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/multicast_querier_interval",
+ system_set_dev_sysfs("bridge/multicast_querier_interval",
dev->ifname, val);
}
static void system_bridge_set_startup_query_interval(struct device *dev, const char *val)
{
- system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/multicast_startup_query_interval",
+ system_set_dev_sysfs("bridge/multicast_startup_query_interval",
dev->ifname, val);
}
-static void system_bridge_set_stp_state(struct device *dev, const char *val)
+void system_bridge_set_stp_state(struct device *dev, bool val)
{
- system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/stp_state", dev->ifname, val);
+ const char *valstr = val ? "1" : "0";
+
+ system_set_dev_sysfs("bridge/stp_state", dev->ifname, valstr);
}
static void system_bridge_set_forward_delay(struct device *dev, const char *val)
{
- system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/forward_delay", dev->ifname, val);
+ system_set_dev_sysfs("bridge/forward_delay", dev->ifname, val);
}
static void system_bridge_set_priority(struct device *dev, const char *val)
{
- system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/priority", dev->ifname, val);
+ system_set_dev_sysfs("bridge/priority", dev->ifname, val);
}
static void system_bridge_set_ageing_time(struct device *dev, const char *val)
{
- system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/ageing_time", dev->ifname, val);
+ system_set_dev_sysfs("bridge/ageing_time", dev->ifname, val);
}
static void system_bridge_set_hello_time(struct device *dev, const char *val)
{
- system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/hello_time", dev->ifname, val);
+ system_set_dev_sysfs("bridge/hello_time", dev->ifname, val);
}
static void system_bridge_set_max_age(struct device *dev, const char *val)
{
- system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/max_age", dev->ifname, val);
+ system_set_dev_sysfs("bridge/max_age", dev->ifname, val);
}
static void system_bridge_set_learning(struct device *dev, const char *val)
{
- system_set_dev_sysctl("/sys/class/net/%s/brport/learning", dev->ifname, val);
+ system_set_dev_sysfs("brport/learning", dev->ifname, val);
}
static void system_bridge_set_unicast_flood(struct device *dev, const char *val)
{
- system_set_dev_sysctl("/sys/class/net/%s/brport/unicast_flood", dev->ifname, val);
+ system_set_dev_sysfs("brport/unicast_flood", dev->ifname, val);
}
-static void system_set_sendredirects(struct device *dev, const char *val)
+static void system_bridge_set_vlan_filtering(struct device *dev, const char *val)
{
- system_set_dev_sysctl("/proc/sys/net/ipv4/conf/%s/send_redirects", dev->ifname, val);
+ system_set_dev_sysfs("bridge/vlan_filtering", dev->ifname, val);
}
-static void system_bridge_set_vlan_filtering(struct device *dev, const char *val)
+static int system_get_disable_ipv6(struct device *dev, char *buf, const size_t buf_sz)
{
- system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/vlan_filtering", dev->ifname, val);
+ return system_get_dev_sysctl("ipv6/conf", "disable_ipv6",
+ dev->ifname, buf, buf_sz);
}
-static int system_get_sysctl(const char *path, char *buf, const size_t buf_sz)
+static int system_get_ip6segmentrouting(struct device *dev, char *buf, const size_t buf_sz)
{
- int fd = -1, ret = -1;
-
- fd = open(path, O_RDONLY);
- if (fd < 0)
- goto out;
-
- ssize_t len = read(fd, buf, buf_sz - 1);
- if (len < 0)
- goto out;
+ return system_get_dev_sysctl("ipv6/conf", "seg6_enabled",
+ dev->ifname, buf, buf_sz);
+}
- ret = buf[len] = 0;
+static int system_get_rpfilter(struct device *dev, char *buf, const size_t buf_sz)
+{
+ return system_get_dev_sysctl("ipv4/conf", "rp_filter",
+ dev->ifname, buf, buf_sz);
+}
-out:
- if (fd >= 0)
- close(fd);
+static int system_get_acceptlocal(struct device *dev, char *buf, const size_t buf_sz)
+{
+ return system_get_dev_sysctl("ipv4/conf", "accept_local",
+ dev->ifname, buf, buf_sz);
+}
- return ret;
+static int system_get_igmpversion(struct device *dev, char *buf, const size_t buf_sz)
+{
+ return system_get_dev_sysctl("ipv4/conf", "force_igmp_version",
+ dev->ifname, buf, buf_sz);
}
-static int
-system_get_dev_sysctl(const char *path, const char *device, char *buf, const size_t buf_sz)
+static int system_get_mldversion(struct device *dev, char *buf, const size_t buf_sz)
{
- snprintf(dev_buf, sizeof(dev_buf), path, device);
- return system_get_sysctl(dev_buf, buf, buf_sz);
+ return system_get_dev_sysctl("ipv6/conf", "force_mld_version",
+ dev->ifname, buf, buf_sz);
}
-static int system_get_disable_ipv6(struct device *dev, char *buf, const size_t buf_sz)
+static int system_get_neigh4reachabletime(struct device *dev, char *buf, const size_t buf_sz)
{
- return system_get_dev_sysctl("/proc/sys/net/ipv6/conf/%s/disable_ipv6",
- dev->ifname, buf, buf_sz);
+ return system_get_dev_sysctl("ipv4/neigh", "base_reachable_time_ms",
+ dev->ifname, buf, buf_sz);
}
-static int system_get_rpfilter(struct device *dev, char *buf, const size_t buf_sz)
+static int system_get_neigh6reachabletime(struct device *dev, char *buf, const size_t buf_sz)
{
- return system_get_dev_sysctl("/proc/sys/net/ipv4/conf/%s/rp_filter",
- dev->ifname, buf, buf_sz);
+ return system_get_dev_sysctl("ipv6/neigh", "base_reachable_time_ms",
+ dev->ifname, buf, buf_sz);
}
-static int system_get_acceptlocal(struct device *dev, char *buf, const size_t buf_sz)
+static int system_get_neigh4gcstaletime(struct device *dev, char *buf, const size_t buf_sz)
{
- return system_get_dev_sysctl("/proc/sys/net/ipv4/conf/%s/accept_local",
- dev->ifname, buf, buf_sz);
+ return system_get_dev_sysctl("ipv4/neigh", "gc_stale_time",
+ dev->ifname, buf, buf_sz);
}
-static int system_get_igmpversion(struct device *dev, char *buf, const size_t buf_sz)
+static int system_get_neigh6gcstaletime(struct device *dev, char *buf, const size_t buf_sz)
{
- return system_get_dev_sysctl("/proc/sys/net/ipv4/conf/%s/force_igmp_version",
+ return system_get_dev_sysctl("ipv6/neigh", "gc_stale_time",
dev->ifname, buf, buf_sz);
}
-static int system_get_mldversion(struct device *dev, char *buf, const size_t buf_sz)
+static int system_get_neigh4locktime(struct device *dev, char *buf, const size_t buf_sz)
{
- return system_get_dev_sysctl("/proc/sys/net/ipv6/conf/%s/force_mld_version",
+ return system_get_dev_sysctl("ipv4/neigh", "locktime",
dev->ifname, buf, buf_sz);
}
-static int system_get_neigh4reachabletime(struct device *dev, char *buf, const size_t buf_sz)
+static int system_get_dadtransmits(struct device *dev, char *buf, const size_t buf_sz)
{
- return system_get_dev_sysctl("/proc/sys/net/ipv4/neigh/%s/base_reachable_time_ms",
+ return system_get_dev_sysctl("ipv6/conf", "dad_transmits",
dev->ifname, buf, buf_sz);
}
-static int system_get_neigh6reachabletime(struct device *dev, char *buf, const size_t buf_sz)
+static int system_get_sendredirects(struct device *dev, char *buf, const size_t buf_sz)
{
- return system_get_dev_sysctl("/proc/sys/net/ipv6/neigh/%s/base_reachable_time_ms",
+ return system_get_dev_sysctl("ipv4/conf", "send_redirects",
dev->ifname, buf, buf_sz);
}
-static int system_get_neigh4gcstaletime(struct device *dev, char *buf, const size_t buf_sz)
+
+static int system_get_drop_v4_unicast_in_l2_multicast(struct device *dev, char *buf, const size_t buf_sz)
{
- return system_get_dev_sysctl("/proc/sys/net/ipv4/neigh/%s/gc_stale_time",
+ return system_get_dev_sysctl("ipv4/conf", "drop_unicast_in_l2_multicast",
dev->ifname, buf, buf_sz);
}
-static int system_get_neigh6gcstaletime(struct device *dev, char *buf, const size_t buf_sz)
+static int system_get_drop_v6_unicast_in_l2_multicast(struct device *dev, char *buf, const size_t buf_sz)
{
- return system_get_dev_sysctl("/proc/sys/net/ipv6/neigh/%s/gc_stale_time",
+ return system_get_dev_sysctl("ipv6/conf", "drop_unicast_in_l2_multicast",
dev->ifname, buf, buf_sz);
}
-static int system_get_neigh4locktime(struct device *dev, char *buf, const size_t buf_sz)
+static int system_get_drop_gratuitous_arp(struct device *dev, char *buf, const size_t buf_sz)
{
- return system_get_dev_sysctl("/proc/sys/net/ipv4/neigh/%s/locktime",
+ return system_get_dev_sysctl("ipv4/conf", "drop_gratuitous_arp",
dev->ifname, buf, buf_sz);
}
-static int system_get_dadtransmits(struct device *dev, char *buf, const size_t buf_sz)
+static int system_get_drop_unsolicited_na(struct device *dev, char *buf, const size_t buf_sz)
{
- return system_get_dev_sysctl("/proc/sys/net/ipv6/conf/%s/dad_transmits",
+ return system_get_dev_sysctl("ipv6/conf", "drop_unsolicited_na",
dev->ifname, buf, buf_sz);
}
-static int system_get_sendredirects(struct device *dev, char *buf, const size_t buf_sz)
+static int system_get_arp_accept(struct device *dev, char *buf, const size_t buf_sz)
{
- return system_get_dev_sysctl("/proc/sys/net/ipv4/conf/%s/send_redirects",
+ return system_get_dev_sysctl("ipv4/conf", "arp_accept",
dev->ifname, buf, buf_sz);
}
if (!dev)
goto out;
- if (!system_get_dev_sysctl("/sys/class/net/%s/carrier", dev->ifname, buf, sizeof(buf)))
+ if (!system_get_dev_sysfs("carrier", dev->ifname, buf, sizeof(buf)))
link_state = strtoul(buf, NULL, 0);
- if (dev->type == &simple_device_type && !system_if_force_external(dev->ifname))
+ if (dev->type == &simple_device_type)
device_set_present(dev, true);
device_set_link(dev, link_state ? true : false);
{
const char *subsystem = NULL, *interface = NULL, *interface_old = NULL;
char *cur, *end, *sep;
- struct device *dev;
int skip;
- bool add, move = false;
+ bool add;
- if (!strncmp(data, "add@", 4))
+ if (!strncmp(data, "add@", 4) || !strncmp(data, "move@", 5))
add = true;
else if (!strncmp(data, "remove@", 7))
add = false;
- else if (!strncmp(data, "move@", 5)) {
- add = true;
- move = true;
- }
else
return;
}
}
- if (subsystem && interface) {
- if (move && interface_old)
- goto move;
- else
- goto found;
- }
-
- return;
-
-move:
- dev = device_find(interface_old);
- if (!dev)
+ if (!subsystem || !interface)
return;
- if (dev->type != &simple_device_type)
- goto found;
-
- device_set_present(dev, false);
-
- return;
-
-found:
- dev = device_find(interface);
- if (!dev)
- return;
+ if (interface_old)
+ device_hotplug_event(interface_old, false);
- if (dev->type != &simple_device_type)
- return;
-
- if (add && system_if_force_external(dev->ifname))
- return;
-
- device_set_present(dev, add);
+ device_hotplug_event(interface, add);
}
static void
return ioctl(sock_ioctl, cmd, &ifr);
}
-static bool system_is_bridge(const char *name, char *buf, int buflen)
+static bool system_is_bridge(const char *name)
{
struct stat st;
- snprintf(buf, buflen, "/sys/devices/virtual/net/%s/bridge", name);
- if (stat(buf, &st) < 0)
- return false;
-
- return true;
+ return stat(dev_sysfs_path(name, "bridge"), &st) >= 0;
}
static char *system_get_bridge(const char *name, char *buf, int buflen)
ssize_t len = -1;
glob_t gl;
- snprintf(buf, buflen, "/sys/devices/virtual/net/*/brif/%s/bridge", name);
+ snprintf(buf, buflen, "%s/devices/virtual/net/*/brif/%s/bridge", sysfs_path, name);
if (glob(buf, GLOB_NOSORT, NULL, &gl) < 0)
return NULL;
system_bridge_set_wireless(struct device *bridge, struct device *dev)
{
bool mcast_to_ucast = dev->wireless_ap;
- bool hairpin = true;
+ bool hairpin;
if (bridge->settings.flags & DEV_OPT_MULTICAST_TO_UNICAST &&
!bridge->settings.multicast_to_unicast)
mcast_to_ucast = false;
- if (!mcast_to_ucast || dev->wireless_isolate)
+ hairpin = mcast_to_ucast || dev->wireless_proxyarp;
+ if (dev->wireless_isolate)
hairpin = false;
system_bridge_set_multicast_to_unicast(dev, mcast_to_ucast ? "1" : "0");
system_bridge_set_hairpin_mode(dev, hairpin ? "1" : "0");
+ system_bridge_set_proxyarp_wifi(dev, dev->wireless_proxyarp ? "1" : "0");
}
int system_bridge_addif(struct device *bridge, struct device *dev)
{
char buf[64];
char *oldbr;
- int ret = 0;
+ int tries = 0;
+ int ret;
+retry:
+ ret = 0;
oldbr = system_get_bridge(dev->ifname, dev_buf, sizeof(dev_buf));
- if (!oldbr || strcmp(oldbr, bridge->ifname) != 0)
+ if (!oldbr || strcmp(oldbr, bridge->ifname) != 0) {
ret = system_bridge_if(bridge->ifname, dev, SIOCBRADDIF, NULL);
+ tries++;
+ D(SYSTEM, "Failed to add device '%s' to bridge '%s' (tries=%d): %s\n",
+ dev->ifname, bridge->ifname, tries, strerror(errno));
+ if (tries <= 3)
+ goto retry;
+ }
if (dev->wireless)
system_bridge_set_wireless(bridge, dev);
dev->settings.isolate)
system_bridge_set_isolated(dev, "1");
+ if (dev->bpdu_filter)
+ system_bridge_set_bpdu_filter(dev, dev->bpdu_filter ? "1" : "0");
+
return ret;
}
return ret;
}
+int system_bonding_set_device(struct device *dev, struct bonding_config *cfg)
+{
+ const char *ifname = dev->ifname;
+ struct blob_attr *cur;
+ char op = cfg ? '+' : '-';
+ char buf[64];
+ int rem;
+
+ snprintf(dev_buf, sizeof(dev_buf), "%s/class/net/bonding_masters", sysfs_path);
+ snprintf(buf, sizeof(buf), "%c%s", op, ifname);
+ write_file(dev_buf, buf);
+
+ if (!cfg)
+ return 0;
+
+ system_set_dev_sysfs("bonding/mode", ifname, bonding_policy_str[cfg->policy]);
+
+ system_set_dev_sysfs_int("bonding/all_ports_active", ifname, cfg->all_ports_active);
+
+ if (cfg->policy == BONDING_MODE_BALANCE_XOR ||
+ cfg->policy == BONDING_MODE_BALANCE_TLB ||
+ cfg->policy == BONDING_MODE_8023AD)
+ system_set_dev_sysfs("bonding/xmit_hash_policy", ifname, cfg->xmit_hash_policy);
+
+ if (cfg->policy == BONDING_MODE_8023AD) {
+ system_set_dev_sysfs("bonding/ad_actor_system", ifname, cfg->ad_actor_system);
+ system_set_dev_sysfs_int("bonding/ad_actor_sys_prio", ifname, cfg->ad_actor_sys_prio);
+ system_set_dev_sysfs("bonding/ad_select", ifname, cfg->ad_select);
+ system_set_dev_sysfs("bonding/lacp_rate", ifname, cfg->lacp_rate);
+ system_set_dev_sysfs_int("bonding/min_links", ifname, cfg->min_links);
+ }
+
+ if (cfg->policy == BONDING_MODE_BALANCE_RR)
+ system_set_dev_sysfs_int("bonding/packets_per_slave", ifname, cfg->packets_per_port);
+
+ if (cfg->policy == BONDING_MODE_BALANCE_TLB ||
+ cfg->policy == BONDING_MODE_BALANCE_ALB)
+ system_set_dev_sysfs_int("bonding/lp_interval", ifname, cfg->lp_interval);
+
+ if (cfg->policy == BONDING_MODE_BALANCE_TLB)
+ system_set_dev_sysfs_int("bonding/tlb_dynamic_lb", ifname, cfg->dynamic_lb);
+ system_set_dev_sysfs_int("bonding/resend_igmp", ifname, cfg->resend_igmp);
+ system_set_dev_sysfs_int("bonding/num_grat_arp", ifname, cfg->num_peer_notif);
+ system_set_dev_sysfs("bonding/primary_reselect", ifname, cfg->primary_reselect);
+ system_set_dev_sysfs("bonding/fail_over_mac", ifname, cfg->failover_mac);
+
+ system_set_dev_sysfs_int((cfg->monitor_arp ?
+ "bonding/arp_interval" :
+ "bonding/miimon"), ifname, cfg->monitor_interval);
+
+ blobmsg_for_each_attr(cur, cfg->arp_target, rem) {
+ snprintf(buf, sizeof(buf), "+%s", blobmsg_get_string(cur));
+ system_set_dev_sysfs("bonding/arp_ip_target", ifname, buf);
+ }
+
+ system_set_dev_sysfs_int("bonding/arp_all_targets", ifname, cfg->arp_all_targets);
+ if (cfg->policy < BONDING_MODE_8023AD)
+ system_set_dev_sysfs("bonding/arp_validate", ifname, cfg->arp_validate);
+ system_set_dev_sysfs_int("bonding/use_carrier", ifname, cfg->use_carrier);
+ if (!cfg->monitor_arp && cfg->monitor_interval) {
+ system_set_dev_sysfs_int("bonding/updelay", ifname, cfg->updelay);
+ system_set_dev_sysfs_int("bonding/downdelay", ifname, cfg->downdelay);
+ }
+
+ return 0;
+}
+
+int system_bonding_set_port(struct device *dev, struct device *port, bool add, bool primary)
+{
+ const char *port_name = port->ifname;
+ const char op_ch = add ? '+' : '-';
+ char buf[IFNAMSIZ + 2];
+
+ snprintf(buf, sizeof(buf), "%c%s", op_ch, port_name);
+ system_if_down(port);
+ system_set_dev_sysfs("bonding/slaves", dev->ifname, buf);
+ system_if_up(port);
+
+ if (primary)
+ system_set_dev_sysfs("bonding/primary", dev->ifname,
+ add ? port_name : "");
+
+ return 0;
+}
+
int system_if_resolve(struct device *dev)
{
struct ifreq ifr;
system_if_flags(dev->ifname, 0, IFF_UP);
- if (system_is_bridge(dev->ifname, buf, sizeof(buf))) {
+ if (system_is_bridge(dev->ifname)) {
D(SYSTEM, "Delete existing bridge named '%s'\n", dev->ifname);
system_bridge_delbr(dev);
return;
char *buf,
int buf_len)
{
- system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/multicast_snooping",
+ system_set_dev_sysfs("bridge/multicast_snooping",
bridge->ifname, cfg->igmp_snoop ? "1" : "0");
- system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/multicast_querier",
+ system_set_dev_sysfs("bridge/multicast_querier",
bridge->ifname, cfg->multicast_querier ? "1" : "0");
snprintf(buf, buf_len, "%i", cfg->hash_max);
- system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/hash_max",
+ system_set_dev_sysfs("/bridge/hash_max",
bridge->ifname, buf);
if (bridge->settings.flags & DEV_OPT_MULTICAST_ROUTER) {
if (ioctl(sock_ioctl, SIOCBRADDBR, bridge->ifname) < 0)
return -1;
- system_bridge_set_stp_state(bridge, cfg->stp ? "1" : "0");
+ system_bridge_set_stp_state(bridge, cfg->stp);
snprintf(buf, sizeof(buf), "%lu", sec_to_jiffies(cfg->forward_delay));
system_bridge_set_forward_delay(bridge, buf);
snprintf(buf, sizeof(buf), "%d", cfg->priority);
system_bridge_set_priority(bridge, buf);
+ snprintf(buf, sizeof(buf), "%lu", sec_to_jiffies(cfg->hello_time));
+ system_bridge_set_hello_time(bridge, buf);
+
+ snprintf(buf, sizeof(buf), "%lu", sec_to_jiffies(cfg->max_age));
+ system_bridge_set_max_age(bridge, buf);
+
if (cfg->flags & BRIDGE_OPT_AGEING_TIME) {
snprintf(buf, sizeof(buf), "%lu", sec_to_jiffies(cfg->ageing_time));
system_bridge_set_ageing_time(bridge, buf);
}
- if (cfg->flags & BRIDGE_OPT_HELLO_TIME) {
- snprintf(buf, sizeof(buf), "%lu", sec_to_jiffies(cfg->hello_time));
- system_bridge_set_hello_time(bridge, buf);
- }
-
- if (cfg->flags & BRIDGE_OPT_MAX_AGE) {
- snprintf(buf, sizeof(buf), "%lu", sec_to_jiffies(cfg->max_age));
- system_bridge_set_max_age(bridge, buf);
- }
-
return 0;
}
return system_link_del(vlandev->ifname);
}
+static void
+system_set_ethtool_settings(struct device *dev, struct device_settings *s)
+{
+ struct ethtool_cmd ecmd = {
+ .cmd = ETHTOOL_GSET,
+ };
+ struct ifreq ifr = {
+ .ifr_data = (caddr_t)&ecmd,
+ };
+ static const struct {
+ int speed;
+ uint8_t bit_half;
+ uint8_t bit_full;
+ } speed_mask[] = {
+ { 10, ETHTOOL_LINK_MODE_10baseT_Half_BIT, ETHTOOL_LINK_MODE_10baseT_Full_BIT },
+ { 100, ETHTOOL_LINK_MODE_100baseT_Half_BIT, ETHTOOL_LINK_MODE_100baseT_Full_BIT },
+ { 1000, ETHTOOL_LINK_MODE_1000baseT_Half_BIT, ETHTOOL_LINK_MODE_1000baseT_Full_BIT },
+ };
+ uint32_t adv;
+ int i;
+
+ strncpy(ifr.ifr_name, dev->ifname, sizeof(ifr.ifr_name) - 1);
+
+ if (ioctl(sock_ioctl, SIOCETHTOOL, &ifr) != 0)
+ return;
+
+ adv = ecmd.supported;
+ for (i = 0; i < ARRAY_SIZE(speed_mask); i++) {
+ if (s->flags & DEV_OPT_DUPLEX) {
+ int bit = s->duplex ? speed_mask[i].bit_half : speed_mask[i].bit_full;
+ adv &= ~(1 << bit);
+ }
+
+ if (!(s->flags & DEV_OPT_SPEED) ||
+ s->speed == speed_mask[i].speed)
+ continue;
+
+ adv &= ~(1 << speed_mask[i].bit_full);
+ adv &= ~(1 << speed_mask[i].bit_half);
+ }
+
+
+ if (ecmd.autoneg && ecmd.advertising == adv)
+ return;
+
+ ecmd.autoneg = 1;
+ ecmd.advertising = adv;
+ ecmd.cmd = ETHTOOL_SSET;
+ ioctl(sock_ioctl, SIOCETHTOOL, &ifr);
+}
+
void
system_if_get_settings(struct device *dev, struct device_settings *s)
{
s->flags |= DEV_OPT_IPV6;
}
+ if (!system_get_ip6segmentrouting(dev, buf, sizeof(buf))) {
+ s->ip6segmentrouting = strtoul(buf, NULL, 0);
+ s->flags |= DEV_OPT_IP6SEGMENTROUTING;
+ }
+
if (ioctl(sock_ioctl, SIOCGIFFLAGS, &ifr) == 0) {
s->promisc = ifr.ifr_flags & IFF_PROMISC;
s->flags |= DEV_OPT_PROMISC;
s->sendredirects = strtoul(buf, NULL, 0);
s->flags |= DEV_OPT_SENDREDIRECTS;
}
+
+ if (!system_get_drop_v4_unicast_in_l2_multicast(dev, buf, sizeof(buf))) {
+ s->drop_v4_unicast_in_l2_multicast = strtoul(buf, NULL, 0);
+ s->flags |= DEV_OPT_DROP_V4_UNICAST_IN_L2_MULTICAST;
+ }
+
+ if (!system_get_drop_v6_unicast_in_l2_multicast(dev, buf, sizeof(buf))) {
+ s->drop_v6_unicast_in_l2_multicast = strtoul(buf, NULL, 0);
+ s->flags |= DEV_OPT_DROP_V6_UNICAST_IN_L2_MULTICAST;
+ }
+
+ if (!system_get_drop_gratuitous_arp(dev, buf, sizeof(buf))) {
+ s->drop_gratuitous_arp = strtoul(buf, NULL, 0);
+ s->flags |= DEV_OPT_DROP_GRATUITOUS_ARP;
+ }
+
+ if (!system_get_drop_unsolicited_na(dev, buf, sizeof(buf))) {
+ s->drop_unsolicited_na = strtoul(buf, NULL, 0);
+ s->flags |= DEV_OPT_DROP_UNSOLICITED_NA;
+ }
+
+ if (!system_get_arp_accept(dev, buf, sizeof(buf))) {
+ s->arp_accept = strtoul(buf, NULL, 0);
+ s->flags |= DEV_OPT_ARP_ACCEPT;
+ }
}
void
-system_if_apply_settings(struct device *dev, struct device_settings *s, unsigned int apply_mask)
+system_if_apply_settings(struct device *dev, struct device_settings *s, uint64_t apply_mask)
{
struct ifreq ifr;
char buf[12];
+ apply_mask &= s->flags;
+
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, dev->ifname, sizeof(ifr.ifr_name) - 1);
- if (s->flags & DEV_OPT_MTU & apply_mask) {
+ if (apply_mask & DEV_OPT_MTU) {
ifr.ifr_mtu = s->mtu;
if (ioctl(sock_ioctl, SIOCSIFMTU, &ifr) < 0)
s->flags &= ~DEV_OPT_MTU;
}
- if (s->flags & DEV_OPT_MTU6 & apply_mask) {
+ if (apply_mask & DEV_OPT_MTU6) {
system_update_ipv6_mtu(dev, s->mtu6);
}
- if (s->flags & DEV_OPT_TXQUEUELEN & apply_mask) {
+ if (apply_mask & DEV_OPT_TXQUEUELEN) {
ifr.ifr_qlen = s->txqueuelen;
if (ioctl(sock_ioctl, SIOCSIFTXQLEN, &ifr) < 0)
s->flags &= ~DEV_OPT_TXQUEUELEN;
}
- if ((s->flags & DEV_OPT_MACADDR & apply_mask) && !dev->external) {
+ if ((apply_mask & (DEV_OPT_MACADDR | DEV_OPT_DEFAULT_MACADDR)) && !dev->external) {
ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
memcpy(&ifr.ifr_hwaddr.sa_data, s->macaddr, sizeof(s->macaddr));
if (ioctl(sock_ioctl, SIOCSIFHWADDR, &ifr) < 0)
s->flags &= ~DEV_OPT_MACADDR;
}
- if (s->flags & DEV_OPT_IPV6 & apply_mask)
+ if (apply_mask & DEV_OPT_IPV6)
system_set_disable_ipv6(dev, s->ipv6 ? "0" : "1");
- if (s->flags & DEV_OPT_PROMISC & apply_mask) {
+ if (s->flags & DEV_OPT_IP6SEGMENTROUTING & apply_mask) {
+ struct device dummy = {
+ .ifname = "all",
+ };
+ bool ip6segmentrouting = device_check_ip6segmentrouting();
+
+ system_set_ip6segmentrouting(dev, s->ip6segmentrouting ? "1" : "0");
+ system_set_ip6segmentrouting(&dummy, ip6segmentrouting ? "1" : "0");
+ }
+ if (apply_mask & DEV_OPT_PROMISC) {
if (system_if_flags(dev->ifname, s->promisc ? IFF_PROMISC : 0,
!s->promisc ? IFF_PROMISC : 0) < 0)
s->flags &= ~DEV_OPT_PROMISC;
}
- if (s->flags & DEV_OPT_RPFILTER & apply_mask) {
+ if (apply_mask & DEV_OPT_RPFILTER) {
snprintf(buf, sizeof(buf), "%u", s->rpfilter);
system_set_rpfilter(dev, buf);
}
- if (s->flags & DEV_OPT_ACCEPTLOCAL & apply_mask)
+ if (apply_mask & DEV_OPT_ACCEPTLOCAL)
system_set_acceptlocal(dev, s->acceptlocal ? "1" : "0");
- if (s->flags & DEV_OPT_IGMPVERSION & apply_mask) {
+ if (apply_mask & DEV_OPT_IGMPVERSION) {
snprintf(buf, sizeof(buf), "%u", s->igmpversion);
system_set_igmpversion(dev, buf);
}
- if (s->flags & DEV_OPT_MLDVERSION & apply_mask) {
+ if (apply_mask & DEV_OPT_MLDVERSION) {
snprintf(buf, sizeof(buf), "%u", s->mldversion);
system_set_mldversion(dev, buf);
}
- if (s->flags & DEV_OPT_NEIGHREACHABLETIME & apply_mask) {
+ if (apply_mask & DEV_OPT_NEIGHREACHABLETIME) {
snprintf(buf, sizeof(buf), "%u", s->neigh4reachabletime);
system_set_neigh4reachabletime(dev, buf);
snprintf(buf, sizeof(buf), "%u", s->neigh6reachabletime);
system_set_neigh6reachabletime(dev, buf);
}
- if (s->flags & DEV_OPT_NEIGHLOCKTIME & apply_mask) {
+ if (apply_mask & DEV_OPT_NEIGHLOCKTIME) {
snprintf(buf, sizeof(buf), "%d", s->neigh4locktime);
system_set_neigh4locktime(dev, buf);
}
- if (s->flags & DEV_OPT_NEIGHGCSTALETIME & apply_mask) {
+ if (apply_mask & DEV_OPT_NEIGHGCSTALETIME) {
snprintf(buf, sizeof(buf), "%u", s->neigh4gcstaletime);
system_set_neigh4gcstaletime(dev, buf);
snprintf(buf, sizeof(buf), "%u", s->neigh6gcstaletime);
system_set_neigh6gcstaletime(dev, buf);
}
- if (s->flags & DEV_OPT_DADTRANSMITS & apply_mask) {
+ if (apply_mask & DEV_OPT_DADTRANSMITS) {
snprintf(buf, sizeof(buf), "%u", s->dadtransmits);
system_set_dadtransmits(dev, buf);
}
- if (s->flags & DEV_OPT_MULTICAST & apply_mask) {
+ if (apply_mask & DEV_OPT_MULTICAST) {
if (system_if_flags(dev->ifname, s->multicast ? IFF_MULTICAST : 0,
!s->multicast ? IFF_MULTICAST : 0) < 0)
s->flags &= ~DEV_OPT_MULTICAST;
}
- if (s->flags & DEV_OPT_SENDREDIRECTS & apply_mask)
+ if (apply_mask & DEV_OPT_SENDREDIRECTS)
system_set_sendredirects(dev, s->sendredirects ? "1" : "0");
+ if (apply_mask & DEV_OPT_DROP_V4_UNICAST_IN_L2_MULTICAST)
+ system_set_drop_v4_unicast_in_l2_multicast(dev, s->drop_v4_unicast_in_l2_multicast ? "1" : "0");
+ if (apply_mask & DEV_OPT_DROP_V6_UNICAST_IN_L2_MULTICAST)
+ system_set_drop_v6_unicast_in_l2_multicast(dev, s->drop_v6_unicast_in_l2_multicast ? "1" : "0");
+ if (apply_mask & DEV_OPT_DROP_GRATUITOUS_ARP)
+ system_set_drop_gratuitous_arp(dev, s->drop_gratuitous_arp ? "1" : "0");
+ if (apply_mask & DEV_OPT_DROP_UNSOLICITED_NA)
+ system_set_drop_unsolicited_na(dev, s->drop_unsolicited_na ? "1" : "0");
+ if (apply_mask & DEV_OPT_ARP_ACCEPT)
+ system_set_arp_accept(dev, s->arp_accept ? "1" : "0");
+ system_set_ethtool_settings(dev, s);
}
int system_if_up(struct device *dev)
{
- system_if_get_settings(dev, &dev->orig_settings);
- /* Only keep orig settings based on what needs to be set */
- dev->orig_settings.valid_flags = dev->orig_settings.flags;
- dev->orig_settings.flags &= dev->settings.flags;
- system_if_apply_settings(dev, &dev->settings, dev->settings.flags);
return system_if_flags(dev->ifname, IFF_UP, 0);
}
int system_if_down(struct device *dev)
{
- int ret = system_if_flags(dev->ifname, 0, IFF_UP);
- system_if_apply_settings(dev, &dev->orig_settings, dev->orig_settings.flags);
- return ret;
+ return system_if_flags(dev->ifname, 0, IFF_UP);
}
struct if_check_data {
return NL_STOP;
}
+struct bridge_vlan_check_data {
+ struct device *check_dev;
+ int ifindex;
+ int ret;
+ bool pending;
+};
+
+static void bridge_vlan_check_port(struct bridge_vlan_check_data *data,
+ struct bridge_vlan_port *port,
+ struct bridge_vlan_info *vinfo)
+{
+ uint16_t flags = 0, diff, mask;
+
+ if (port->flags & BRVLAN_F_PVID)
+ flags |= BRIDGE_VLAN_INFO_PVID;
+ if (port->flags & BRVLAN_F_UNTAGGED)
+ flags |= BRIDGE_VLAN_INFO_UNTAGGED;
+
+ diff = vinfo->flags ^ flags;
+ mask = BRVLAN_F_UNTAGGED | (flags & BRIDGE_VLAN_INFO_PVID);
+ if (diff & mask) {
+ data->ret = 1;
+ data->pending = false;
+ }
+
+ port->check = 1;
+}
+
+static void bridge_vlan_check_attr(struct bridge_vlan_check_data *data,
+ struct rtattr *attr)
+{
+ struct bridge_vlan_hotplug_port *port;
+ struct bridge_vlan_info *vinfo;
+ struct bridge_vlan *vlan;
+ struct rtattr *cur;
+ int rem = RTA_PAYLOAD(attr);
+ int i;
+
+ for (cur = RTA_DATA(attr); RTA_OK(cur, rem); cur = RTA_NEXT(cur, rem)) {
+ if (cur->rta_type != IFLA_BRIDGE_VLAN_INFO)
+ continue;
+
+ vinfo = RTA_DATA(cur);
+ vlan = vlist_find(&data->check_dev->vlans, &vinfo->vid, vlan, node);
+ if (!vlan) {
+ data->ret = 1;
+ data->pending = false;
+ return;
+ }
+
+ for (i = 0; i < vlan->n_ports; i++)
+ if (!vlan->ports[i].check)
+ bridge_vlan_check_port(data, &vlan->ports[i], vinfo);
+
+ list_for_each_entry(port, &vlan->hotplug_ports, list)
+ if (!port->port.check)
+ bridge_vlan_check_port(data, &port->port, vinfo);
+ }
+}
+
+static int bridge_vlan_check_cb(struct nl_msg *msg, void *arg)
+{
+ struct bridge_vlan_check_data *data = arg;
+ struct nlmsghdr *nh = nlmsg_hdr(msg);
+ struct ifinfomsg *ifi = NLMSG_DATA(nh);
+ struct rtattr *attr;
+ int rem;
+
+ if (nh->nlmsg_type != RTM_NEWLINK)
+ return NL_SKIP;
+
+ if (ifi->ifi_family != AF_BRIDGE)
+ return NL_SKIP;
+
+ if (ifi->ifi_index != data->ifindex)
+ return NL_SKIP;
+
+ attr = IFLA_RTA(ifi);
+ rem = nh->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi));
+ while (RTA_OK(attr, rem)) {
+ if (attr->rta_type == IFLA_AF_SPEC)
+ bridge_vlan_check_attr(data, attr);
+
+ attr = RTA_NEXT(attr, rem);
+ }
+
+ return NL_SKIP;
+}
+
+static int bridge_vlan_ack_cb(struct nl_msg *msg, void *arg)
+{
+ struct bridge_vlan_check_data *data = arg;
+ data->pending = false;
+ return NL_STOP;
+}
+
+static int bridge_vlan_error_cb(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg)
+{
+ struct bridge_vlan_check_data *data = arg;
+ data->pending = false;
+ return NL_STOP;
+}
+
+int system_bridge_vlan_check(struct device *dev, char *ifname)
+{
+ struct bridge_vlan_check_data data = {
+ .check_dev = dev,
+ .ifindex = if_nametoindex(ifname),
+ .ret = -1,
+ .pending = true,
+ };
+ static struct ifinfomsg ifi = {
+ .ifi_family = AF_BRIDGE
+ };
+ static struct rtattr ext_req = {
+ .rta_type = IFLA_EXT_MASK,
+ .rta_len = RTA_LENGTH(sizeof(uint32_t)),
+ };
+ uint32_t filter = RTEXT_FILTER_BRVLAN;
+ struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT);
+ struct bridge_vlan *vlan;
+ struct nl_msg *msg;
+ int i;
+
+ if (!data.ifindex)
+ return 0;
+
+ msg = nlmsg_alloc_simple(RTM_GETLINK, NLM_F_DUMP);
+
+ if (nlmsg_append(msg, &ifi, sizeof(ifi), 0) ||
+ nlmsg_append(msg, &ext_req, sizeof(ext_req), NLMSG_ALIGNTO) ||
+ nlmsg_append(msg, &filter, sizeof(filter), 0))
+ goto free;
+
+ vlist_for_each_element(&dev->vlans, vlan, node) {
+ struct bridge_vlan_hotplug_port *port;
+
+ for (i = 0; i < vlan->n_ports; i++) {
+ if (!strcmp(vlan->ports[i].ifname, ifname))
+ vlan->ports[i].check = 0;
+ else
+ vlan->ports[i].check = -1;
+ }
+
+ list_for_each_entry(port, &vlan->hotplug_ports, list) {
+ if (!strcmp(port->port.ifname, ifname))
+ port->port.check = 0;
+ else
+ port->port.check = -1;
+ }
+ }
+
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, bridge_vlan_check_cb, &data);
+ nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, bridge_vlan_ack_cb, &data);
+ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, bridge_vlan_ack_cb, &data);
+ nl_cb_err(cb, NL_CB_CUSTOM, bridge_vlan_error_cb, &data);
+
+ if (nl_send_auto_complete(sock_rtnl, msg) < 0)
+ goto free;
+
+ data.ret = 0;
+ while (data.pending)
+ nl_recvmsgs(sock_rtnl, cb);
+
+ vlist_for_each_element(&dev->vlans, vlan, node) {
+ struct bridge_vlan_hotplug_port *port;
+
+ for (i = 0; i < vlan->n_ports; i++) {
+ if (!vlan->ports[i].check) {
+ data.ret = 1;
+ break;
+ }
+ }
+
+ list_for_each_entry(port, &vlan->hotplug_ports, list) {
+ if (!port->port.check) {
+ data.ret = 1;
+ break;
+ }
+ }
+ }
+
+ goto out;
+
+free:
+ nlmsg_free(msg);
+out:
+ nl_cb_put(cb);
+ return data.ret;
+}
+
int system_if_check(struct device *dev)
{
struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT);
system_if_get_parent(struct device *dev)
{
char buf[64], *devname;
- int ifindex, iflink, len;
- FILE *f;
-
- snprintf(buf, sizeof(buf), "/sys/class/net/%s/iflink", dev->ifname);
- f = fopen(buf, "r");
- if (!f)
- return NULL;
-
- len = fread(buf, 1, sizeof(buf) - 1, f);
- fclose(f);
+ int ifindex, iflink;
- if (len <= 0)
+ if (system_get_dev_sysfs("iflink", dev->ifname, buf, sizeof(buf)) < 0)
return NULL;
- buf[len] = 0;
iflink = strtoul(buf, NULL, 0);
ifindex = system_if_resolve(dev);
if (!iflink || iflink == ifindex)
bool
system_if_force_external(const char *ifname)
{
- char buf[64];
struct stat s;
- snprintf(buf, sizeof(buf), "/sys/class/net/%s/phy80211", ifname);
- return stat(buf, &s) == 0;
+ return stat(dev_sysfs_path(ifname, "phy80211"), &s) == 0;
}
int
"rx_errors", "tx_bytes", "tx_window_errors",
"rx_fifo_errors", "tx_carrier_errors",
};
- char buf[64];
int stats_dir;
int i;
uint64_t val = 0;
- snprintf(buf, sizeof(buf), "/sys/class/net/%s/statistics", dev->ifname);
- stats_dir = open(buf, O_DIRECTORY);
+ stats_dir = open(dev_sysfs_path(dev->ifname, "statistics"), O_DIRECTORY);
if (stats_dir < 0)
return -1;
int system_flush_routes(void)
{
- const char *names[] = {
- "/proc/sys/net/ipv4/route/flush",
- "/proc/sys/net/ipv6/route/flush"
- };
+ const char *names[] = { "ipv4", "ipv6" };
int fd, i;
for (i = 0; i < ARRAY_SIZE(names); i++) {
- fd = open(names[i], O_WRONLY);
+ snprintf(dev_buf, sizeof(dev_buf), "%s/sys/net/%s/route/flush", proc_path, names[i]);
+ fd = open(dev_buf, O_WRONLY);
if (fd < 0)
continue;
char buf[64];
int fd;
- snprintf(buf, sizeof(buf), "/proc/sys/net/ipv6/conf/%s/mtu",
- dev->ifname);
-
- fd = open(buf, O_RDWR);
+ fd = open(dev_sysctl_path("ipv6/conf", dev->ifname, "mtu"), O_RDWR);
if (fd < 0)
return ret;