Skip to content

Commit

Permalink
bridge: Implement MLD Querier wake-up calls / Android bug workaround
Browse files Browse the repository at this point in the history
Implement a configurable MLD Querier wake-up calls "feature" which
works around a widely spread Android bug in connection with IGMP/MLD
snooping.

Currently there are mobile devices (e.g. Android) which are not able
to receive and respond to MLD Queries reliably because the Wifi driver
filters a lot of ICMPv6 when the device is asleep - including
MLD. This in turn breaks IPv6 communication when MLD Snooping is
enabled. However there is one ICMPv6 type which is allowed to pass and
which can be used to wake up the mobile device: ICMPv6 Echo Requests.

If this bridge is the selected MLD Querier then setting
"multicast_wakeupcall" to a number n greater than 0 will send n
ICMPv6 Echo Requests to each host behind this port to wake
them up with each MLD Query. Upon receiving a matching ICMPv6 Echo
Reply an MLD Query with a unicast ethernet destination will be sent
to the specific host(s).

Link: https://issuetracker.google.com/issues/149630944
Link: freifunk-gluon/gluon#1832

Signed-off-by: Linus Lüssing <[email protected]>
  • Loading branch information
T-X authored and intel-lab-lkp committed Aug 16, 2020
1 parent bfdd5aa commit fdde3c8
Show file tree
Hide file tree
Showing 9 changed files with 374 additions and 8 deletions.
1 change: 1 addition & 0 deletions include/linux/if_bridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ struct br_ip_list {
#define BR_MRP_AWARE BIT(17)
#define BR_MRP_LOST_CONT BIT(18)
#define BR_MRP_LOST_IN_CONT BIT(19)
#define BR_MULTICAST_WAKEUPCALL BIT(20)

#define BR_DEFAULT_AGEING_TIME (300 * HZ)

Expand Down
1 change: 1 addition & 0 deletions include/uapi/linux/if_link.h
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ enum {
IFLA_BRPORT_BACKUP_PORT,
IFLA_BRPORT_MRP_RING_OPEN,
IFLA_BRPORT_MRP_IN_OPEN,
IFLA_BRPORT_MCAST_WAKEUPCALL,
__IFLA_BRPORT_MAX
};
#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
Expand Down
26 changes: 26 additions & 0 deletions net/bridge/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,32 @@ config BRIDGE_IGMP_SNOOPING

If unsure, say Y.

config BRIDGE_IGMP_SNOOPING_WAKEUPCALLS
bool "MLD Querier wake-up calls"
depends on BRIDGE_IGMP_SNOOPING
depends on IPV6
help
If you say Y here, then the MLD Snooping Querier will be built
with a per bridge port wake-up call "feature"/workaround.

Currently there are mobile devices (e.g. Android) which are not able
to receive and respond to MLD Queries reliably because the Wifi driver
filters a lot of ICMPv6 when the device is asleep - including MLD.
This in turn breaks IPv6 communication when MLD Snooping is enabled.
However there is one ICMPv6 type which is allowed to pass and
which can be used to wake up the mobile device: ICMPv6 Echo Requests.

If this bridge is the selected MLD Querier then setting
"multicast_wakeupcall" to a number n greater than 0 will send n
ICMPv6 Echo Requests to each host behind this port to wake them up
with each MLD Query. Upon receiving a matching ICMPv6 Echo Reply
an MLD Query with a unicast ethernet destination will be sent to the
specific host(s).

Say N to exclude this support and reduce the binary size.

If unsure, say N.

config BRIDGE_VLAN_FILTERING
bool "VLAN filtering"
depends on BRIDGE
Expand Down
10 changes: 10 additions & 0 deletions net/bridge/br_fdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ static void fdb_rcu_free(struct rcu_head *head)
{
struct net_bridge_fdb_entry *ent
= container_of(head, struct net_bridge_fdb_entry, rcu);

#ifdef CONFIG_BRIDGE_IGMP_SNOOPING_WAKEUPCALLS
del_timer_sync(&ent->wakeupcall_timer);
#endif
kmem_cache_free(br_fdb_cache, ent);
}

Expand Down Expand Up @@ -511,6 +515,12 @@ static struct net_bridge_fdb_entry *fdb_create(struct net_bridge *br,
fdb->key.vlan_id = vid;
fdb->flags = flags;
fdb->updated = fdb->used = jiffies;

#ifdef CONFIG_BRIDGE_IGMP_SNOOPING_WAKEUPCALLS
timer_setup(&fdb->wakeupcall_timer,
br_multicast_send_wakeupcall, 0);
#endif

if (rhashtable_lookup_insert_fast(&br->fdb_hash_tbl,
&fdb->rhnode,
br_fdb_rht_params)) {
Expand Down
4 changes: 3 additions & 1 deletion net/bridge/br_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,10 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
if (dst) {
unsigned long now = jiffies;

if (test_bit(BR_FDB_LOCAL, &dst->flags))
if (test_bit(BR_FDB_LOCAL, &dst->flags)) {
br_multicast_wakeupcall_rcv(br, p, skb, vid);
return br_pass_frame_up(skb);
}

if (now != dst->used)
dst->used = now;
Expand Down
Loading

0 comments on commit fdde3c8

Please sign in to comment.