summaryrefslogtreecommitdiffhomepage
path: root/system-linux.c
diff options
context:
space:
mode:
authorHans Dedecker <dedeckeh@gmail.com>2014-04-07 13:30:52 +0200
committerFelix Fietkau <nbd@openwrt.org>2014-04-26 21:44:19 +0200
commit98ca67469da70accd710b14c28e77be2126170a8 (patch)
tree3cc649f08f9743fff2f8367dee74162ed30ace96 /system-linux.c
parent08d35c7a59a182b9ef05d95ca3c583806b2ba924 (diff)
netifd: Add interface config support to enable/disable IPv6 in the kernel per device
Main use case is being able to disable IPv6 on (a) WAN interface(s) when only IPv4 connectivity is offered or 6rd is used. Signed-off-by: Hans Dedecker <dedeckeh@gmail.com>
Diffstat (limited to 'system-linux.c')
-rw-r--r--system-linux.c44
1 files changed, 42 insertions, 2 deletions
diff --git a/system-linux.c b/system-linux.c
index 7cec649..8f46705 100644
--- a/system-linux.c
+++ b/system-linux.c
@@ -211,6 +211,40 @@ 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);
}
+static int system_get_sysctl(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 int
+system_get_dev_sysctl(const char *path, const char *device, char *buf, const size_t buf_sz)
+{
+ snprintf(dev_buf, sizeof(dev_buf), path, device);
+ return system_get_sysctl(dev_buf, buf, buf_sz);
+}
+
+static int system_get_disable_ipv6(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);
+}
+
#ifndef IFF_LOWER_UP
#define IFF_LOWER_UP 0x10000
#endif
@@ -380,7 +414,6 @@ int system_bridge_addif(struct device *bridge, struct device *dev)
{
char *oldbr;
- system_set_disable_ipv6(dev, "1");
oldbr = system_get_bridge(dev->ifname, dev_buf, sizeof(dev_buf));
if (oldbr && !strcmp(oldbr, bridge->ifname))
return 0;
@@ -390,7 +423,6 @@ int system_bridge_addif(struct device *bridge, struct device *dev)
int system_bridge_delif(struct device *bridge, struct device *dev)
{
- system_set_disable_ipv6(dev, "0");
return system_bridge_if(bridge->ifname, dev, SIOCBRDELIF, NULL);
}
@@ -777,6 +809,7 @@ static void
system_if_get_settings(struct device *dev, struct device_settings *s)
{
struct ifreq ifr;
+ char buf[10];
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, dev->ifname, sizeof(ifr.ifr_name));
@@ -795,6 +828,11 @@ system_if_get_settings(struct device *dev, struct device_settings *s)
memcpy(s->macaddr, &ifr.ifr_hwaddr.sa_data, sizeof(s->macaddr));
s->flags |= DEV_OPT_MACADDR;
}
+
+ if (!system_get_disable_ipv6(dev, buf, sizeof(buf))) {
+ s->ipv6 = !strtoul(buf, NULL, 0);
+ s->flags |= DEV_OPT_IPV6;
+ }
}
void
@@ -823,6 +861,8 @@ system_if_apply_settings(struct device *dev, struct device_settings *s, unsigned
if (ioctl(sock_ioctl, SIOCSIFHWADDR, &ifr) < 0)
s->flags &= ~DEV_OPT_MACADDR;
}
+ if (s->flags & DEV_OPT_IPV6 & apply_mask)
+ system_set_disable_ipv6(dev, s->ipv6 ? "0" : "1");
}
int system_if_up(struct device *dev)