bridge: Allow setting multicast_to_unicast option
authorLinus Lüssing <linus.luessing@c0d3.blue>
Sun, 23 Aug 2015 15:19:27 +0000 (17:19 +0200)
committerFelix Fietkau <nbd@openwrt.org>
Tue, 25 Aug 2015 06:46:30 +0000 (08:46 +0200)
With this patch the multicast_to_unicast feature can be disabled for all
wireless interfaces via an according option on the uci bridge interface.

This patch also exports the setting information to wireless handler
scripts. The hostapd script will need that information to determine
whether to enable or disable ap-isolation, for instance.

Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
device.c
device.h
scripts/netifd-wireless.sh
system-linux.c
wireless.c

index 66eb6d46f619289c1387fe31f28879038e570df5..37687730e775edcf36a2f5f22ee260c005d3ad18 100644 (file)
--- a/device.c
+++ b/device.c
@@ -48,6 +48,7 @@ static const struct blobmsg_policy dev_attrs[__DEV_ATTR_MAX] = {
        [DEV_ATTR_RPS] = { .name = "rps", .type = BLOBMSG_TYPE_BOOL },
        [DEV_ATTR_XPS] = { .name = "xps", .type = BLOBMSG_TYPE_BOOL },
        [DEV_ATTR_DADTRANSMITS] = { .name = "dadtransmits", .type = BLOBMSG_TYPE_INT32 },
+       [DEV_ATTR_MULTICAST_TO_UNICAST] = { .name = "multicast_to_unicast", .type = BLOBMSG_TYPE_BOOL },
 };
 
 const struct uci_blob_param_list device_attr_list = {
@@ -174,6 +175,7 @@ device_merge_settings(struct device *dev, struct device_settings *n)
                s->neigh6reachabletime : os->neigh6reachabletime;
        n->dadtransmits = s->flags & DEV_OPT_DADTRANSMITS ?
                s->dadtransmits : os->dadtransmits;
+       n->multicast_to_unicast = s->multicast_to_unicast;
        n->flags = s->flags | os->flags;
 }
 
@@ -274,6 +276,11 @@ device_init_settings(struct device *dev, struct blob_attr **tb)
                s->flags |= DEV_OPT_DADTRANSMITS;
        }
 
+       if ((cur = tb[DEV_ATTR_MULTICAST_TO_UNICAST])) {
+               s->multicast_to_unicast = blobmsg_get_bool(cur);
+               s->flags |= DEV_OPT_MULTICAST_TO_UNICAST;
+       }
+
        device_set_disabled(dev, disabled);
 }
 
@@ -891,6 +898,8 @@ device_dump_status(struct blob_buf *b, struct device *dev)
                }
                if (st.flags & DEV_OPT_DADTRANSMITS)
                        blobmsg_add_u32(b, "dadtransmits", st.dadtransmits);
+               if (st.flags & DEV_OPT_MULTICAST_TO_UNICAST)
+                       blobmsg_add_u8(b, "multicast_to_unicast", st.multicast_to_unicast);
        }
 
        s = blobmsg_open_table(b, "statistics");
index 77ebe842410af9506217518f3ad747b7f61515d3..c31399c9c5f9b28ed5caf43ecc6e1d5ad1bcaab3 100644 (file)
--- a/device.h
+++ b/device.h
@@ -42,6 +42,7 @@ enum {
        DEV_ATTR_RPS,
        DEV_ATTR_XPS,
        DEV_ATTR_DADTRANSMITS,
+       DEV_ATTR_MULTICAST_TO_UNICAST,
        __DEV_ATTR_MAX,
 };
 
@@ -84,6 +85,7 @@ enum {
        DEV_OPT_XPS                     = (1 << 11),
        DEV_OPT_MTU6                    = (1 << 12),
        DEV_OPT_DADTRANSMITS            = (1 << 13),
+       DEV_OPT_MULTICAST_TO_UNICAST    = (1 << 14),
 };
 
 /* events broadcasted to all users of a device */
@@ -141,6 +143,7 @@ struct device_settings {
        bool rps;
        bool xps;
        unsigned int dadtransmits;
+       bool multicast_to_unicast;
 };
 
 /*
index f981f1b2803aee1f55b4dba947b2ea34a5e2aaa1..83a8223e422cdf439b2401595245f2f29a8cd023 100644 (file)
@@ -274,6 +274,7 @@ for_each_interface() {
                json_select "$_w_iface"
                if [ -n "$_w_types" ]; then
                        json_get_var network_bridge bridge
+                       json_get_var multicast_to_unicast multicast_to_unicast
                        json_select config
                        _wireless_set_brsnoop_isolation "$multicast_to_unicast"
                        json_get_var _w_type mode
index 9c4bea63b9b51b8d7cef03165c413c0d0a10db10..944245cc00122af5fdf3becba92874dd2752ab55 100644 (file)
@@ -567,14 +567,19 @@ static char *system_get_bridge(const char *name, char *buf, int buflen)
 }
 
 static void
-system_bridge_set_wireless(struct device *dev)
+system_bridge_set_wireless(struct device *bridge, struct device *dev)
 {
+       bool mcast_to_ucast = true;
        bool hairpin = true;
 
-       if (dev->wireless_isolate)
+       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 = false;
 
-       system_bridge_set_multicast_to_unicast(dev, "1");
+       system_bridge_set_multicast_to_unicast(dev, mcast_to_ucast ? "1" : "0");
        system_bridge_set_hairpin_mode(dev, hairpin ? "1" : "0");
 }
 
@@ -588,7 +593,7 @@ int system_bridge_addif(struct device *bridge, struct device *dev)
                ret = system_bridge_if(bridge->ifname, dev, SIOCBRADDIF, NULL);
 
        if (dev->wireless)
-               system_bridge_set_wireless(dev);
+               system_bridge_set_wireless(bridge, dev);
 
        return ret;
 }
index 337f56306c8a20606268678e6271239f76a46782..d0d2942216f58cdf10756937086c55619ed21f97 100644 (file)
@@ -92,6 +92,10 @@ vif_config_add_bridge(struct blob_buf *buf, struct blob_attr *networks, bool pre
                dev->hotplug_ops->prepare(dev);
 
        blobmsg_add_string(buf, "bridge", dev->ifname);
+
+       if (dev->settings.flags & DEV_OPT_MULTICAST_TO_UNICAST)
+               blobmsg_add_u8(buf, "multicast_to_unicast",
+                              dev->settings.multicast_to_unicast);
 }
 
 static void