diff options
-rw-r--r-- | bridge.c | 6 | ||||
-rw-r--r-- | device.c | 9 | ||||
-rw-r--r-- | device.h | 3 | ||||
-rw-r--r-- | system-linux.c | 44 |
4 files changed, 60 insertions, 2 deletions
@@ -154,6 +154,12 @@ bridge_enable_member(struct bridge_member *bm) if (!bm->present) return 0; + /* Disable IPv6 for bridge members */ + if (!(bm->dev.dev->settings.flags & DEV_OPT_IPV6)) { + bm->dev.dev->settings.ipv6 = 0; + bm->dev.dev->settings.flags |= DEV_OPT_IPV6; + } + ret = device_claim(&bm->dev); if (ret < 0) goto error; @@ -37,6 +37,7 @@ static const struct blobmsg_policy dev_attrs[__DEV_ATTR_MAX] = { [DEV_ATTR_MACADDR] = { .name = "macaddr", .type = BLOBMSG_TYPE_STRING }, [DEV_ATTR_TXQUEUELEN] = { .name = "txqueuelen", .type = BLOBMSG_TYPE_INT32 }, [DEV_ATTR_ENABLED] = { .name = "enabled", .type = BLOBMSG_TYPE_BOOL }, + [DEV_ATTR_IPV6] = { .name = "ipv6", .type = BLOBMSG_TYPE_BOOL }, }; const struct uci_blob_param_list device_attr_list = { @@ -139,6 +140,7 @@ device_merge_settings(struct device *dev, struct device_settings *n) memcpy(n->macaddr, (s->flags & DEV_OPT_MACADDR ? s->macaddr : os->macaddr), sizeof(n->macaddr)); + n->ipv6 = s->flags & DEV_OPT_IPV6 ? s->ipv6 : os->ipv6; n->flags = s->flags | os->flags; } @@ -172,6 +174,11 @@ device_init_settings(struct device *dev, struct blob_attr **tb) } } + if ((cur = tb[DEV_ATTR_IPV6])) { + s->ipv6 = blobmsg_get_bool(cur); + s->flags |= DEV_OPT_IPV6; + } + device_set_disabled(dev, disabled); } @@ -705,6 +712,8 @@ device_dump_status(struct blob_buf *b, struct device *dev) blobmsg_add_string(b, "macaddr", format_macaddr(st.macaddr)); if (st.flags & DEV_OPT_TXQUEUELEN) blobmsg_add_u32(b, "txqueuelen", st.txqueuelen); + if (st.flags & DEV_OPT_IPV6) + blobmsg_add_u8(b, "ipv6", st.ipv6); } s = blobmsg_open_table(b, "statistics"); @@ -31,6 +31,7 @@ enum { DEV_ATTR_MACADDR, DEV_ATTR_TXQUEUELEN, DEV_ATTR_ENABLED, + DEV_ATTR_IPV6, __DEV_ATTR_MAX, }; @@ -60,6 +61,7 @@ enum { DEV_OPT_MTU = (1 << 0), DEV_OPT_MACADDR = (1 << 1), DEV_OPT_TXQUEUELEN = (1 << 2), + DEV_OPT_IPV6 = (1 << 3), }; /* events broadcasted to all users of a device */ @@ -105,6 +107,7 @@ struct device_settings { unsigned int mtu; unsigned int txqueuelen; uint8_t macaddr[6]; + bool ipv6; }; /* 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) |