[PATCH] ath9k: fix data bus crash when setting nf_override via debugfs

2021-02-09 Thread Linus Lüssing
From: Linus Lüssing 

When trying to set the noise floor via debugfs, a "data bus error"
crash like the following can happen:

[   88.433133] Data bus error, epc == 80221c28, ra == 83314e60
[   88.438895] Oops[#1]:
[   88.441246] CPU: 0 PID: 7263 Comm: sh Not tainted 4.14.195 #0
[   88.447174] task: 838a1c20 task.stack: 82d5e000
[   88.451847] $ 0   :  0030 deadc0de 83141de4
[   88.457248] $ 4   : b810a2c4 a2c4 83230fd4 
[   88.462652] $ 8   : 000a  0001 
[   88.468055] $12   : 7f8ef318   77f802a0
[   88.473457] $16   : 83230080 0002 001b 83230080
[   88.478861] $20   : 83a1c3f8 00841000 77f7adb0 ff92
[   88.484263] $24   : 0fa4 77edd860
[   88.489665] $28   : 82d5e000 82d5fda8  83314e60
[   88.495070] Hi: 
[   88.498044] Lo: 
[   88.501040] epc   : 80221c28 ioread32+0x8/0x10
[   88.505671] ra: 83314e60 ath9k_hw_loadnf+0x88/0x520 [ath9k_hw]
[   88.512049] Status: 1000fc03 KERNEL EXL IE
[   88.516369] Cause : 5080801c (ExcCode 07)
[   88.520508] PrId  : 00019374 (MIPS 24Kc)
[   88.524556] Modules linked in: ath9k ath9k_common pppoe ppp_async l2tp_ppp 
cdc_mbim batman_adv ath9k_hw ath sr9700 smsc95xx sierra_net rndis_host qmi_wwan 
pppox ppp_generic pl2303 nf_conntrack_ipv6 mcs7830 mac80211 kalmia iptable_nat 
ipt_REJECT ipt_MASQUERADE huawei_cdc_ncm ftdi_sio dm9601 cfg80211 cdc_subset 
cdc_ncm cdc_ether cdc_eem ax88179_178a asix xt_time xt_tcpudp xt_tcpmss 
xt_statistic xt_state xt_nat xt_multiport xt_mark xt_mac xt_limit xt_length 
xt_hl xt_ecn xt_dscp xt_conntrack xt_comment xt_TCPMSS xt_REDIRECT xt_NETMAP 
xt_LOG xt_HL xt_FLOWOFFLOAD xt_DSCP xt_CLASSIFY usbserial usbnet usbhid slhc 
rtl8150 r8152 pegasus nf_reject_ipv4 nf_nat_redirect nf_nat_masquerade_ipv4 
nf_conntrack_ipv4 nf_nat_ipv4 nf_nat nf_log_ipv4 nf_flow_table_hw nf_flow_table 
nf_defrag_ipv6 nf_defrag_ipv4 nf_conntrack
[   88.597894]  libcrc32c kaweth iptable_mangle iptable_filter ipt_ECN ipheth 
ip_tables hso hid_generic crc_ccitt compat cdc_wdm cdc_acm br_netfilter hid 
evdev input_core nf_log_ipv6 nf_log_common ip6table_mangle ip6table_filter 
ip6_tables ip6t_REJECT x_tables nf_reject_ipv6 l2tp_netlink l2tp_core 
udp_tunnel ip6_udp_tunnel xfrm6_mode_tunnel xfrm6_mode_transport 
xfrm6_mode_beet ipcomp6 xfrm6_tunnel esp6 ah6 xfrm4_tunnel xfrm4_mode_tunnel 
xfrm4_mode_transport xfrm4_mode_beet ipcomp esp4 ah4 tunnel6 tunnel4 tun 
xfrm_user xfrm_ipcomp af_key xfrm_algo sha256_generic sha1_generic 
jitterentropy_rng drbg md5 hmac echainiv des_generic deflate zlib_inflate 
zlib_deflate cbc authenc crypto_acompress ehci_platform ehci_hcd 
gpio_button_hotplug usbcore nls_base usb_common crc16 mii aead crypto_null 
cryptomgr crc32c_generic
[   88.671671]  crypto_hash
[   88.674292] Process sh (pid: 7263, threadinfo=82d5e000, task=838a1c20, 
tls=77f81efc)
[   88.682279] Stack : 8060 0008 0200    
 0002
[   88.690916] 8050 83230080 82d5fe22 00841000 77f7adb0  
 83156858
[   88.699553]  8352fa00 83ad62b0 835302a8  300a00f8 
0003 82d5fe38
[   88.708190] 82d5fef4 0001 77f54dc4 77f8 77f7adb0 c79fe901 
 
[   88.716828] 8051 0002 00841000 77f54dc4 77f8 801ce4cc 
000b 41824292
[   88.725465] ...
[   88.727994] Call Trace:
[   88.730532] [<80221c28>] ioread32+0x8/0x10
[   88.734765] Code:   8c82  000f <03e8>   08088708 
   aca4  03e8
[   88.744846]
[   88.746464] ---[ end trace db226b2de1b69b9e ]---
[   88.753477] Kernel panic - not syncing: Fatal exception
[   88.759981] Rebooting in 3 seconds..

The "REG_READ(ah, AR_PHY_AGC_CONTROL)" in ath9k_hw_loadnf() does not
like being called when the hardware is asleep, leading to this crash.

The easiest way to reproduce this is trying to set nf_override while
the hardware is down:

  $ ip link set down dev wlan0
  $ echo "-85" > /sys/kernel/debug/ieee80211/phy0/ath9k/nf_override

Fixing this crash by waking the hardware up before trying to set the
noise floor. Similar to what other ath9k debugfs files do.

Tested on a Lima board from 8devices, which has a QCA 4531 chipset.

Fixes: b90189759a7f ("ath9k: add noise floor override option")
Cc: Simon Wunderlich 
Signed-off-by: Linus Lüssing 
---
 drivers/net/wireless/ath/ath9k/debug.c | 5 -
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath9k/debug.c 
b/drivers/net/wireless/ath/ath9k/debug.c
index 017a43bc400c..4c81b1d7f417 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -1223,8 +1223,11 @@ static ssize_t write_file_nf_override(struct file *file,
 
ah->nf_override = val;
 
-   if (ah->curchan)
+   if (ah->curchan) {
+   ath9k_ps_wakeup(sc);
ath9k

Re: [PATCH net] bridge: mcast: Fix MLD2 Report IPv6 payload length check

2020-07-06 Thread Linus Lüssing
On Sun, Jul 05, 2020 at 11:18:36PM +0300, Nikolay Aleksandrov wrote:
> > > By the way, I can't verify at the moment, but I think we can drop that 
> > > whole
> > > hunk altogether since skb_header_pointer() is used and it will simply 
> > > return
> > > an error if there isn't enough data for nsrcs.
> > > 
> > 
> > Hm, while unlikely, the IPv6 packet / header payload length might be
> > shorter than the frame / skb size.
> > 
> > And even though it wouldn't crash reading over the IPv6 packet
> > length, especially as skb_header_pointer() is used, I think we should
> > still avoid reading over the size indicated by the IPv6 header payload
> > length field, to stay protocol compliant.
> > 
> > Does that make sense?
> > 
> 
> Sure, I just thought the ipv6_mc_may_pull() call after that includes those 2 
> bytes as well, so
> we're covered. That is, it seems to be doing the same check with the full 
> grec size included.
> 

Ah, okay, that's what you mean! You're right, technically the
ipv6_mc_may_pull() later would cover it, too. And it should work,
even if nsrcs were outside of the IPv6 packet and had a bogus
value. (I think.)

My brain linearly parsing the parser code would probably get a bit
confused initially, as it'd look like a bit like a bug. But the
current check for nsrcs might look confusing, too (q.e.d.).

So as you prefer, I'd be okay with both leaving that check for
consistency or removing it for brevity.


Re: [PATCH net] bridge: mcast: Fix MLD2 Report IPv6 payload length check

2020-07-05 Thread Linus Lüssing
On Sun, Jul 05, 2020 at 10:11:39PM +0300, Nikolay Aleksandrov wrote:
> On 7/5/20 10:08 PM, Linus Lüssing wrote:
> > On Sun, Jul 05, 2020 at 09:33:13PM +0300, Nikolay Aleksandrov wrote:
> > > On 05/07/2020 21:22, Linus Lüssing wrote:
> > > > Commit e57f61858b7c ("net: bridge: mcast: fix stale nsrcs pointer in
> > > > igmp3/mld2 report handling") introduced a small bug which would 
> > > > potentially
> > > > lead to accepting an MLD2 Report with a broken IPv6 header payload 
> > > > length
> > > > field.
> > > > 
> > > > The check needs to take into account the 2 bytes for the "Number of
> > > > Sources" field in the "Multicast Address Record" before reading it.
> > > > And not the size of a pointer to this field.
> > > > 
> > > > Fixes: e57f61858b7c ("net: bridge: mcast: fix stale nsrcs pointer in 
> > > > igmp3/mld2 report handling")
> > > > Signed-off-by: Linus Lüssing 
> > > > ---
> > > >   net/bridge/br_multicast.c | 2 +-
> > > >   1 file changed, 1 insertion(+), 1 deletion(-)
> > > > 
> > > 
> > > I'd rather be more concerned with it rejecting a valid report due to 
> > > wrong size. The ptr
> > > size would always be bigger. :)
> > > 
> > > Thanks!
> > > Acked-by: Nikolay Aleksandrov 
> > 
> > Aiy, you're right, it's the other way round. I'll update the
> > commit message and send a v2 in a minute, with your Acked-by
> > included.
> > 
> 
> By the way, I can't verify at the moment, but I think we can drop that whole
> hunk altogether since skb_header_pointer() is used and it will simply return
> an error if there isn't enough data for nsrcs.
> 

Hm, while unlikely, the IPv6 packet / header payload length might be
shorter than the frame / skb size.

And even though it wouldn't crash reading over the IPv6 packet
length, especially as skb_header_pointer() is used, I think we should
still avoid reading over the size indicated by the IPv6 header payload
length field, to stay protocol compliant.

Does that make sense?


[PATCH net v2] bridge: mcast: Fix MLD2 Report IPv6 payload length check

2020-07-05 Thread Linus Lüssing
Commit e57f61858b7c ("net: bridge: mcast: fix stale nsrcs pointer in
igmp3/mld2 report handling") introduced a bug in the IPv6 header payload
length check which would potentially lead to rejecting a valid MLD2 Report:

The check needs to take into account the 2 bytes for the "Number of
Sources" field in the "Multicast Address Record" before reading it.
And not the size of a pointer to this field.

Fixes: e57f61858b7c ("net: bridge: mcast: fix stale nsrcs pointer in igmp3/mld2 
report handling")
Acked-by: Nikolay Aleksandrov 
Signed-off-by: Linus Lüssing 
---
Changelog v2:
* updated commit message, the issue is accidentally rejcting a valid and
  not accepting an invalid MLD2 Report

 net/bridge/br_multicast.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 83490bf73a13..4c4a93abde68 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1000,21 +1000,21 @@ static int br_ip6_multicast_mld2_report(struct 
net_bridge *br,
num = ntohs(icmp6h->icmp6_dataun.un_data16[1]);
len = skb_transport_offset(skb) + sizeof(*icmp6h);
 
for (i = 0; i < num; i++) {
__be16 *_nsrcs, __nsrcs;
u16 nsrcs;
 
nsrcs_offset = len + offsetof(struct mld2_grec, grec_nsrcs);
 
if (skb_transport_offset(skb) + ipv6_transport_len(skb) <
-   nsrcs_offset + sizeof(_nsrcs))
+   nsrcs_offset + sizeof(__nsrcs))
return -EINVAL;
 
_nsrcs = skb_header_pointer(skb, nsrcs_offset,
sizeof(__nsrcs), &__nsrcs);
if (!_nsrcs)
return -EINVAL;
 
nsrcs = ntohs(*_nsrcs);
grec_len = struct_size(grec, grec_src, nsrcs);
 
-- 
2.27.0



Re: [PATCH net] bridge: mcast: Fix MLD2 Report IPv6 payload length check

2020-07-05 Thread Linus Lüssing
On Sun, Jul 05, 2020 at 09:33:13PM +0300, Nikolay Aleksandrov wrote:
> On 05/07/2020 21:22, Linus Lüssing wrote:
> > Commit e57f61858b7c ("net: bridge: mcast: fix stale nsrcs pointer in
> > igmp3/mld2 report handling") introduced a small bug which would potentially
> > lead to accepting an MLD2 Report with a broken IPv6 header payload length
> > field.
> > 
> > The check needs to take into account the 2 bytes for the "Number of
> > Sources" field in the "Multicast Address Record" before reading it.
> > And not the size of a pointer to this field.
> > 
> > Fixes: e57f61858b7c ("net: bridge: mcast: fix stale nsrcs pointer in 
> > igmp3/mld2 report handling")
> > Signed-off-by: Linus Lüssing 
> > ---
> >  net/bridge/br_multicast.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> > 
> 
> I'd rather be more concerned with it rejecting a valid report due to wrong 
> size. The ptr
> size would always be bigger. :)
> 
> Thanks!
> Acked-by: Nikolay Aleksandrov 

Aiy, you're right, it's the other way round. I'll update the
commit message and send a v2 in a minute, with your Acked-by
included.


[PATCH net] bridge: mcast: Fix MLD2 Report IPv6 payload length check

2020-07-05 Thread Linus Lüssing
Commit e57f61858b7c ("net: bridge: mcast: fix stale nsrcs pointer in
igmp3/mld2 report handling") introduced a small bug which would potentially
lead to accepting an MLD2 Report with a broken IPv6 header payload length
field.

The check needs to take into account the 2 bytes for the "Number of
Sources" field in the "Multicast Address Record" before reading it.
And not the size of a pointer to this field.

Fixes: e57f61858b7c ("net: bridge: mcast: fix stale nsrcs pointer in igmp3/mld2 
report handling")
Signed-off-by: Linus Lüssing 
---
 net/bridge/br_multicast.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 83490bf73a13..4c4a93abde68 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1000,21 +1000,21 @@ static int br_ip6_multicast_mld2_report(struct 
net_bridge *br,
num = ntohs(icmp6h->icmp6_dataun.un_data16[1]);
len = skb_transport_offset(skb) + sizeof(*icmp6h);
 
for (i = 0; i < num; i++) {
__be16 *_nsrcs, __nsrcs;
u16 nsrcs;
 
nsrcs_offset = len + offsetof(struct mld2_grec, grec_nsrcs);
 
if (skb_transport_offset(skb) + ipv6_transport_len(skb) <
-   nsrcs_offset + sizeof(_nsrcs))
+   nsrcs_offset + sizeof(__nsrcs))
return -EINVAL;
 
_nsrcs = skb_header_pointer(skb, nsrcs_offset,
sizeof(__nsrcs), &__nsrcs);
if (!_nsrcs)
return -EINVAL;
 
nsrcs = ntohs(*_nsrcs);
grec_len = struct_size(grec, grec_src, nsrcs);
 
-- 
2.27.0



[PATCH net-next v2 3/4] bridge: join all-snoopers multicast address

2019-01-20 Thread Linus Lüssing
Next to snooping IGMP/MLD queries RFC4541, section 2.1.1.a) recommends
to snoop multicast router advertisements to detect multicast routers.

Multicast router advertisements are sent to an "all-snoopers"
multicast address. To be able to receive them reliably, we need to
join this group.

Otherwise other snooping switches might refrain from forwarding these
advertisements to us.

Signed-off-by: Linus Lüssing 
---
 include/uapi/linux/in.h   |  9 +++---
 net/bridge/br_multicast.c | 72 ++-
 net/ipv6/mcast.c  |  2 ++
 3 files changed, 78 insertions(+), 5 deletions(-)

diff --git a/include/uapi/linux/in.h b/include/uapi/linux/in.h
index f6052e70bf40..7ab685cacb8f 100644
--- a/include/uapi/linux/in.h
+++ b/include/uapi/linux/in.h
@@ -292,10 +292,11 @@ struct sockaddr_in {
 #defineIN_LOOPBACK(a)  long int) (a)) & 0xff00) == 
0x7f00)
 
 /* Defines for Multicast INADDR */
-#define INADDR_UNSPEC_GROUP0xe000U /* 224.0.0.0   */
-#define INADDR_ALLHOSTS_GROUP  0xe001U /* 224.0.0.1   */
-#define INADDR_ALLRTRS_GROUP0xe002U/* 224.0.0.2 */
-#define INADDR_MAX_LOCAL_GROUP  0xe0ffU/* 224.0.0.255 */
+#define INADDR_UNSPEC_GROUP0xe000U /* 224.0.0.0   */
+#define INADDR_ALLHOSTS_GROUP  0xe001U /* 224.0.0.1   */
+#define INADDR_ALLRTRS_GROUP   0xe002U /* 224.0.0.2 */
+#define INADDR_ALLSNOOPERS_GROUP   0xe06aU /* 224.0.0.106 */
+#define INADDR_MAX_LOCAL_GROUP 0xe0ffU /* 224.0.0.255 */
 #endif
 
 /*  contains the htonl type stuff.. */
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 156c4905639e..2366f4a2780e 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1780,6 +1780,68 @@ void br_multicast_init(struct net_bridge *br)
INIT_HLIST_HEAD(&br->mdb_list);
 }
 
+static void br_ip4_multicast_join_snoopers(struct net_bridge *br)
+{
+   struct in_device *in_dev = in_dev_get(br->dev);
+
+   if (!in_dev)
+   return;
+
+   ip_mc_inc_group(in_dev, htonl(INADDR_ALLSNOOPERS_GROUP));
+   in_dev_put(in_dev);
+}
+
+#if IS_ENABLED(CONFIG_IPV6)
+static void br_ip6_multicast_join_snoopers(struct net_bridge *br)
+{
+   struct in6_addr addr;
+
+   ipv6_addr_set(&addr, htonl(0xff02), 0, 0, htonl(0x6a));
+   ipv6_dev_mc_inc(br->dev, &addr);
+}
+#else
+static inline void br_ip6_multicast_join_snoopers(struct net_bridge *br)
+{
+}
+#endif
+
+static void br_multicast_join_snoopers(struct net_bridge *br)
+{
+   br_ip4_multicast_join_snoopers(br);
+   br_ip6_multicast_join_snoopers(br);
+}
+
+static void br_ip4_multicast_leave_snoopers(struct net_bridge *br)
+{
+   struct in_device *in_dev = in_dev_get(br->dev);
+
+   if (WARN_ON(!in_dev))
+   return;
+
+   ip_mc_dec_group(in_dev, htonl(INADDR_ALLSNOOPERS_GROUP));
+   in_dev_put(in_dev);
+}
+
+#if IS_ENABLED(CONFIG_IPV6)
+static void br_ip6_multicast_leave_snoopers(struct net_bridge *br)
+{
+   struct in6_addr addr;
+
+   ipv6_addr_set(&addr, htonl(0xff02), 0, 0, htonl(0x6a));
+   ipv6_dev_mc_dec(br->dev, &addr);
+}
+#else
+static inline void br_ip6_multicast_leave_snoopers(struct net_bridge *br)
+{
+}
+#endif
+
+static void br_multicast_leave_snoopers(struct net_bridge *br)
+{
+   br_ip4_multicast_leave_snoopers(br);
+   br_ip6_multicast_leave_snoopers(br);
+}
+
 static void __br_multicast_open(struct net_bridge *br,
struct bridge_mcast_own_query *query)
 {
@@ -1793,6 +1855,9 @@ static void __br_multicast_open(struct net_bridge *br,
 
 void br_multicast_open(struct net_bridge *br)
 {
+   if (br_opt_get(br, BROPT_MULTICAST_ENABLED))
+   br_multicast_join_snoopers(br);
+
__br_multicast_open(br, &br->ip4_own_query);
 #if IS_ENABLED(CONFIG_IPV6)
__br_multicast_open(br, &br->ip6_own_query);
@@ -1808,6 +1873,9 @@ void br_multicast_stop(struct net_bridge *br)
del_timer_sync(&br->ip6_other_query.timer);
del_timer_sync(&br->ip6_own_query.timer);
 #endif
+
+   if (br_opt_get(br, BROPT_MULTICAST_ENABLED))
+   br_multicast_leave_snoopers(br);
 }
 
 void br_multicast_dev_del(struct net_bridge *br)
@@ -1943,8 +2011,10 @@ int br_multicast_toggle(struct net_bridge *br, unsigned 
long val)
 
br_mc_disabled_update(br->dev, val);
br_opt_toggle(br, BROPT_MULTICAST_ENABLED, !!val);
-   if (!br_opt_get(br, BROPT_MULTICAST_ENABLED))
+   if (!br_opt_get(br, BROPT_MULTICAST_ENABLED)) {
+   br_multicast_leave_snoopers(br);
goto unlock;
+   }
 
if (!netif_running(br->dev))
goto unlock;
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 21f6deb2aec9..42f3f5cd349f 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ 

[PATCH net-next v2 2/4] bridge: simplify ip_mc_check_igmp() and ipv6_mc_check_mld() internals

2019-01-20 Thread Linus Lüssing
With this patch the internal use of the skb_trimmed is reduced to
the ICMPv6/IGMP checksum verification. And for the length checks
the newly introduced helper functions are used instead of calculating
and checking with skb->len directly.

These changes should hopefully make it easier to verify that length
checks are performed properly.

Signed-off-by: Linus Lüssing 
---
 net/ipv4/igmp.c| 51 ++---
 net/ipv6/mcast_snoop.c | 62 --
 2 files changed, 52 insertions(+), 61 deletions(-)

diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index b1f6d93282d7..a40e48ded10d 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -1493,22 +1493,22 @@ static int ip_mc_check_igmp_reportv3(struct sk_buff 
*skb)
 
len += sizeof(struct igmpv3_report);
 
-   return pskb_may_pull(skb, len) ? 0 : -EINVAL;
+   return ip_mc_may_pull(skb, len) ? 0 : -EINVAL;
 }
 
 static int ip_mc_check_igmp_query(struct sk_buff *skb)
 {
-   unsigned int len = skb_transport_offset(skb);
-
-   len += sizeof(struct igmphdr);
-   if (skb->len < len)
-   return -EINVAL;
+   unsigned int transport_len = ip_transport_len(skb);
+   unsigned int len;
 
/* IGMPv{1,2}? */
-   if (skb->len != len) {
+   if (transport_len != sizeof(struct igmphdr)) {
/* or IGMPv3? */
-   len += sizeof(struct igmpv3_query) - sizeof(struct igmphdr);
-   if (skb->len < len || !pskb_may_pull(skb, len))
+   if (transport_len < sizeof(struct igmpv3_query))
+   return -EINVAL;
+
+   len = skb_transport_offset(skb) + sizeof(struct igmpv3_query);
+   if (!ip_mc_may_pull(skb, len))
return -EINVAL;
}
 
@@ -1544,35 +1544,24 @@ static inline __sum16 ip_mc_validate_checksum(struct 
sk_buff *skb)
return skb_checksum_simple_validate(skb);
 }
 
-static int __ip_mc_check_igmp(struct sk_buff *skb)
-
+static int ip_mc_check_igmp_csum(struct sk_buff *skb)
 {
-   struct sk_buff *skb_chk;
-   unsigned int transport_len;
unsigned int len = skb_transport_offset(skb) + sizeof(struct igmphdr);
-   int ret = -EINVAL;
+   unsigned int transport_len = ip_transport_len(skb);
+   struct sk_buff *skb_chk;
 
-   transport_len = ntohs(ip_hdr(skb)->tot_len) - ip_hdrlen(skb);
+   if (!ip_mc_may_pull(skb, len))
+   return -EINVAL;
 
skb_chk = skb_checksum_trimmed(skb, transport_len,
   ip_mc_validate_checksum);
if (!skb_chk)
-   goto err;
+   return -EINVAL;
 
-   if (!pskb_may_pull(skb_chk, len))
-   goto err;
-
-   ret = ip_mc_check_igmp_msg(skb_chk);
-   if (ret)
-   goto err;
-
-   ret = 0;
-
-err:
-   if (skb_chk && skb_chk != skb)
+   if (skb_chk != skb)
kfree_skb(skb_chk);
 
-   return ret;
+   return 0;
 }
 
 /**
@@ -1600,7 +1589,11 @@ int ip_mc_check_igmp(struct sk_buff *skb)
if (ip_hdr(skb)->protocol != IPPROTO_IGMP)
return -ENOMSG;
 
-   return __ip_mc_check_igmp(skb);
+   ret = ip_mc_check_igmp_csum(skb);
+   if (ret < 0)
+   return ret;
+
+   return ip_mc_check_igmp_msg(skb);
 }
 EXPORT_SYMBOL(ip_mc_check_igmp);
 
diff --git a/net/ipv6/mcast_snoop.c b/net/ipv6/mcast_snoop.c
index 1a917dc80d5e..a72ddfc40eb3 100644
--- a/net/ipv6/mcast_snoop.c
+++ b/net/ipv6/mcast_snoop.c
@@ -77,27 +77,27 @@ static int ipv6_mc_check_mld_reportv2(struct sk_buff *skb)
 
len += sizeof(struct mld2_report);
 
-   return pskb_may_pull(skb, len) ? 0 : -EINVAL;
+   return ipv6_mc_may_pull(skb, len) ? 0 : -EINVAL;
 }
 
 static int ipv6_mc_check_mld_query(struct sk_buff *skb)
 {
+   unsigned int transport_len = ipv6_transport_len(skb);
struct mld_msg *mld;
-   unsigned int len = skb_transport_offset(skb);
+   unsigned int len;
 
/* RFC2710+RFC3810 (MLDv1+MLDv2) require link-local source addresses */
if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL))
return -EINVAL;
 
-   len += sizeof(struct mld_msg);
-   if (skb->len < len)
-   return -EINVAL;
-
/* MLDv1? */
-   if (skb->len != len) {
+   if (transport_len != sizeof(struct mld_msg)) {
/* or MLDv2? */
-   len += sizeof(struct mld2_query) - sizeof(struct mld_msg);
-   if (skb->len < len || !pskb_may_pull(skb, len))
+   if (transport_len < sizeof(struct mld2_query))
+   return -EINVAL;
+
+   len = skb_transport_offset(skb) + sizeof(struct mld2_query);
+   if (!ipv6_mc_may_pull(skb, len))
return -EINVAL;
}
 
@@ -115,7 +115,13 @@ st

[PATCH net-next v2 4/4] bridge: Snoop Multicast Router Advertisements

2019-01-20 Thread Linus Lüssing
When multiple multicast routers are present in a broadcast domain then
only one of them will be detectable via IGMP/MLD query snooping. The
multicast router with the lowest IP address will become the selected and
active querier while all other multicast routers will then refrain from
sending queries.

To detect such rather silent multicast routers, too, RFC4286
("Multicast Router Discovery") provides a standardized protocol to
detect multicast routers for multicast snooping switches.

This patch implements the necessary MRD Advertisement message parsing
and after successful processing adds such routers to the internal
multicast router list.

Signed-off-by: Linus Lüssing 
---
 include/linux/in.h  |  5 +
 include/net/addrconf.h  | 15 +
 include/uapi/linux/icmpv6.h |  2 ++
 include/uapi/linux/igmp.h   |  1 +
 net/bridge/br_multicast.c   | 55 +
 net/ipv6/mcast_snoop.c  |  5 -
 6 files changed, 82 insertions(+), 1 deletion(-)

diff --git a/include/linux/in.h b/include/linux/in.h
index 31b493734763..435e7f2a513a 100644
--- a/include/linux/in.h
+++ b/include/linux/in.h
@@ -60,6 +60,11 @@ static inline bool ipv4_is_lbcast(__be32 addr)
return addr == htonl(INADDR_BROADCAST);
 }
 
+static inline bool ipv4_is_all_snoopers(__be32 addr)
+{
+   return addr == htonl(INADDR_ALLSNOOPERS_GROUP);
+}
+
 static inline bool ipv4_is_zeronet(__be32 addr)
 {
return (addr & htonl(0xff00)) == htonl(0x);
diff --git a/include/net/addrconf.h b/include/net/addrconf.h
index daf11dcb0f70..20d523ee2fec 100644
--- a/include/net/addrconf.h
+++ b/include/net/addrconf.h
@@ -229,6 +229,7 @@ void ipv6_mc_unmap(struct inet6_dev *idev);
 void ipv6_mc_remap(struct inet6_dev *idev);
 void ipv6_mc_init_dev(struct inet6_dev *idev);
 void ipv6_mc_destroy_dev(struct inet6_dev *idev);
+int ipv6_mc_check_icmpv6(struct sk_buff *skb);
 int ipv6_mc_check_mld(struct sk_buff *skb);
 void addrconf_dad_failure(struct sk_buff *skb, struct inet6_ifaddr *ifp);
 
@@ -499,6 +500,20 @@ static inline bool ipv6_addr_is_solict_mult(const struct 
in6_addr *addr)
 #endif
 }
 
+static inline bool ipv6_addr_is_all_snoopers(const struct in6_addr *addr)
+{
+#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
+   __be64 *p = (__be64 *)addr;
+
+   return ((p[0] ^ cpu_to_be64(0xff02UL)) |
+   (p[1] ^ cpu_to_be64(0x6a))) == 0UL;
+#else
+   return ((addr->s6_addr32[0] ^ htonl(0xff02)) |
+   addr->s6_addr32[1] | addr->s6_addr32[2] |
+   (addr->s6_addr32[3] ^ htonl(0x006a))) == 0;
+#endif
+}
+
 #ifdef CONFIG_PROC_FS
 int if6_proc_init(void);
 void if6_proc_exit(void);
diff --git a/include/uapi/linux/icmpv6.h b/include/uapi/linux/icmpv6.h
index caf8dc019250..325395f56bfa 100644
--- a/include/uapi/linux/icmpv6.h
+++ b/include/uapi/linux/icmpv6.h
@@ -108,6 +108,8 @@ struct icmp6hdr {
 #define ICMPV6_MOBILE_PREFIX_SOL   146
 #define ICMPV6_MOBILE_PREFIX_ADV   147
 
+#define ICMPV6_MRDISC_ADV  151
+
 /*
  * Codes for Destination Unreachable
  */
diff --git a/include/uapi/linux/igmp.h b/include/uapi/linux/igmp.h
index 7e44ac02ca18..90c28bc466c6 100644
--- a/include/uapi/linux/igmp.h
+++ b/include/uapi/linux/igmp.h
@@ -93,6 +93,7 @@ struct igmpv3_query {
 #define IGMP_MTRACE_RESP   0x1e
 #define IGMP_MTRACE0x1f
 
+#define IGMP_MRDISC_ADV0x30/* From RFC4286 */
 
 /*
  * Use the BSD names for these for compatibility
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 2366f4a2780e..2c46c7aca571 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -14,6 +14,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -29,10 +30,12 @@
 #include 
 #include 
 #if IS_ENABLED(CONFIG_IPV6)
+#include 
 #include 
 #include 
 #include 
 #include 
+#include 
 #endif
 
 #include "br_private.h"
@@ -1583,6 +1586,19 @@ static void br_multicast_pim(struct net_bridge *br,
br_multicast_mark_router(br, port);
 }
 
+static int br_ip4_multicast_mrd_rcv(struct net_bridge *br,
+   struct net_bridge_port *port,
+   struct sk_buff *skb)
+{
+   if (ip_hdr(skb)->protocol != IPPROTO_IGMP ||
+   igmp_hdr(skb)->type != IGMP_MRDISC_ADV)
+   return -ENOMSG;
+
+   br_multicast_mark_router(br, port);
+
+   return 0;
+}
+
 static int br_multicast_ipv4_rcv(struct net_bridge *br,
 struct net_bridge_port *port,
 struct sk_buff *skb,
@@ -1600,7 +1616,15 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
} else if (pim_ipv4_all_pim_routers(ip_hdr(skb)->daddr)) {
if (ip_hdr(skb)->protocol == IPPROTO_PIM)
  

[PATCH net-next v2 1/4] bridge: simplify ip_mc_check_igmp() and ipv6_mc_check_mld() calls

2019-01-20 Thread Linus Lüssing
This patch refactors ip_mc_check_igmp(), ipv6_mc_check_mld() and
their callers (more precisely, the Linux bridge) to not rely on
the skb_trimmed parameter anymore.

An skb with its tail trimmed to the IP packet length was initially
introduced for the following three reasons:

1) To be able to verify the ICMPv6 checksum.
2) To be able to distinguish the version of an IGMP or MLD query.
   They are distinguishable only by their size.
3) To avoid parsing data for an IGMPv3 or MLDv2 report that is
   beyond the IP packet but still within the skb.

The first case still uses a cloned and potentially trimmed skb to
verfiy. However, there is no need to propagate it to the caller.
For the second and third case explicit IP packet length checks were
added.

This hopefully makes ip_mc_check_igmp() and ipv6_mc_check_mld() easier
to read and verfiy, as well as easier to use.

Signed-off-by: Linus Lüssing 
---
 include/linux/igmp.h   | 11 -
 include/linux/ip.h |  5 
 include/linux/ipv6.h   |  6 +
 include/net/addrconf.h | 12 +-
 net/batman-adv/multicast.c |  4 ++--
 net/bridge/br_multicast.c  | 57 +++---
 net/ipv4/igmp.c| 23 ---
 net/ipv6/mcast_snoop.c | 24 ---
 8 files changed, 70 insertions(+), 72 deletions(-)

diff --git a/include/linux/igmp.h b/include/linux/igmp.h
index 119f53941c12..8b4348f69bc5 100644
--- a/include/linux/igmp.h
+++ b/include/linux/igmp.h
@@ -18,6 +18,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -106,6 +107,14 @@ struct ip_mc_list {
 #define IGMPV3_QQIC(value) IGMPV3_EXP(0x80, 4, 3, value)
 #define IGMPV3_MRC(value) IGMPV3_EXP(0x80, 4, 3, value)
 
+static inline int ip_mc_may_pull(struct sk_buff *skb, unsigned int len)
+{
+   if (skb_transport_offset(skb) + ip_transport_len(skb) < len)
+   return -EINVAL;
+
+   return pskb_may_pull(skb, len);
+}
+
 extern int ip_check_mc_rcu(struct in_device *dev, __be32 mc_addr, __be32 
src_addr, u8 proto);
 extern int igmp_rcv(struct sk_buff *);
 extern int ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr);
@@ -130,6 +139,6 @@ extern void ip_mc_unmap(struct in_device *);
 extern void ip_mc_remap(struct in_device *);
 extern void ip_mc_dec_group(struct in_device *in_dev, __be32 addr);
 extern void ip_mc_inc_group(struct in_device *in_dev, __be32 addr);
-int ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed);
+int ip_mc_check_igmp(struct sk_buff *skb);
 
 #endif
diff --git a/include/linux/ip.h b/include/linux/ip.h
index 492bc6513533..482b7b7c9f30 100644
--- a/include/linux/ip.h
+++ b/include/linux/ip.h
@@ -34,4 +34,9 @@ static inline struct iphdr *ipip_hdr(const struct sk_buff 
*skb)
 {
return (struct iphdr *)skb_transport_header(skb);
 }
+
+static inline unsigned int ip_transport_len(const struct sk_buff *skb)
+{
+   return ntohs(ip_hdr(skb)->tot_len) - skb_network_header_len(skb);
+}
 #endif /* _LINUX_IP_H */
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 495e834c1367..6d45ce784bea 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -104,6 +104,12 @@ static inline struct ipv6hdr *ipipv6_hdr(const struct 
sk_buff *skb)
return (struct ipv6hdr *)skb_transport_header(skb);
 }
 
+static inline unsigned int ipv6_transport_len(const struct sk_buff *skb)
+{
+   return ntohs(ipv6_hdr(skb)->payload_len) + sizeof(struct ipv6hdr) -
+  skb_network_header_len(skb);
+}
+
 /* 
This structure contains results of exthdrs parsing
as offsets from skb->nh.
diff --git a/include/net/addrconf.h b/include/net/addrconf.h
index 1656c5978498..daf11dcb0f70 100644
--- a/include/net/addrconf.h
+++ b/include/net/addrconf.h
@@ -49,6 +49,7 @@ struct prefix_info {
struct in6_addr prefix;
 };
 
+#include 
 #include 
 #include 
 #include 
@@ -201,6 +202,15 @@ u32 ipv6_addr_label(struct net *net, const struct in6_addr 
*addr,
 /*
  * multicast prototypes (mcast.c)
  */
+static inline int ipv6_mc_may_pull(struct sk_buff *skb,
+  unsigned int len)
+{
+   if (skb_transport_offset(skb) + ipv6_transport_len(skb) < len)
+   return -EINVAL;
+
+   return pskb_may_pull(skb, len);
+}
+
 int ipv6_sock_mc_join(struct sock *sk, int ifindex,
  const struct in6_addr *addr);
 int ipv6_sock_mc_drop(struct sock *sk, int ifindex,
@@ -219,7 +229,7 @@ void ipv6_mc_unmap(struct inet6_dev *idev);
 void ipv6_mc_remap(struct inet6_dev *idev);
 void ipv6_mc_init_dev(struct inet6_dev *idev);
 void ipv6_mc_destroy_dev(struct inet6_dev *idev);
-int ipv6_mc_check_mld(struct sk_buff *skb, struct sk_buff **skb_trimmed);
+int ipv6_mc_check_mld(struct sk_buff *skb);
 void addrconf_dad_failure(struct sk_buff *skb, struct inet6_ifaddr *ifp);
 
 bool ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group,
diff --git a/net/batman-adv/mu

[PATCH net-next v2 0/4] bridge: implement Multicast Router Discovery (RFC4286)

2019-01-20 Thread Linus Lüssing
Hi,

This patchset adds initial Multicast Router Discovery support to
the Linux bridge (RFC4286). With MRD it is possible to detect multicast
routers and mark bridge ports and forward multicast packets to such routers
accordingly.

So far, multicast routers are detected via IGMP/MLD queries and PIM
messages in the Linux bridge. As there is only one active, selected
querier at a time RFC4541 ("Considerations for Internet Group Management
Protocol (IGMP) and Multicast Listener Discovery (MLD) Snooping
Switches") section 2.1.1.a) recommends snooping Multicast Router
Advertisements as provided by MRD (RFC4286).


The first two patches are refactoring some existing code which is reused
for parsing the Multicast Router Advertisements later in the fourth
patch. The third patch lets the bridge join the all-snoopers multicast
address to be able to reliably receive the Multicast Router
Advertisements.


What is not implemented yet from RFC4286 yet:

* Sending Multicast Router Solicitations:
  -> RFC4286: "[...] may be sent when [...] an interface is
 (re-)initialized [or] MRD is enabled"
* Snooping Multicast Router Terminations:
  -> currently this only relies on our own timeouts
* Adjusting timeouts with the values provided in the announcements


Regards, Linus

---

Changes in v2:

* rebased to current net-next/master (no conflicts/changes)




[PATCH net-next 2/4] bridge: simplify ip_mc_check_igmp() and ipv6_mc_check_mld() internals

2018-12-21 Thread Linus Lüssing
With this patch the internal use of the skb_trimmed is reduced to
the ICMPv6/IGMP checksum verification. And for the length checks
the newly introduced helper functions are used instead of calculating
and checking with skb->len directly.

These changes should hopefully make it easier to verify that length
checks are performed properly.

Signed-off-by: Linus Lüssing 
---
 net/ipv4/igmp.c| 51 ++---
 net/ipv6/mcast_snoop.c | 62 --
 2 files changed, 52 insertions(+), 61 deletions(-)

diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index b1f6d93282d7..a40e48ded10d 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -1493,22 +1493,22 @@ static int ip_mc_check_igmp_reportv3(struct sk_buff 
*skb)
 
len += sizeof(struct igmpv3_report);
 
-   return pskb_may_pull(skb, len) ? 0 : -EINVAL;
+   return ip_mc_may_pull(skb, len) ? 0 : -EINVAL;
 }
 
 static int ip_mc_check_igmp_query(struct sk_buff *skb)
 {
-   unsigned int len = skb_transport_offset(skb);
-
-   len += sizeof(struct igmphdr);
-   if (skb->len < len)
-   return -EINVAL;
+   unsigned int transport_len = ip_transport_len(skb);
+   unsigned int len;
 
/* IGMPv{1,2}? */
-   if (skb->len != len) {
+   if (transport_len != sizeof(struct igmphdr)) {
/* or IGMPv3? */
-   len += sizeof(struct igmpv3_query) - sizeof(struct igmphdr);
-   if (skb->len < len || !pskb_may_pull(skb, len))
+   if (transport_len < sizeof(struct igmpv3_query))
+   return -EINVAL;
+
+   len = skb_transport_offset(skb) + sizeof(struct igmpv3_query);
+   if (!ip_mc_may_pull(skb, len))
return -EINVAL;
}
 
@@ -1544,35 +1544,24 @@ static inline __sum16 ip_mc_validate_checksum(struct 
sk_buff *skb)
return skb_checksum_simple_validate(skb);
 }
 
-static int __ip_mc_check_igmp(struct sk_buff *skb)
-
+static int ip_mc_check_igmp_csum(struct sk_buff *skb)
 {
-   struct sk_buff *skb_chk;
-   unsigned int transport_len;
unsigned int len = skb_transport_offset(skb) + sizeof(struct igmphdr);
-   int ret = -EINVAL;
+   unsigned int transport_len = ip_transport_len(skb);
+   struct sk_buff *skb_chk;
 
-   transport_len = ntohs(ip_hdr(skb)->tot_len) - ip_hdrlen(skb);
+   if (!ip_mc_may_pull(skb, len))
+   return -EINVAL;
 
skb_chk = skb_checksum_trimmed(skb, transport_len,
   ip_mc_validate_checksum);
if (!skb_chk)
-   goto err;
+   return -EINVAL;
 
-   if (!pskb_may_pull(skb_chk, len))
-   goto err;
-
-   ret = ip_mc_check_igmp_msg(skb_chk);
-   if (ret)
-   goto err;
-
-   ret = 0;
-
-err:
-   if (skb_chk && skb_chk != skb)
+   if (skb_chk != skb)
kfree_skb(skb_chk);
 
-   return ret;
+   return 0;
 }
 
 /**
@@ -1600,7 +1589,11 @@ int ip_mc_check_igmp(struct sk_buff *skb)
if (ip_hdr(skb)->protocol != IPPROTO_IGMP)
return -ENOMSG;
 
-   return __ip_mc_check_igmp(skb);
+   ret = ip_mc_check_igmp_csum(skb);
+   if (ret < 0)
+   return ret;
+
+   return ip_mc_check_igmp_msg(skb);
 }
 EXPORT_SYMBOL(ip_mc_check_igmp);
 
diff --git a/net/ipv6/mcast_snoop.c b/net/ipv6/mcast_snoop.c
index 1a917dc80d5e..a72ddfc40eb3 100644
--- a/net/ipv6/mcast_snoop.c
+++ b/net/ipv6/mcast_snoop.c
@@ -77,27 +77,27 @@ static int ipv6_mc_check_mld_reportv2(struct sk_buff *skb)
 
len += sizeof(struct mld2_report);
 
-   return pskb_may_pull(skb, len) ? 0 : -EINVAL;
+   return ipv6_mc_may_pull(skb, len) ? 0 : -EINVAL;
 }
 
 static int ipv6_mc_check_mld_query(struct sk_buff *skb)
 {
+   unsigned int transport_len = ipv6_transport_len(skb);
struct mld_msg *mld;
-   unsigned int len = skb_transport_offset(skb);
+   unsigned int len;
 
/* RFC2710+RFC3810 (MLDv1+MLDv2) require link-local source addresses */
if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL))
return -EINVAL;
 
-   len += sizeof(struct mld_msg);
-   if (skb->len < len)
-   return -EINVAL;
-
/* MLDv1? */
-   if (skb->len != len) {
+   if (transport_len != sizeof(struct mld_msg)) {
/* or MLDv2? */
-   len += sizeof(struct mld2_query) - sizeof(struct mld_msg);
-   if (skb->len < len || !pskb_may_pull(skb, len))
+   if (transport_len < sizeof(struct mld2_query))
+   return -EINVAL;
+
+   len = skb_transport_offset(skb) + sizeof(struct mld2_query);
+   if (!ipv6_mc_may_pull(skb, len))
return -EINVAL;
}
 
@@ -115,7 +115,13 @@ st

[PATCH net-next 1/4] bridge: simplify ip_mc_check_igmp() and ipv6_mc_check_mld() calls

2018-12-21 Thread Linus Lüssing
This patch refactors ip_mc_check_igmp(), ipv6_mc_check_mld() and
their callers (more precisely, the Linux bridge) to not rely on
the skb_trimmed parameter anymore.

An skb with its tail trimmed to the IP packet length was initially
introduced for the following three reasons:

1) To be able to verify the ICMPv6 checksum.
2) To be able to distinguish the version of an IGMP or MLD query.
   They are distinguishable only by their size.
3) To avoid parsing data for an IGMPv3 or MLDv2 report that is
   beyond the IP packet but still within the skb.

The first case still uses a cloned and potentially trimmed skb to
verfiy. However, there is no need to propagate it to the caller.
For the second and third case explicit IP packet length checks were
added.

This hopefully makes ip_mc_check_igmp() and ipv6_mc_check_mld() easier
to read and verfiy, as well as easier to use.

Signed-off-by: Linus Lüssing 
---
 include/linux/igmp.h   | 11 -
 include/linux/ip.h |  5 
 include/linux/ipv6.h   |  6 +
 include/net/addrconf.h | 12 +-
 net/batman-adv/multicast.c |  4 ++--
 net/bridge/br_multicast.c  | 57 +++---
 net/ipv4/igmp.c| 23 ---
 net/ipv6/mcast_snoop.c | 24 ---
 8 files changed, 70 insertions(+), 72 deletions(-)

diff --git a/include/linux/igmp.h b/include/linux/igmp.h
index 119f53941c12..8b4348f69bc5 100644
--- a/include/linux/igmp.h
+++ b/include/linux/igmp.h
@@ -18,6 +18,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -106,6 +107,14 @@ struct ip_mc_list {
 #define IGMPV3_QQIC(value) IGMPV3_EXP(0x80, 4, 3, value)
 #define IGMPV3_MRC(value) IGMPV3_EXP(0x80, 4, 3, value)
 
+static inline int ip_mc_may_pull(struct sk_buff *skb, unsigned int len)
+{
+   if (skb_transport_offset(skb) + ip_transport_len(skb) < len)
+   return -EINVAL;
+
+   return pskb_may_pull(skb, len);
+}
+
 extern int ip_check_mc_rcu(struct in_device *dev, __be32 mc_addr, __be32 
src_addr, u8 proto);
 extern int igmp_rcv(struct sk_buff *);
 extern int ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr);
@@ -130,6 +139,6 @@ extern void ip_mc_unmap(struct in_device *);
 extern void ip_mc_remap(struct in_device *);
 extern void ip_mc_dec_group(struct in_device *in_dev, __be32 addr);
 extern void ip_mc_inc_group(struct in_device *in_dev, __be32 addr);
-int ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed);
+int ip_mc_check_igmp(struct sk_buff *skb);
 
 #endif
diff --git a/include/linux/ip.h b/include/linux/ip.h
index 492bc6513533..482b7b7c9f30 100644
--- a/include/linux/ip.h
+++ b/include/linux/ip.h
@@ -34,4 +34,9 @@ static inline struct iphdr *ipip_hdr(const struct sk_buff 
*skb)
 {
return (struct iphdr *)skb_transport_header(skb);
 }
+
+static inline unsigned int ip_transport_len(const struct sk_buff *skb)
+{
+   return ntohs(ip_hdr(skb)->tot_len) - skb_network_header_len(skb);
+}
 #endif /* _LINUX_IP_H */
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 495e834c1367..6d45ce784bea 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -104,6 +104,12 @@ static inline struct ipv6hdr *ipipv6_hdr(const struct 
sk_buff *skb)
return (struct ipv6hdr *)skb_transport_header(skb);
 }
 
+static inline unsigned int ipv6_transport_len(const struct sk_buff *skb)
+{
+   return ntohs(ipv6_hdr(skb)->payload_len) + sizeof(struct ipv6hdr) -
+  skb_network_header_len(skb);
+}
+
 /* 
This structure contains results of exthdrs parsing
as offsets from skb->nh.
diff --git a/include/net/addrconf.h b/include/net/addrconf.h
index 1656c5978498..daf11dcb0f70 100644
--- a/include/net/addrconf.h
+++ b/include/net/addrconf.h
@@ -49,6 +49,7 @@ struct prefix_info {
struct in6_addr prefix;
 };
 
+#include 
 #include 
 #include 
 #include 
@@ -201,6 +202,15 @@ u32 ipv6_addr_label(struct net *net, const struct in6_addr 
*addr,
 /*
  * multicast prototypes (mcast.c)
  */
+static inline int ipv6_mc_may_pull(struct sk_buff *skb,
+  unsigned int len)
+{
+   if (skb_transport_offset(skb) + ipv6_transport_len(skb) < len)
+   return -EINVAL;
+
+   return pskb_may_pull(skb, len);
+}
+
 int ipv6_sock_mc_join(struct sock *sk, int ifindex,
  const struct in6_addr *addr);
 int ipv6_sock_mc_drop(struct sock *sk, int ifindex,
@@ -219,7 +229,7 @@ void ipv6_mc_unmap(struct inet6_dev *idev);
 void ipv6_mc_remap(struct inet6_dev *idev);
 void ipv6_mc_init_dev(struct inet6_dev *idev);
 void ipv6_mc_destroy_dev(struct inet6_dev *idev);
-int ipv6_mc_check_mld(struct sk_buff *skb, struct sk_buff **skb_trimmed);
+int ipv6_mc_check_mld(struct sk_buff *skb);
 void addrconf_dad_failure(struct sk_buff *skb, struct inet6_ifaddr *ifp);
 
 bool ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group,
diff --git a/net/batman-adv/mu

[PATCH net-next 0/4] bridge: implement Multicast Router Discovery (RFC4286)

2018-12-21 Thread Linus Lüssing
Hi,

This patchset adds initial Multicast Router Discovery support to
the Linux bridge (RFC4286). With MRD it is possible to detect multicast
routers and mark bridge ports and forward multicast packets to such routers
accordingly.

So far, multicast routers are detected via IGMP/MLD queries and PIM
messages in the Linux bridge. As there is only one active, selected
querier at a time RFC4541 ("Considerations for Internet Group Management
Protocol (IGMP) and Multicast Listener Discovery (MLD) Snooping
Switches") section 2.1.1.a) recommends snooping Multicast Router
Advertisements as provided by MRD (RFC4286).


The first two patches are refactoring some existing code which is reused
for parsing the Multicast Router Advertisements later in the fourth
patch. The third patch lets the bridge join the all-snoopers multicast
address to be able to reliably receive the Multicast Router
Advertisements.


What is not implemented yet from RFC4286 yet:

* Sending Multicast Router Solicitations:
  -> RFC4286: "[...] may be sent when [...] an interface is
 (re-)initialized [or] MRD is enabled"
* Snooping Multicast Router Terminations:
  -> currently this only relies on our own timeouts
* Adjusting timeouts with the values provided in the announcements


Regards, Linus





[PATCH net-next 4/4] bridge: Snoop Multicast Router Advertisements

2018-12-21 Thread Linus Lüssing
When multiple multicast routers are present in a broadcast domain then
only one of them will be detectable via IGMP/MLD query snooping. The
multicast router with the lowest IP address will become the selected and
active querier while all other multicast routers will then refrain from
sending queries.

To detect such rather silent multicast routers, too, RFC4286
("Multicast Router Discovery") provides a standardized protocol to
detect multicast routers for multicast snooping switches.

This patch implements the necessary MRD Advertisement message parsing
and after successful processing adds such routers to the internal
multicast router list.

Signed-off-by: Linus Lüssing 
---
 include/linux/in.h  |  5 +
 include/net/addrconf.h  | 15 +
 include/uapi/linux/icmpv6.h |  2 ++
 include/uapi/linux/igmp.h   |  1 +
 net/bridge/br_multicast.c   | 55 +
 net/ipv6/mcast_snoop.c  |  5 -
 6 files changed, 82 insertions(+), 1 deletion(-)

diff --git a/include/linux/in.h b/include/linux/in.h
index 31b493734763..435e7f2a513a 100644
--- a/include/linux/in.h
+++ b/include/linux/in.h
@@ -60,6 +60,11 @@ static inline bool ipv4_is_lbcast(__be32 addr)
return addr == htonl(INADDR_BROADCAST);
 }
 
+static inline bool ipv4_is_all_snoopers(__be32 addr)
+{
+   return addr == htonl(INADDR_ALLSNOOPERS_GROUP);
+}
+
 static inline bool ipv4_is_zeronet(__be32 addr)
 {
return (addr & htonl(0xff00)) == htonl(0x);
diff --git a/include/net/addrconf.h b/include/net/addrconf.h
index daf11dcb0f70..20d523ee2fec 100644
--- a/include/net/addrconf.h
+++ b/include/net/addrconf.h
@@ -229,6 +229,7 @@ void ipv6_mc_unmap(struct inet6_dev *idev);
 void ipv6_mc_remap(struct inet6_dev *idev);
 void ipv6_mc_init_dev(struct inet6_dev *idev);
 void ipv6_mc_destroy_dev(struct inet6_dev *idev);
+int ipv6_mc_check_icmpv6(struct sk_buff *skb);
 int ipv6_mc_check_mld(struct sk_buff *skb);
 void addrconf_dad_failure(struct sk_buff *skb, struct inet6_ifaddr *ifp);
 
@@ -499,6 +500,20 @@ static inline bool ipv6_addr_is_solict_mult(const struct 
in6_addr *addr)
 #endif
 }
 
+static inline bool ipv6_addr_is_all_snoopers(const struct in6_addr *addr)
+{
+#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
+   __be64 *p = (__be64 *)addr;
+
+   return ((p[0] ^ cpu_to_be64(0xff02UL)) |
+   (p[1] ^ cpu_to_be64(0x6a))) == 0UL;
+#else
+   return ((addr->s6_addr32[0] ^ htonl(0xff02)) |
+   addr->s6_addr32[1] | addr->s6_addr32[2] |
+   (addr->s6_addr32[3] ^ htonl(0x006a))) == 0;
+#endif
+}
+
 #ifdef CONFIG_PROC_FS
 int if6_proc_init(void);
 void if6_proc_exit(void);
diff --git a/include/uapi/linux/icmpv6.h b/include/uapi/linux/icmpv6.h
index caf8dc019250..325395f56bfa 100644
--- a/include/uapi/linux/icmpv6.h
+++ b/include/uapi/linux/icmpv6.h
@@ -108,6 +108,8 @@ struct icmp6hdr {
 #define ICMPV6_MOBILE_PREFIX_SOL   146
 #define ICMPV6_MOBILE_PREFIX_ADV   147
 
+#define ICMPV6_MRDISC_ADV  151
+
 /*
  * Codes for Destination Unreachable
  */
diff --git a/include/uapi/linux/igmp.h b/include/uapi/linux/igmp.h
index 7e44ac02ca18..90c28bc466c6 100644
--- a/include/uapi/linux/igmp.h
+++ b/include/uapi/linux/igmp.h
@@ -93,6 +93,7 @@ struct igmpv3_query {
 #define IGMP_MTRACE_RESP   0x1e
 #define IGMP_MTRACE0x1f
 
+#define IGMP_MRDISC_ADV0x30/* From RFC4286 */
 
 /*
  * Use the BSD names for these for compatibility
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 2366f4a2780e..2c46c7aca571 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -14,6 +14,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -29,10 +30,12 @@
 #include 
 #include 
 #if IS_ENABLED(CONFIG_IPV6)
+#include 
 #include 
 #include 
 #include 
 #include 
+#include 
 #endif
 
 #include "br_private.h"
@@ -1583,6 +1586,19 @@ static void br_multicast_pim(struct net_bridge *br,
br_multicast_mark_router(br, port);
 }
 
+static int br_ip4_multicast_mrd_rcv(struct net_bridge *br,
+   struct net_bridge_port *port,
+   struct sk_buff *skb)
+{
+   if (ip_hdr(skb)->protocol != IPPROTO_IGMP ||
+   igmp_hdr(skb)->type != IGMP_MRDISC_ADV)
+   return -ENOMSG;
+
+   br_multicast_mark_router(br, port);
+
+   return 0;
+}
+
 static int br_multicast_ipv4_rcv(struct net_bridge *br,
 struct net_bridge_port *port,
 struct sk_buff *skb,
@@ -1600,7 +1616,15 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
} else if (pim_ipv4_all_pim_routers(ip_hdr(skb)->daddr)) {
if (ip_hdr(skb)->protocol == IPPROTO_PIM)
  

[PATCH net-next 3/4] bridge: join all-snoopers multicast address

2018-12-21 Thread Linus Lüssing
Next to snooping IGMP/MLD queries RFC4541, section 2.1.1.a) recommends
to snoop multicast router advertisements to detect multicast routers.

Multicast router advertisements are sent to an "all-snoopers"
multicast address. To be able to receive them reliably, we need to
join this group.

Otherwise other snooping switches might refrain from forwarding these
advertisements to us.

Signed-off-by: Linus Lüssing 
---
 include/uapi/linux/in.h   |  9 +++---
 net/bridge/br_multicast.c | 72 ++-
 net/ipv6/mcast.c  |  2 ++
 3 files changed, 78 insertions(+), 5 deletions(-)

diff --git a/include/uapi/linux/in.h b/include/uapi/linux/in.h
index f6052e70bf40..7ab685cacb8f 100644
--- a/include/uapi/linux/in.h
+++ b/include/uapi/linux/in.h
@@ -292,10 +292,11 @@ struct sockaddr_in {
 #defineIN_LOOPBACK(a)  long int) (a)) & 0xff00) == 
0x7f00)
 
 /* Defines for Multicast INADDR */
-#define INADDR_UNSPEC_GROUP0xe000U /* 224.0.0.0   */
-#define INADDR_ALLHOSTS_GROUP  0xe001U /* 224.0.0.1   */
-#define INADDR_ALLRTRS_GROUP0xe002U/* 224.0.0.2 */
-#define INADDR_MAX_LOCAL_GROUP  0xe0ffU/* 224.0.0.255 */
+#define INADDR_UNSPEC_GROUP0xe000U /* 224.0.0.0   */
+#define INADDR_ALLHOSTS_GROUP  0xe001U /* 224.0.0.1   */
+#define INADDR_ALLRTRS_GROUP   0xe002U /* 224.0.0.2 */
+#define INADDR_ALLSNOOPERS_GROUP   0xe06aU /* 224.0.0.106 */
+#define INADDR_MAX_LOCAL_GROUP 0xe0ffU /* 224.0.0.255 */
 #endif
 
 /*  contains the htonl type stuff.. */
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 156c4905639e..2366f4a2780e 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1780,6 +1780,68 @@ void br_multicast_init(struct net_bridge *br)
INIT_HLIST_HEAD(&br->mdb_list);
 }
 
+static void br_ip4_multicast_join_snoopers(struct net_bridge *br)
+{
+   struct in_device *in_dev = in_dev_get(br->dev);
+
+   if (!in_dev)
+   return;
+
+   ip_mc_inc_group(in_dev, htonl(INADDR_ALLSNOOPERS_GROUP));
+   in_dev_put(in_dev);
+}
+
+#if IS_ENABLED(CONFIG_IPV6)
+static void br_ip6_multicast_join_snoopers(struct net_bridge *br)
+{
+   struct in6_addr addr;
+
+   ipv6_addr_set(&addr, htonl(0xff02), 0, 0, htonl(0x6a));
+   ipv6_dev_mc_inc(br->dev, &addr);
+}
+#else
+static inline void br_ip6_multicast_join_snoopers(struct net_bridge *br)
+{
+}
+#endif
+
+static void br_multicast_join_snoopers(struct net_bridge *br)
+{
+   br_ip4_multicast_join_snoopers(br);
+   br_ip6_multicast_join_snoopers(br);
+}
+
+static void br_ip4_multicast_leave_snoopers(struct net_bridge *br)
+{
+   struct in_device *in_dev = in_dev_get(br->dev);
+
+   if (WARN_ON(!in_dev))
+   return;
+
+   ip_mc_dec_group(in_dev, htonl(INADDR_ALLSNOOPERS_GROUP));
+   in_dev_put(in_dev);
+}
+
+#if IS_ENABLED(CONFIG_IPV6)
+static void br_ip6_multicast_leave_snoopers(struct net_bridge *br)
+{
+   struct in6_addr addr;
+
+   ipv6_addr_set(&addr, htonl(0xff02), 0, 0, htonl(0x6a));
+   ipv6_dev_mc_dec(br->dev, &addr);
+}
+#else
+static inline void br_ip6_multicast_leave_snoopers(struct net_bridge *br)
+{
+}
+#endif
+
+static void br_multicast_leave_snoopers(struct net_bridge *br)
+{
+   br_ip4_multicast_leave_snoopers(br);
+   br_ip6_multicast_leave_snoopers(br);
+}
+
 static void __br_multicast_open(struct net_bridge *br,
struct bridge_mcast_own_query *query)
 {
@@ -1793,6 +1855,9 @@ static void __br_multicast_open(struct net_bridge *br,
 
 void br_multicast_open(struct net_bridge *br)
 {
+   if (br_opt_get(br, BROPT_MULTICAST_ENABLED))
+   br_multicast_join_snoopers(br);
+
__br_multicast_open(br, &br->ip4_own_query);
 #if IS_ENABLED(CONFIG_IPV6)
__br_multicast_open(br, &br->ip6_own_query);
@@ -1808,6 +1873,9 @@ void br_multicast_stop(struct net_bridge *br)
del_timer_sync(&br->ip6_other_query.timer);
del_timer_sync(&br->ip6_own_query.timer);
 #endif
+
+   if (br_opt_get(br, BROPT_MULTICAST_ENABLED))
+   br_multicast_leave_snoopers(br);
 }
 
 void br_multicast_dev_del(struct net_bridge *br)
@@ -1943,8 +2011,10 @@ int br_multicast_toggle(struct net_bridge *br, unsigned 
long val)
 
br_mc_disabled_update(br->dev, val);
br_opt_toggle(br, BROPT_MULTICAST_ENABLED, !!val);
-   if (!br_opt_get(br, BROPT_MULTICAST_ENABLED))
+   if (!br_opt_get(br, BROPT_MULTICAST_ENABLED)) {
+   br_multicast_leave_snoopers(br);
goto unlock;
+   }
 
if (!netif_running(br->dev))
goto unlock;
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 21f6deb2aec9..42f3f5cd349f 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ 

[PATCH net-next v2] netfilter: ebtables: avoid resetting limit rule state

2018-12-08 Thread Linus Lüssing
So far any changes with ebtables will reset the state of limit rules,
leading to spikes in traffic. This is especially noticeable if changes
are done frequently, for instance via a daemon.

This patch fixes this by bailing out from (re)setting if the limit
rule was initialized before.

When sending packets every 250ms for 600s, with a
"--limit 1/sec --limit-burst 50" rule and a command like this
in the background:

$ ebtables -N VOIDCHAIN
$ while true; do ebtables -F VOIDCHAIN; sleep 30; done

The results are:

Before: ~1600 packets
After: 650 packets

This also aligns the behavior to "xtables-nft-multi ebtables" which uses
nft_limit instead of ebt_limit. In tests nft_limit did not suffer from
this issue and rate limited to 650 just fine.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Linus Lüssing 

---

Changelog v2:

- Adjusted commit message (adjusted title, added test results with
  nft_limit for comparison)
- Excluded rate limiting variables from zeroing when passed to userspace
  by increasing .usersize. This became necessary with 4.11 /
  commit ec2318904965 ("xtables: extend matches and targets with .usersize")
- Retested with 4.20-rc4 and current net-next/master (83af01ba1c2d)

v1 was:

"[net-next] bridge: ebtables: Avoid resetting limit rule state"
-> https://lore.kernel.org/patchwork/patch/854802/
---
 net/bridge/netfilter/ebt_limit.c | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/net/bridge/netfilter/ebt_limit.c b/net/bridge/netfilter/ebt_limit.c
index 165b9d678cf1..2cf9861c3bce 100644
--- a/net/bridge/netfilter/ebt_limit.c
+++ b/net/bridge/netfilter/ebt_limit.c
@@ -69,6 +69,10 @@ static int ebt_limit_mt_check(const struct xt_mtchk_param 
*par)
 {
struct ebt_limit_info *info = par->matchinfo;
 
+   /* Do not reset state on unrelated table changes */
+   if (info->prev)
+   return 0;
+
/* Check for overflow. */
if (info->burst == 0 ||
user2credits(info->avg * info->burst) < user2credits(info->avg)) {
@@ -105,7 +109,7 @@ static struct xt_match ebt_limit_mt_reg __read_mostly = {
.match  = ebt_limit_mt,
.checkentry = ebt_limit_mt_check,
.matchsize  = sizeof(struct ebt_limit_info),
-   .usersize   = offsetof(struct ebt_limit_info, prev),
+   .usersize   = sizeof(struct ebt_limit_info),
 #ifdef CONFIG_COMPAT
.compatsize = sizeof(struct ebt_compat_limit_info),
 #endif
-- 
2.11.0



Re: [PATCH net-next] bridge: ebtables: Avoid resetting limit rule state

2017-12-07 Thread Linus Lüssing
On Fri, Dec 08, 2017 at 06:46:06AM +0100, Linus Lüssing wrote:
> Extending the usersize to include info->prev would probably be too
> hackish/ugly, right?

And wouldn't be enough anyway, since
info->{credit,credit_cap,cost} would still be zeroed... Hm.


Re: [PATCH net-next] bridge: ebtables: Avoid resetting limit rule state

2017-12-07 Thread Linus Lüssing
On Thu, Dec 07, 2017 at 01:26:19AM +0100, Pablo Neira Ayuso wrote:
> > I also had a quick look at a 4.15-rc1 kernel in a VM now. I still
> > end up in ebt_limit_mt_check() with the variables being reset
> > when editing the table somewhere.
> 
> My question is if your fix would work with 4.15-rc1.

You are absoluetly right, it's not working anymore since the
commit you mentioned initially :-(
("xtables: extend matches and targets with .usersize").
info->prev is always 0 since exactly this commit.

That means, trying tricks in ebt_limit_mt_check() is too
late now, the old values are already overwritten? (or is there
some commit scheme which installs the ebt_limit_info provided
by ebt_limit_check() some time after its call?)

Extending the usersize to include info->prev would probably be too
hackish/ugly, right?


Re: [Bridge] [PATCH net-next] bridge: ebtables: Avoid resetting limit rule state

2017-12-03 Thread Linus Lüssing
On Mon, Dec 04, 2017 at 05:53:35AM +0100, Linus Lüssing wrote:
> And so, no I do not have this patch. I looked at it now, but it
> does not seem to have any relation with .matchinfo, does it?

Relation between .usersize and .checkentry I ment, not
.usersize and .matchinfo.


Re: [PATCH net-next] bridge: ebtables: Avoid resetting limit rule state

2017-12-03 Thread Linus Lüssing
Hi Pablo,

Thanks for your reply!

On Tue, Nov 28, 2017 at 12:30:08AM +0100, Pablo Neira Ayuso wrote:
> [...]
> > diff --git a/net/bridge/netfilter/ebt_limit.c 
> > b/net/bridge/netfilter/ebt_limit.c
> > index 61a9f1be1263..f74b48633feb 100644
> > --- a/net/bridge/netfilter/ebt_limit.c
> > +++ b/net/bridge/netfilter/ebt_limit.c
> > @@ -69,6 +69,10 @@ static int ebt_limit_mt_check(const struct 
> > xt_mtchk_param *par)
> >  {
> > struct ebt_limit_info *info = par->matchinfo;
> >  
> > +   /* Do not reset state on unrelated table changes */
> > +   if (info->prev)
> > +   return 0;
> 
> What kernel version are you using? I suspect you don't have this
> applied?

I'm indeed using a 4.4.102 kernel, as LEDE is still in the process
of updating to 4.14. So 4.4 with LEDE is where I got the measurement
results from.

> 
> commit ec23189049651b16dc2ffab35a4371dc1f491aca
> Author: Willem de Bruijn 
> Date:   Mon Jan 2 17:19:46 2017 -0500
> 
> xtables: extend matches and targets with .usersize

And so, no I do not have this patch. I looked at it now, but it
does not seem to have any relation with .matchinfo, does it?

I also had a quick look at a 4.15-rc1 kernel in a VM now. I still
end up in ebt_limit_mt_check() with the variables being reset
when editing the table somewhere.

Regards, Linus


[PATCH net-next] bridge: ebtables: Avoid resetting limit rule state

2017-11-24 Thread Linus Lüssing
So far any changes with ebtables will reset the state of limit rules,
leading to spikes in traffic. This is especially noticeable if changes
are done frequently, for instance via a daemon.

This patch fixes this by bailing out from (re)setting if the limit
rule was initialized before.

When sending packets every 250ms for 600s, with a
"--limit 1/sec --limit-burst 50" rule and a command like this
in the background:

$ ebtables -N VOIDCHAIN
$ while true; do ebtables -F VOIDCHAIN; sleep 30; done

The results are:

Before: ~1600 packets
After: 650 packets

Signed-off-by: Linus Lüssing 
---
 net/bridge/netfilter/ebt_limit.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/net/bridge/netfilter/ebt_limit.c b/net/bridge/netfilter/ebt_limit.c
index 61a9f1be1263..f74b48633feb 100644
--- a/net/bridge/netfilter/ebt_limit.c
+++ b/net/bridge/netfilter/ebt_limit.c
@@ -69,6 +69,10 @@ static int ebt_limit_mt_check(const struct xt_mtchk_param 
*par)
 {
struct ebt_limit_info *info = par->matchinfo;
 
+   /* Do not reset state on unrelated table changes */
+   if (info->prev)
+   return 0;
+
/* Check for overflow. */
if (info->burst == 0 ||
user2credits(info->avg * info->burst) < user2credits(info->avg)) {
-- 
2.11.0



Re: [PATCH 3.16 076/294] batman-adv: fix TT sync flag inconsistencies

2017-11-12 Thread Linus Lüssing
Hi Ben,

On Tue, Nov 07, 2017 at 01:42:35PM +, Ben Hutchings wrote:
> That function didn't exist in 3.16 (at least not under that name).

Ah, you're right, back then the netlink interface did not
exist in batman-adv yet, only the debugfs one.
batadv_tt_global_print_entry would be the equivalent function
for debugfs. But not worth the effort now, in my opinion.

I'm fine with this proposed patch for 3.16 now. Thanks for the
clarification! And I'm happy to see this patch backported.

Regards, Linus


Re: [PATCH 3.16 076/294] batman-adv: fix TT sync flag inconsistencies

2017-11-06 Thread Linus Lüssing
Hi Ben!

On Mon, Nov 06, 2017 at 11:03:02PM +, Ben Hutchings wrote:
> 3.16.50-rc1 review patch.  If anyone has any objections, please let me know.
> 
> --
> 
> From: Linus Lüssing 
> 
> commit 54e22f265e872ae140755b3318521d400a094605 upstream.
[...]
> [bwh: Backported to 3.16:
>  - Drop changes to batadv_tt_global_dump_subentry()

May I ask, were there specific concerns for stable 3.16 kernel
releases with this change?

It's not bothering me, but I'm currently wondering whether
this could cause some confusion to users.

Regards, Linus


Re: [PATCH] ARM: dts: meson8b: add reserved memory zone to fix silent freezes

2017-10-28 Thread Linus Lüssing
On Mon, Oct 23, 2017 at 09:47:21AM +0200, Linus Lüssing wrote:
> I'm currently continuing to bisect which difference in Emiliano's
> and my kernel image makes mine boot successfully but not
> Emiliano's. (And I'm continuing reading and testing with the
> filter-range option to better understand what it's presence - or
> absence - does exactly)

I found the difference between Emiliano's and my kernel image and
could narrow it down to this particular difference via bisecting:

Using the multi_v7_defconfig target, but with the following
two options unselected:

* System Type
  -> Qualcomm Support
 - Enable support for MSM8X60 (disabled)
 - Enable support for MSM8960 (disabled)

Results in the following diff, according to ./scripts/diffconfig:

-CLKSRC_QCOM y
-MSM_IOMMU n
 ARCH_MSM8960 y -> n
 ARCH_MSM8X60 y -> n

Once this is unselected, the kernel hangs for me on boot, too.
Both with or without this 2MB reserved memory region patch.

Removing the "arm,filter-ranges" as tried by Emiliano makes it
boot again.

Finally, what also helps booting again is this diff from the
pending SMP support patch series from Carlo/Martin [0]:

~
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 47d3a1ab08d2..82faa958ab88 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -147,6 +147,7 @@  textofs-$(CONFIG_SA) := 0x00208000
 endif
 textofs-$(CONFIG_ARCH_MSM8X60) := 0x00208000
 textofs-$(CONFIG_ARCH_MSM8960) := 0x00208000
+textofs-$(CONFIG_ARCH_MESON) := 0x00208000
 textofs-$(CONFIG_ARCH_AXXIA) := 0x00308000
 
 # Machine directory name.  This list is sorted alphanumerically
~

Note the $(CONFIG_ARCH_MSM8X60) and $(CONFIG_ARCH_MSM8960) just
above. Sounds familiar :-)?

With this textofs diff alone, stress-ng still hangs though. Only
with the 2MB memory zone reserved via DT or the "arm,filter-ranges"
removed, stress-ng succeeds, too.

Regards, Linus

[0]: "[v7,4/6] ARM: meson: Add SMP bringup code for Meson8 and Meson8b"
 -> https://patchwork.kernel.org/patch/9954935/


On Mon, Oct 23, 2017 at 09:47:21AM +0200, Linus Lüssing wrote:
> Subject: Re: [PATCH] ARM: dts: meson8b: add reserved memory zone to fix 
> silent freezes
> To: Kevin Hilman 
> Cc: Carlo Caione , Kevin Hilman , 
> Martin Blumenstingl , Emiliano Ingrassia 
> , linux-amlo...@lists.infradead.org
> 
> Hi Kevin,
> 
> Just wanted to let you know that Emiliano and I are currently
> debugging further off-list.
> 
> So far I can reproduce that:
> 
> a) For the binary kernel image Emiliano sent me I can reproduce
> his hang ups during boot on my Odroid C1+.
> b) The 2MB reserved memory region this patch adds does not help
> for this image.
> c) Removing the "arm,filter-range" as proposed by Emiliano back
> then instead of adding this reserved memory zone fixes my freezes
> during boot in Emiliano's image and during stress-ng for my kernel
> image, too.
> 
> I'm currently continuing to bisect which difference in Emiliano's
> and my kernel image makes mine boot successfully but not
> Emiliano's. (And I'm continuing reading and testing with the
> filter-range option to better understand what it's presence - or
> absence - does exactly)
> 
> 
> If these observations ring a bell for anyone here, I'd be curious
> to hear what they think.
> 
> Regards, Linus
> 
> ___
> linux-amlogic mailing list
> linux-amlo...@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-amlogic


Re: [PATCH 0/4] drm/meson: power domain init related fixes

2017-10-17 Thread Linus Lüssing
On Tue, Oct 17, 2017 at 10:07:40AM +0200, Neil Armstrong wrote:
> A PM Power Domain driver has been pushed at [1] to solve the main issue.

URL to [1] missing?


[PATCH] ARM: dts: meson8b: add reserved memory zone to fix silent freezes

2017-10-02 Thread Linus Lüssing
So far, the stress-ng tool for instance quickly resulted in a silent
freeze of the system with no prior notice on a serial console when
running its filesystem or memory stressor classes.

Even with a panic-on-OOM and reboot-on-panic (vm.panic_on_oom=1,
kernel.panic=10) configured, the system would neither reboot nor
would the OOM killer get any chance to otherwise do its job.

The Amlogic reference source code uses a 2MB PHYS_OFFSET. With these 2MB
reserved via DT, stress-ng was able to run on an Odroid C1+ just fine for
several hours, the OOM killer was able to kill processes again and if
configured would successfully trigger a reboot of the system.

Fixes: 4a69fcd3a108 ("ARM: meson: Add DTS for Odroid-C1 and Tronfy MXQ boards")
Signed-off-by: Linus Lüssing 

---
The following stress-ng command worked fine now:
$ stress-ng -v --sequential 0 -t 120s --exclude sysfs,opcode --metrics
(5 hours runtime, tested on an Odroid C1+ with an 4.14-rc1 kernel + SMP
+ USB DTS patches)
---
 arch/arm/boot/dts/meson8b.dtsi | 12 
 1 file changed, 12 insertions(+)

diff --git a/arch/arm/boot/dts/meson8b.dtsi b/arch/arm/boot/dts/meson8b.dtsi
index bc278da..d75a5b5 100644
--- a/arch/arm/boot/dts/meson8b.dtsi
+++ b/arch/arm/boot/dts/meson8b.dtsi
@@ -83,6 +83,18 @@
};
};
 
+   reserved-memory {
+   #address-cells = <1>;
+   #size-cells = <1>;
+   ranges;
+
+   /* 2 MiB reserved for Hardware ROM Firmware? */
+   hwrom@0 {
+   reg = <0x0 0x20>;
+   no-map;
+   };
+   };
+
scu@c430 {
compatible = "arm,cortex-a5-scu";
reg = <0xc430 0x100>;
-- 
2.1.4



[PATCH v2] ARM: multi_v7_defconfig: Enable USB3503 driver

2017-09-28 Thread Linus Lüssing
The Odroid U3 (Exynos 4412 based) for instance needs this driver,
otherwise its USB hub will not come up.

Also selecting it as built-in to allow booting from USB without
an initrd/initramfs. exynos_defconfig does the same already, too.

Signed-off-by: Linus Lüssing 
---
 arch/arm/configs/multi_v7_defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/configs/multi_v7_defconfig 
b/arch/arm/configs/multi_v7_defconfig
index 0cacdbf..c2484ef 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -693,6 +693,7 @@ CONFIG_USB_MUSB_HDRC=m
 CONFIG_USB_MUSB_SUNXI=m
 CONFIG_USB_DWC3=y
 CONFIG_USB_DWC2=y
+CONFIG_USB_HSIC_USB3503=y
 CONFIG_USB_CHIPIDEA=y
 CONFIG_USB_CHIPIDEA_UDC=y
 CONFIG_USB_CHIPIDEA_HOST=y
-- 
2.1.4



Re: [PATCH] ARM: multi_v7_defconfig: Enable USB3503 driver

2017-09-28 Thread Linus Lüssing
Hi Krzysztof,

Thanks for your quick reply!

On Thu, Sep 28, 2017 at 08:21:26AM +0200, Krzysztof Kozlowski wrote:
> [...]
> Anyway please define this as a module (unless it can't... but it
> worked in my case).

In that case you used an initrd, right? I see various cases of USB
built-ins, like CONFIG_USB_STORAGE=y, CONFIG_USB_DWC2=y and so on in
multi_v7_defconfig. So my impression was that multi_v7_defconfig was
supposed to allow booting a rootfs from a USB storage device even
without an initrd.

Let me know if that impression is wrong though, I'll happily resend
(and test) the patch with CONFIG_USB_HSIC_USB3503=m then :-).

Regards, Linus


[PATCH] ARM: multi_v7_defconfig: Enable USB3503 driver

2017-09-27 Thread Linus Lüssing
The Odroid U3 (Exynos 4412 based) for instance needs this driver,
otherwise its USB hub will not come up.

exynos_defconfig already has this enabled as built-in, too. So
just doing the same here in multi_v7_defconfig.

Signed-off-by: Linus Lüssing 

---
Thanks to Tobias Jakobi, who indirectly made me aware of why USB
did not work for me.

 arch/arm/configs/multi_v7_defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/configs/multi_v7_defconfig 
b/arch/arm/configs/multi_v7_defconfig
index 0cacdbf..c2484ef 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -693,6 +693,7 @@ CONFIG_USB_MUSB_HDRC=m
 CONFIG_USB_MUSB_SUNXI=m
 CONFIG_USB_DWC3=y
 CONFIG_USB_DWC2=y
+CONFIG_USB_HSIC_USB3503=y
 CONFIG_USB_CHIPIDEA=y
 CONFIG_USB_CHIPIDEA_UDC=y
 CONFIG_USB_CHIPIDEA_HOST=y
-- 
2.1.4



[PATCH net v3] bridge: ebtables: fix reception of frames DNAT-ed to bridge device/port

2017-04-19 Thread Linus Lüssing
When trying to redirect bridged frames to the bridge device itself or
a bridge port (brouting) via the dnat target then this currently fails:

The ethernet destination of the frame is dnat'ed to the MAC address of
the bridge device or port just fine. However, the IP code drops it in
the beginning of ip_input.c/ip_rcv() as the dnat target left
the skb->pkt_type as PACKET_OTHERHOST.

Fixing this by resetting skb->pkt_type to an appropriate type after
dnat'ing.

Signed-off-by: Linus Lüssing 

---

Changelog v3:
- moved pkt_type fixup into ebtable dnat code
  -> v1/v2 only fixed it for prerouting/dnat so far, now tested
 and verified that v3 fixes it for brouting/dnat, too
- updated commit message

Changelog v2:
- refrain from altering pkt_type for multicast packets
  with a unicast destination MAC
---
 net/bridge/netfilter/ebt_dnat.c | 22 ++
 1 file changed, 22 insertions(+)

diff --git a/net/bridge/netfilter/ebt_dnat.c b/net/bridge/netfilter/ebt_dnat.c
index 4e0b0c3..21acb53 100644
--- a/net/bridge/netfilter/ebt_dnat.c
+++ b/net/bridge/netfilter/ebt_dnat.c
@@ -9,6 +9,7 @@
  */
 #include 
 #include 
+#include "../br_private.h"
 #include 
 #include 
 #include 
@@ -18,11 +19,32 @@ static unsigned int
 ebt_dnat_tg(struct sk_buff *skb, const struct xt_action_param *par)
 {
const struct ebt_nat_info *info = par->targinfo;
+   struct net_device *dev;
 
if (!skb_make_writable(skb, 0))
return EBT_DROP;
 
ether_addr_copy(eth_hdr(skb)->h_dest, info->mac);
+
+   if (is_multicast_ether_addr(info->mac)) {
+   if (is_broadcast_ether_addr(info->mac))
+   skb->pkt_type = PACKET_BROADCAST;
+   else
+   skb->pkt_type = PACKET_MULTICAST;
+   } else {
+   rcu_read_lock();
+   if (xt_hooknum(par) != NF_BR_BROUTING)
+   dev = br_port_get_rcu(xt_in(par))->br->dev;
+   else
+   dev = xt_in(par);
+
+   if (ether_addr_equal(info->mac, dev->dev_addr))
+   skb->pkt_type = PACKET_HOST;
+   else
+   skb->pkt_type = PACKET_OTHERHOST;
+   rcu_read_unlock();
+   }
+
return info->target;
 }
 
-- 
2.1.4



Re: [PATCH v2] bridge: ebtables: fix reception of frames DNAT-ed to bridge device

2017-04-17 Thread Linus Lüssing
On Tue, Mar 21, 2017 at 04:32:45PM -0700, Stephen Hemminger wrote:
> On Tue, 21 Mar 2017 23:28:45 +0100
> Linus Lüssing  wrote:
> 
> > However, the IP code drops it in the beginning of ip_input.c/ip_rcv()
> > as the dnat target did not update the skb->pkt_type. If after
> > dnat'ing the packet is now destined to us then the skb->pkt_type
> > needs to be updated from PACKET_OTHERHOST to PACKET_HOST, too.
> 
> Why not fix DNAT netfilter module rather than hacking bridge code here.

Sorry for the late response. Wanted to do some more testing before
replying.

My assumptions regarding macvlan were wrong:

A) The code my patch adds is not touched in the case of a macvlan
device on top of a bridge - with macvlan there seems to be no FDB entry
for the MAC address of the macvlan device at all, actually, resulting
in the flooding of a frame intended for that device (is this, ehm,
known/intended?).

B) ip_rcv() does not drop for a macvlan device, because macvlan
unconditionally sets skb->pkt_type to PACKET_HOST in macvlan_handle_frame().

(And I guess, maybe I shouldn't actually care that much about
macvlans on top of a bridge, as a veth-pair is much cleaner for that?)


Regarding netdev::dev_addrs, if I understand the kernel code correctly, it
is only, potentially populated with more than netdev::dev_addr for two
drivers, via dev_addr_add(): bnx2x and ixgbe. So for a bridge device,
there should never be more than one item in netdev::dev_addrs
(= netdev::dev_addr), correct?


So, currently I'm happy with moving the fix into the ebtables dnat
code and just checking against the netdev::dev_addr of the bridge
device now. (if anyone has any suggestions regarding upper devices
I should test with that, then please let me know)

(Sorry, Pablo, for me pressing against your earlier suggestion to
put the fix in the ebtables dnat instead of bridge code. :( )

Regards, Linus


[PATCH v2] bridge: ebtables: fix reception of frames DNAT-ed to bridge device

2017-03-21 Thread Linus Lüssing
When trying to redirect bridged frames to the bridge device itself
via the ebtables nat-prerouting chain and the dnat target then this
currently fails:

The ethernet destination of the frame is dnat'ed to the MAC address of
the bridge itself just fine and the correctly altered frame can even
be captured via a tcpdump on br0 (with or without promisc mode).

However, the IP code drops it in the beginning of ip_input.c/ip_rcv()
as the dnat target did not update the skb->pkt_type. If after
dnat'ing the packet is now destined to us then the skb->pkt_type
needs to be updated from PACKET_OTHERHOST to PACKET_HOST, too.

Signed-off-by: Linus Lüssing 

---
Changelog v2:
* refrain from altering pkt_type for multicast packets
  with a unicast destination MAC
---
 net/bridge/br_input.c | 7 ++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index 013f2290b..fd7bc4c 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -198,8 +198,13 @@ int br_handle_frame_finish(struct net *net, struct sock 
*sk, struct sk_buff *skb
if (dst) {
unsigned long now = jiffies;
 
-   if (dst->is_local)
+   if (dst->is_local) {
+   /* fix up potential DNAT inconsistencies */
+   if (skb->pkt_type == PACKET_OTHERHOST)
+   skb->pkt_type = PACKET_HOST;
+
return br_pass_frame_up(skb);
+   }
 
if (now != dst->used)
dst->used = now;
-- 
2.1.4



Re: [Bridge] [PATCH net] bridge: ebtables: fix reception of frames DNAT-ed to bridge device

2017-03-20 Thread Linus Lüssing
On Sun, Mar 19, 2017 at 05:55:06PM +0100, Linus Lüssing wrote:
> On Fri, Mar 17, 2017 at 02:10:44PM +0100, Pablo Neira Ayuso wrote:
> > Wait.
> > 
> > May this break local multicast listener that are bound to the bridge
> > interface? Assuming the bridge interface got an IP address, and that
> > there is local multicast listener.
> > 
> > Missing anything here?
> 
> Hm, for multicast packets usually the code path a few lines
> later in br_handle_frame_finish() should be taken instead.
> 
> But you might be right for IP multicast packets with a unicast MAC
> destination (due to whatever reason, for instance via DNAT'ing
> again).
> 
> Will check that - thanks!

Ok, I tested DNAT'ing an IP multicast packet to the unicast MAC address
of the bridge interface.

Both ping-ing to an IPv4 and IPv6 multicast listener on br0 worked
and was replied to fine, both with or without changing skb->pkt_type
from PACKET_MULTICAST to PACKET_HOST.
("$ ping 224.1.0.123" and "$ ping6 ff02::1:ff40:707c%in0" from a
 network namespace, tied into the bridge via veth)

Also, a DNAT'ed PACKET_BROADCAST worked, with or without changing
it to PACKET_HOST.

I also checked via tcpdump that the destination MAC was changed
successfully.


So, so far I wasn't able to find any bugs with the current
patch. But I think I like the idea of leaving the skb->pkt_type
unaltered for PACKET_MULTICAST and PACKET_BROADCAST, seems cleaner.

I'd just add an "if (skb->pkt_type == PACKET_OTHERHOST)" check
then and resend a PATCH v2.


Re: [PATCH net] bridge: ebtables: fix reception of frames DNAT-ed to bridge device

2017-03-19 Thread Linus Lüssing
On Fri, Mar 17, 2017 at 02:10:44PM +0100, Pablo Neira Ayuso wrote:
> Wait.
> 
> May this break local multicast listener that are bound to the bridge
> interface? Assuming the bridge interface got an IP address, and that
> there is local multicast listener.
> 
> Missing anything here?

Hm, for multicast packets usually the code path a few lines
later in br_handle_frame_finish() should be taken instead.

But you might be right for IP multicast packets with a unicast MAC
destination (due to whatever reason, for instance via DNAT'ing
again).

Will check that - thanks!


Re: [PATCH net] bridge: ebtables: fix reception of frames DNAT-ed to bridge device

2017-03-15 Thread Linus Lüssing
On Wed, Mar 15, 2017 at 07:15:39PM +0100, Pablo Neira Ayuso wrote:
> Could you update ebtables dnat to check if the ethernet address
> matches the one of the input bridge interface, so we mangle the
> ->pkt_type accordingly from there, instead of doing this from the
> core?

Actually, that was the approach I thought about and went for first
(and it would probably work for me). Just checking against the
bridge device's net_device::dev_addr.

I scratched it though, as I was afraid that the issue might still
exist for people using some other upper device on top of the bridge
device. For instance, macvlan? And iterating over the
net_device::dev_addrs list seemed too costly for fast path to me.


Re: [PATCH net] bridge: ebtables: fix reception of frames DNAT-ed to bridge device

2017-03-15 Thread Linus Lüssing
On Wed, Mar 15, 2017 at 11:42:11AM +0100, Pablo Neira Ayuso wrote:
> I'm missing then why redirect is not then just enough for Linus usecase.

For my usecase, the MAC address is configured by the user from a
Web-UI. It may or may not be the one from the bridge device.

Besides, found it counter intuitive that DNAT did not work here
and took me some time to find out why. At least I didn't read about
any such known limitations of the dnat target in the ebtables
manpage.


[PATCH net] bridge: ebtables: fix reception of frames DNAT-ed to bridge device

2017-03-14 Thread Linus Lüssing
When trying to redirect bridged frames to the bridge device itself
via the ebtables nat-prerouting chain and the dnat target then this
currently fails:

The ethernet destination of the frame is dnat'ed to the MAC address of
the bridge itself just fine and the correctly altered frame can even
be captured via a tcpdump on br0 (with or without promisc mode).

However, the IP code drops it in the beginning of ip_input.c/ip_rcv()
as the dnat target did not update the skb->pkt_type. If after
dnat'ing the packet is now destined to us then the skb->pkt_type
needs to be updated from PACKET_OTHERHOST to PACKET_HOST, too.

Signed-off-by: Linus Lüssing 
---
 net/bridge/br_input.c | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index 013f2290b..ec83175 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -198,8 +198,12 @@ int br_handle_frame_finish(struct net *net, struct sock 
*sk, struct sk_buff *skb
if (dst) {
unsigned long now = jiffies;
 
-   if (dst->is_local)
+   if (dst->is_local) {
+   /* fix up potential DNAT mess */
+   skb->pkt_type = PACKET_HOST;
+
return br_pass_frame_up(skb);
+   }
 
if (now != dst->used)
dst->used = now;
-- 
2.1.4



Re: [ipv6] a088d1d73a: WARNING:at_net/mac80211/agg-tx.c:#ieee80211_start_tx_ba_cb[mac80211]

2017-03-13 Thread Linus Lüssing
On Wed, Feb 22, 2017 at 10:03:02AM +0800, kernel test robot wrote:
> 
> FYI, we noticed the following commit:
> 
> commit: a088d1d73a4bcfd7bc482f8d08375b9b665dc3e5 ("ipv6: Fix IPv6 packet loss 
> in scenarios involving roaming + snooping switches")
> https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git master
> 
> in testcase: hwsim
> with following parameters:
> 
>   group: hwsim-01
[...]
> kern  :warn  : [  146.568070] WARNING: CPU: 12 PID: 669 at 
> net/mac80211/agg-tx.c:770 ieee80211_start_tx_ba_cb+0x139/0x150 [mac80211]
[...]
> kern  :warn  : [  146.568114] CPU: 12 PID: 669 Comm: kworker/u256:1 Not 
> tainted 4.10.0-rc6-00104-ga088d1d #1
> kern  :warn  : [  146.568115] Hardware name: Intel Corporation LH 
> Pass/S4600LH, BIOS SE5C600.86B.99.02.1047.032320122259 03/23/2012
> kern  :warn  : [  146.568127] Workqueue: phy0 ieee80211_iface_work [mac80211]
> kern  :warn  : [  146.568128] Call Trace:
> kern  :warn  : [  146.568141]  dump_stack+0x63/0x8a
> kern  :warn  : [  146.568146]  __warn+0xcb/0xf0
> kern  :warn  : [  146.568147]  warn_slowpath_null+0x1d/0x20
> kern  :warn  : [  146.568156]  ieee80211_start_tx_ba_cb+0x139/0x150 [mac80211]
> kern  :warn  : [  146.568166]  ieee80211_iface_work+0x266/0x470 [mac80211]
> kern  :warn  : [  146.568180]  process_one_work+0x1a3/0x480
> kern  :warn  : [  146.568182]  worker_thread+0x4e/0x4d0
> kern  :warn  : [  146.568185]  kthread+0x10c/0x140
> kern  :warn  : [  146.568187]  ? process_one_work+0x480/0x480
> kern  :warn  : [  146.568187]  ? kthread_create_on_node+0x40/0x40
> kern  :warn  : [  146.568195]  ret_from_fork+0x2c/0x40
> kern  :warn  : [  146.568197] ---[ end trace 0e4afc24db5dbafa ]---

Unfortunately, I wasn't able to reproduce this issue with the
plain mac80211-hwsim test suite yet. The according test runs successfully
in my VMs here...

To me, it looks like the WARN_ON() could be triggered by a race condition
in mac80211 or mac80211-hwsim, too. I'm going to forward this to and
discuss this further on the wireless mailing list.

Thanks for the notification, Xiaolong!

Regards, Linus


Re: [PATCH 3.2 049/126] batman-adv: fix splat on disabling an interface

2017-02-15 Thread Linus Lüssing
On Wed, Feb 15, 2017 at 10:41:34PM +, Ben Hutchings wrote:
> 3.2.85-rc1 review patch.  If anyone has any objections, please let me know.
> 
> --
> 
> From: Linus Lüssing 
> 
> commit 9799c50372b23ed774791bdb87d700f1286ee8a9 upstream.

Hi Ben,

This commit was reverted in
27915aa61060fd8954a68a86657784705955088a
('batman-adv: Revert "fix splat on disabling an interface"').

Greg dropped this patch from his stable queue back then, too [0].

Regards, Linus

[0]: https://marc.info/?l=linux-kernel&m=147938417410032


[PATCH net] ipv6: Fix IPv6 packet loss in scenarios involving roaming + snooping switches

2017-02-02 Thread Linus Lüssing
When for instance a mobile Linux device roams from one access point to
another with both APs sharing the same broadcast domain and a
multicast snooping switch in between:

1)(c) <~~~> (AP1) <--[SSW]--> (AP2)

2)  (AP1) <--[SSW]--> (AP2) <~~~> (c)

Then currently IPv6 multicast packets will get lost for (c) until an
MLD Querier sends its next query message. The packet loss occurs
because upon roaming the Linux host so far stayed silent regarding
MLD and the snooping switch will therefore be unaware of the
multicast topology change for a while.

This patch fixes this by always resending MLD reports when an interface
change happens, for instance from NO-CARRIER to CARRIER state.

Signed-off-by: Linus Lüssing 

---

Initial problem report was sent to the bridge mailing list a while ago:
- https://lists.linuxfoundation.org/pipermail/bridge/2015-September/009754.html

The RFCs concerning IGMP, MLD and snooping switches seem a have a hole
concerning roaming. A request for clarification to mcast-w...@ietf.org
was left unanswered, unfortunately:
- https://mailarchive.ietf.org/arch/msg/mcast-wifi/Ghn2cGy1oN2ZwG1qaQO9SE13g6g

However, simply resending reports seems to be the straight forward way
to me to fix the issue mentioned above.
---
 net/ipv6/addrconf.c | 10 --
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index f60e88e..81f7b4e 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -3386,9 +3386,15 @@ static int addrconf_notify(struct notifier_block *this, 
unsigned long event,
}
 
if (idev) {
-   if (idev->if_flags & IF_READY)
-   /* device is already configured. */
+   if (idev->if_flags & IF_READY) {
+   /* device is already configured -
+* but resend MLD reports, we might
+* have roamed and need to update
+* multicast snooping switches
+*/
+   ipv6_mc_up(idev);
break;
+   }
idev->if_flags |= IF_READY;
}
 
-- 
2.1.4



[PATCH net-next v5] bridge: multicast to unicast

2017-01-21 Thread Linus Lüssing
From: Felix Fietkau 

Implements an optional, per bridge port flag and feature to deliver
multicast packets to any host on the according port via unicast
individually. This is done by copying the packet per host and
changing the multicast destination MAC to a unicast one accordingly.

multicast-to-unicast works on top of the multicast snooping feature of
the bridge. Which means unicast copies are only delivered to hosts which
are interested in it and signalized this via IGMP/MLD reports
previously.

This feature is intended for interface types which have a more reliable
and/or efficient way to deliver unicast packets than broadcast ones
(e.g. wifi).

However, it should only be enabled on interfaces where no IGMPv2/MLDv1
report suppression takes place. This feature is disabled by default.

The initial patch and idea is from Felix Fietkau.

Signed-off-by: Felix Fietkau 
[linus.luess...@c0d3.blue: various bug + style fixes, commit message]
Signed-off-by: Linus Lüssing 

---

This feature is used and enabled by default in OpenWRT and LEDE for AP
interfaces for more than a year now to allow both a more robust multicast
delivery and multicast at higher rates (e.g. multicast streaming).

In OpenWRT/LEDE the IGMP/MLD report suppression issue is overcome by
the network daemon enabling AP isolation and by that separating all STAs.
Delivery of STA-to-STA IP mulitcast is made possible again by
enabling and utilizing the bridge hairpin mode, which considers the
incoming port as a potential outgoing port, too.

Hairpin-mode is performed after multicast snooping, therefore leading to
only deliver reports to STAs running a multicast router.

Changes in v5:
* fix a potential pagefault in br_ip6_multicast_mld2_report():
  -> a pskb_may_pull() might reallocate skb->data, therefore perform
 the "src = eth_hdr(skb)->h_source" only afterwards
* simplify code by always adding ether source address to a port group
  and checking the per-port multicast-to-unicast flag instead of a
  per-port-group one (thanks Stephen!)

Changes in v4:
* readd "From: Felix Fietkau [...]" (missed it again in v3)

Changes in v3:
* fix an uninitialized variable bug introduced in br_multicast_flood()
  in v2, found by kbuild test bot

Changes in v2:
* netlink support (thanks Nik!)
* fixed switching between multicast_to_unicast on/off
  -> even after toggling an already existing entry would
 stale in its mode and would never be replaced
  -> new extra check in br_port_group_equal)
* reduced checks in br_multicast_flood() from two to one
  to address fast-path concerns (thanks Nik!)
* rev-christmas tree ordering (thanks Nik!)
* removed "net_bridge_port_group::unicast", using
  ::flags instead (thanks Nik!)
* BR_MULTICAST_TO_UCAST -> BR_MULTICAST_TO_UNICAST
  (BR_MULTICAST_FLAST_LEAVE has the same length anyway)
* simplified maybe_deliver_addr()
  (no return, no "prev" paramater -> was a NOP anyway)
* added "From: Felix Fietkau [...]"
* added "Signed-off-by: Felix Fietkau [...]"
---
 include/linux/if_bridge.h|  1 +
 include/uapi/linux/if_link.h |  1 +
 net/bridge/br_forward.c  | 39 ++-
 net/bridge/br_mdb.c  |  2 +-
 net/bridge/br_multicast.c| 90 
 net/bridge/br_netlink.c  |  5 +++
 net/bridge/br_private.h  |  3 +-
 net/bridge/br_sysfs_if.c |  2 +
 8 files changed, 114 insertions(+), 29 deletions(-)

diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index c6587c0..debc9d5 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -46,6 +46,7 @@ struct br_ip_list {
 #define BR_LEARNING_SYNC   BIT(9)
 #define BR_PROXYARP_WIFI   BIT(10)
 #define BR_MCAST_FLOOD BIT(11)
+#define BR_MULTICAST_TO_UNICASTBIT(12)
 
 #define BR_DEFAULT_AGEING_TIME (300 * HZ)
 
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index 6b13e59..4e59565 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -321,6 +321,7 @@ enum {
IFLA_BRPORT_MULTICAST_ROUTER,
IFLA_BRPORT_PAD,
IFLA_BRPORT_MCAST_FLOOD,
+   IFLA_BRPORT_MCAST_TO_UCAST,
__IFLA_BRPORT_MAX
 };
 #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index 7cb41ae..a0f9d00 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -174,6 +174,31 @@ static struct net_bridge_port *maybe_deliver(
return p;
 }
 
+static void maybe_deliver_addr(struct net_bridge_port *p, struct sk_buff *skb,
+  const unsigned char *addr, bool local_orig)
+{
+   struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
+   const unsigned char *src = eth_hdr(skb)->h_source;
+
+   if (!should_deliver(p, skb))
+   return;
+
+   /* Even with hairpin, no soliloquies - prevent breaking IPv6 DAD */
+   if (s

[PATCH net-next v4] bridge: multicast to unicast

2017-01-18 Thread Linus Lüssing
From: Felix Fietkau 

Implements an optional, per bridge port flag and feature to deliver
multicast packets to any host on the according port via unicast
individually. This is done by copying the packet per host and
changing the multicast destination MAC to a unicast one accordingly.

multicast-to-unicast works on top of the multicast snooping feature of
the bridge. Which means unicast copies are only delivered to hosts which
are interested in it and signalized this via IGMP/MLD reports
previously.

This feature is intended for interface types which have a more reliable
and/or efficient way to deliver unicast packets than broadcast ones
(e.g. wifi).

However, it should only be enabled on interfaces where no IGMPv2/MLDv1
report suppression takes place. This feature is disabled by default.

The initial patch and idea is from Felix Fietkau.

Signed-off-by: Felix Fietkau 
[linus.luess...@c0d3.blue: various bug + style fixes, commit message]
Signed-off-by: Linus Lüssing 

---

This feature is used and enabled by default in OpenWRT and LEDE for AP
interfaces for more than a year now to allow both a more robust multicast
delivery and multicast at higher rates (e.g. multicast streaming).

In OpenWRT/LEDE the IGMP/MLD report suppression issue is overcome by
the network daemon enabling AP isolation and by that separating all STAs.
Delivery of STA-to-STA IP mulitcast is made possible again by
enabling and utilizing the bridge hairpin mode, which considers the
incoming port as a potential outgoing port, too.

Hairpin-mode is performed after multicast snooping, therefore leading to
only deliver reports to STAs running a multicast router.

Changes in v4:
* readd "From: Felix Fietkau [...]" (missed it again in v3)

Changes in v3:
* fix an uninitialized variable bug introduced in br_multicast_flood()
  in v2, found by kbuild test bot

Changes in v2:
* netlink support (thanks Nik!)
* fixed switching between multicast_to_unicast on/off
  -> even after toggling an already existing entry would
 stale in its mode and would never be replaced
  -> new extra check in br_port_group_equal)
* reduced checks in br_multicast_flood() from two to one
  to address fast-path concerns (thanks Nik!)
* rev-christmas tree ordering (thanks Nik!)
* removed "net_bridge_port_group::unicast", using
  ::flags instead (thanks Nik!)
* BR_MULTICAST_TO_UCAST -> BR_MULTICAST_TO_UNICAST
  (BR_MULTICAST_FLAST_LEAVE has the same length anyway)
* simplified maybe_deliver_addr()
  (no return, no "prev" paramater -> was a NOP anyway)
* added "From: Felix Fietkau [...]"
* added "Signed-off-by: Felix Fietkau [...]"
---
 include/linux/if_bridge.h|  1 +
 include/uapi/linux/if_link.h |  1 +
 net/bridge/br_forward.c  | 37 -
 net/bridge/br_mdb.c  |  2 +-
 net/bridge/br_multicast.c| 96 
 net/bridge/br_netlink.c  |  5 +++
 net/bridge/br_private.h  |  8 ++--
 net/bridge/br_sysfs_if.c |  2 +
 8 files changed, 121 insertions(+), 31 deletions(-)

diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index c6587c0..debc9d5 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -46,6 +46,7 @@ struct br_ip_list {
 #define BR_LEARNING_SYNC   BIT(9)
 #define BR_PROXYARP_WIFI   BIT(10)
 #define BR_MCAST_FLOOD BIT(11)
+#define BR_MULTICAST_TO_UNICASTBIT(12)
 
 #define BR_DEFAULT_AGEING_TIME (300 * HZ)
 
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index 6b13e59..4e59565 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -321,6 +321,7 @@ enum {
IFLA_BRPORT_MULTICAST_ROUTER,
IFLA_BRPORT_PAD,
IFLA_BRPORT_MCAST_FLOOD,
+   IFLA_BRPORT_MCAST_TO_UCAST,
__IFLA_BRPORT_MAX
 };
 #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index 7cb41ae..a6c8a27 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -174,6 +174,29 @@ static struct net_bridge_port *maybe_deliver(
return p;
 }
 
+static void maybe_deliver_addr(struct net_bridge_port *p, struct sk_buff *skb,
+  const unsigned char *addr, bool local_orig)
+{
+   struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
+   const unsigned char *src = eth_hdr(skb)->h_source;
+
+   if (!should_deliver(p, skb))
+   return;
+
+   /* Even with hairpin, no soliloquies - prevent breaking IPv6 DAD */
+   if (skb->dev == p->dev && ether_addr_equal(src, addr))
+   return;
+
+   skb = skb_copy(skb, GFP_ATOMIC);
+   if (!skb) {
+   dev->stats.tx_dropped++;
+   return;
+   }
+
+   memcpy(eth_hdr(skb)->h_dest, addr, ETH_ALEN);
+   __br_forward(p, skb, local_orig);
+}
+
 /* called under rcu_read_lock */
 void br_flood(struct net_

[PATCH net-next v3] bridge: multicast to unicast

2017-01-18 Thread Linus Lüssing
Implements an optional, per bridge port flag and feature to deliver
multicast packets to any host on the according port via unicast
individually. This is done by copying the packet per host and
changing the multicast destination MAC to a unicast one accordingly.

multicast-to-unicast works on top of the multicast snooping feature of
the bridge. Which means unicast copies are only delivered to hosts which
are interested in it and signalized this via IGMP/MLD reports
previously.

This feature is intended for interface types which have a more reliable
and/or efficient way to deliver unicast packets than broadcast ones
(e.g. wifi).

However, it should only be enabled on interfaces where no IGMPv2/MLDv1
report suppression takes place. This feature is disabled by default.

The initial patch and idea is from Felix Fietkau.

Signed-off-by: Felix Fietkau 
[linus.luess...@c0d3.blue: various bug + style fixes, commit message]
Signed-off-by: Linus Lüssing 

---

This feature is used and enabled by default in OpenWRT and LEDE for AP
interfaces for more than a year now to allow both a more robust multicast
delivery and multicast at higher rates (e.g. multicast streaming).

In OpenWRT/LEDE the IGMP/MLD report suppression issue is overcome by
the network daemon enabling AP isolation and by that separating all STAs.
Delivery of STA-to-STA IP mulitcast is made possible again by
enabling and utilizing the bridge hairpin mode, which considers the
incoming port as a potential outgoing port, too.

Hairpin-mode is performed after multicast snooping, therefore leading to
only deliver reports to STAs running a multicast router.

Changes in v3:
* fix an uninitialized variable bug introduced in br_multicast_flood()
  in v2, found by kbuild test bot

Changes in v2:
* netlink support (thanks Nik!)
* fixed switching between multicast_to_unicast on/off
  -> even after toggling an already existing entry would
 stale in its mode and would never be replaced
  -> new extra check in br_port_group_equal)
* reduced checks in br_multicast_flood() from two to one
  to address fast-path concerns (thanks Nik!)
* rev-christmas tree ordering (thanks Nik!)
* removed "net_bridge_port_group::unicast", using
  ::flags instead (thanks Nik!)
* BR_MULTICAST_TO_UCAST -> BR_MULTICAST_TO_UNICAST
  (BR_MULTICAST_FLAST_LEAVE has the same length anyway)
* simplified maybe_deliver_addr()
  (no return, no "prev" paramater -> was a NOP anyway)
* added "From: Felix Fietkau [...]"
* added "Signed-off-by: Felix Fietkau [...]"
---
 include/linux/if_bridge.h|  1 +
 include/uapi/linux/if_link.h |  1 +
 net/bridge/br_forward.c  | 37 -
 net/bridge/br_mdb.c  |  2 +-
 net/bridge/br_multicast.c| 96 
 net/bridge/br_netlink.c  |  5 +++
 net/bridge/br_private.h  |  8 ++--
 net/bridge/br_sysfs_if.c |  2 +
 8 files changed, 121 insertions(+), 31 deletions(-)

diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index c6587c0..debc9d5 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -46,6 +46,7 @@ struct br_ip_list {
 #define BR_LEARNING_SYNC   BIT(9)
 #define BR_PROXYARP_WIFI   BIT(10)
 #define BR_MCAST_FLOOD BIT(11)
+#define BR_MULTICAST_TO_UNICASTBIT(12)
 
 #define BR_DEFAULT_AGEING_TIME (300 * HZ)
 
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index 6b13e59..4e59565 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -321,6 +321,7 @@ enum {
IFLA_BRPORT_MULTICAST_ROUTER,
IFLA_BRPORT_PAD,
IFLA_BRPORT_MCAST_FLOOD,
+   IFLA_BRPORT_MCAST_TO_UCAST,
__IFLA_BRPORT_MAX
 };
 #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index 7cb41ae..a6c8a27 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -174,6 +174,29 @@ static struct net_bridge_port *maybe_deliver(
return p;
 }
 
+static void maybe_deliver_addr(struct net_bridge_port *p, struct sk_buff *skb,
+  const unsigned char *addr, bool local_orig)
+{
+   struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
+   const unsigned char *src = eth_hdr(skb)->h_source;
+
+   if (!should_deliver(p, skb))
+   return;
+
+   /* Even with hairpin, no soliloquies - prevent breaking IPv6 DAD */
+   if (skb->dev == p->dev && ether_addr_equal(src, addr))
+   return;
+
+   skb = skb_copy(skb, GFP_ATOMIC);
+   if (!skb) {
+   dev->stats.tx_dropped++;
+   return;
+   }
+
+   memcpy(eth_hdr(skb)->h_dest, addr, ETH_ALEN);
+   __br_forward(p, skb, local_orig);
+}
+
 /* called under rcu_read_lock */
 void br_flood(struct net_bridge *br, struct sk_buff *skb,
  enum br_pkt_type pkt_type, bool local_rcv, bool local_orig)
@

[PATCH net-next v2] bridge: multicast to unicast

2017-01-17 Thread Linus Lüssing
From: Felix Fietkau 

Implements an optional, per bridge port flag and feature to deliver
multicast packets to any host on the according port via unicast
individually. This is done by copying the packet per host and
changing the multicast destination MAC to a unicast one accordingly.

multicast-to-unicast works on top of the multicast snooping feature of
the bridge. Which means unicast copies are only delivered to hosts which
are interested in it and signalized this via IGMP/MLD reports
previously.

This feature is intended for interface types which have a more reliable
and/or efficient way to deliver unicast packets than broadcast ones
(e.g. wifi).

However, it should only be enabled on interfaces where no IGMPv2/MLDv1
report suppression takes place. This feature is disabled by default.

The initial patch and idea is from Felix Fietkau.

Signed-off-by: Felix Fietkau 
[linus.luess...@c0d3.blue: various bug + style fixes, commit message]
Signed-off-by: Linus Lüssing 

---

This feature is used and enabled by default in OpenWRT and LEDE for AP
interfaces for more than a year now to allow both a more robust multicast
delivery and multicast at higher rates (e.g. multicast streaming).

In OpenWRT/LEDE the IGMP/MLD report suppression issue is overcome by
the network daemon enabling AP isolation and by that separating all STAs.
Delivery of STA-to-STA IP mulitcast is made possible again by
enabling and utilizing the bridge hairpin mode, which considers the
incoming port as a potential outgoing port, too.

Hairpin-mode is performed after multicast snooping, therefore leading to
only deliver reports to STAs running a multicast router.

Changes in v2:
* netlink support (thanks Nik!)
* fixed switching between multicast_to_unicast on/off
  -> even after toggling an already existing entry would
 stale in its mode and would never be replaced
  -> new extra check in br_port_group_equal)
* reduced checks in br_multicast_flood() from two to one
  to address fast-path concerns (thanks Nik!)
* rev-christmas tree ordering (thanks Nik!)
* removed "net_bridge_port_group::unicast", using
  ::flags instead (thanks Nik!)
* BR_MULTICAST_TO_UCAST -> BR_MULTICAST_TO_UNICAST
  (BR_MULTICAST_FLAST_LEAVE has the same length anyway)
* simplified maybe_deliver_addr()
  (no return, no "prev" paramater -> was a NOP anyway)
* added "From: Felix Fietkau [...]"
* added "Signed-off-by: Felix Fietkau [...]"
---
 include/linux/if_bridge.h|  1 +
 include/uapi/linux/if_link.h |  1 +
 net/bridge/br_forward.c  | 37 -
 net/bridge/br_mdb.c  |  2 +-
 net/bridge/br_multicast.c| 96 
 net/bridge/br_netlink.c  |  5 +++
 net/bridge/br_private.h  |  8 ++--
 net/bridge/br_sysfs_if.c |  2 +
 8 files changed, 121 insertions(+), 31 deletions(-)

diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index c6587c0..debc9d5 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -46,6 +46,7 @@ struct br_ip_list {
 #define BR_LEARNING_SYNC   BIT(9)
 #define BR_PROXYARP_WIFI   BIT(10)
 #define BR_MCAST_FLOOD BIT(11)
+#define BR_MULTICAST_TO_UNICASTBIT(12)
 
 #define BR_DEFAULT_AGEING_TIME (300 * HZ)
 
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index 6b13e59..4e59565 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -321,6 +321,7 @@ enum {
IFLA_BRPORT_MULTICAST_ROUTER,
IFLA_BRPORT_PAD,
IFLA_BRPORT_MCAST_FLOOD,
+   IFLA_BRPORT_MCAST_TO_UCAST,
__IFLA_BRPORT_MAX
 };
 #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index 7cb41ae..75d041e 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -174,6 +174,29 @@ static struct net_bridge_port *maybe_deliver(
return p;
 }
 
+static void maybe_deliver_addr(struct net_bridge_port *p, struct sk_buff *skb,
+  const unsigned char *addr, bool local_orig)
+{
+   struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
+   const unsigned char *src = eth_hdr(skb)->h_source;
+
+   if (!should_deliver(p, skb))
+   return;
+
+   /* Even with hairpin, no soliloquies - prevent breaking IPv6 DAD */
+   if (skb->dev == p->dev && ether_addr_equal(src, addr))
+   return;
+
+   skb = skb_copy(skb, GFP_ATOMIC);
+   if (!skb) {
+   dev->stats.tx_dropped++;
+   return;
+   }
+
+   memcpy(eth_hdr(skb)->h_dest, addr, ETH_ALEN);
+   __br_forward(p, skb, local_orig);
+}
+
 /* called under rcu_read_lock */
 void br_flood(struct net_bridge *br, struct sk_buff *skb,
  enum br_pkt_type pkt_type, bool local_rcv, bool local_orig)
@@ -241,10 +264,20 @@ void br_multicast_flood(struct net_bridge_mdb_entry *md

Re: [PATCH net-next] bridge: multicast to unicast

2017-01-09 Thread Linus Lüssing
On Mon, Jan 09, 2017 at 01:30:32PM -0800, Stephen Hemminger wrote:
> I wonder if MAC80211 should be doing IGMP snooping and not bridge
> in this environment.

In the long term, yes. For now, not quite sure.

I personally like to go for simple solutions first :).


Re: [PATCH net-next] bridge: multicast to unicast

2017-01-09 Thread Linus Lüssing
On Mon, Jan 09, 2017 at 10:42:46PM +0100, Johannes Berg wrote:
> On Mon, 2017-01-09 at 22:33 +0100, Linus Lüssing wrote:
> > On Mon, Jan 09, 2017 at 01:44:03PM +0100, Johannes Berg wrote:
> > > 
> > > > >  A host SHOULD silently discard a datagram that is
> > > > > received via
> > > > >  a link-layer broadcast (see Section 2.4) but does not
> > > > > specify
> > > > >  an IP multicast or broadcast destination address.
> > > > 
> > > > This example is the other way round. It specifies how the IP
> > > > destination should look like in case of link-layer broadcast. Not
> > > > how the link-layer destination should look like in case of a
> > > > multicast/broadcast IP destination.
> > > 
> > > You stopped reading too early - snipped the context part for you :)
> > 
> > Sorry for writing to you directly, but I still have some
> > difficulties. In pseudo-code that line says:
> > 
> > -
> > if ll_dst(pkt) == bcast AND ip_dst(pkt) != mcast/bcast:
> > -> drop(pkt)
> > -
> > 
> > But after multicast-to-unicast conversion, we have:
> > 
> > -
> > ll_dst(pkt) == ucast AND ip_dst(pkt) == mcast
> > -
> > 
> > So none of the two requirements for dropping are matched?
> > 
> 
> Exactly. My point is that this is breaking the expectation that hosts
> are actually able to drop such packets.

[readding CCs I removed earlier]

Ah! Thanks. I was worried about creating packetloss :D.

Hm, for this other other way round, I think it does not apply for
the bridge multicast-to-unicast patch if I'm not misreading the bridge code:

For a packet with a link-layer multicast address but a unicast IP
destination, the bridge MDB lookup will fail.
(http://lxr.free-electrons.com/source/net/bridge/br_multicast.c?v=4.8#L178
 returns NULL)

Case A): No multicast router on port:
-> bridge, br_multicast_flood(), will drop the packet already
   (no matter if multicast-to-unicast is enabled or not)

Case B): Multicast router present on port:
-> The new patch does not apply multicast-to-unicast but just floods
   packet unaltered
   ("else { port = rport; addr = NULL; }" branch)

Regards, Linus


Re: [PATCH net-next] bridge: multicast to unicast

2017-01-09 Thread Linus Lüssing
On Mon, Jan 09, 2017 at 12:44:19PM +0100, M. Braun wrote:
> Am 09.01.2017 um 09:08 schrieb Johannes Berg:
> > Does it make sense to implement the two in separate layers though?
> > 
> > Clearly, this part needs to be implemented in the bridge layer due to
> > the snooping knowledge, but the code is very similar to what mac80211
> > has now.
> 
> Does the bridge always know about all stations connected?

The bridge does not always know about all stations, especially the
silent ones like in your DVB-T example.

However, concerning IP multicast, there is IGMP/MLD. So the bridge
does know about all stations which are interested in a specific IP
multicast stream.

(As long as there is a querier on the link, which periodically
queriers for IGMP/MLD reports from any listener. If there is no
querier then the bridge multicast snooping, including the bridge
multicast-to-unicast will fall back to flooding)


So if your television example uses IP multicast properly, it is
completely doable with the bridge multicast-to-unicast, thanks to
IGMP/MLD.


Re: [PATCH net-next] bridge: multicast to unicast

2017-01-09 Thread Linus Lüssing
On Mon, Jan 09, 2017 at 09:05:49AM +0100, Johannes Berg wrote:
> On Sat, 2017-01-07 at 16:15 +0100, Linus Lüssing wrote:
> 
> > Actually, I do not quite understand that remark in the mac80211
> > multicast-to-unicast patch. IP should not care about the ethernet
> > header?
> 
> But it does, for example RFC 1122 states:
> 
>  When a host sends a datagram to a link-layer broadcast address,
>  the IP destination address MUST be a legal IP broadcast or IP
>  multicast address.
> 
>  A host SHOULD silently discard a datagram that is received via
>  a link-layer broadcast (see Section 2.4) but does not specify
>  an IP multicast or broadcast destination address.

This example is the other way round. It specifies how the IP
destination should look like in case of link-layer broadcast. Not
how the link-layer destination should look like in case of a
multicast/broadcast IP destination.

Any other examples?


Re: [PATCH net-next] bridge: multicast to unicast

2017-01-07 Thread Linus Lüssing
On Fri, Jan 06, 2017 at 01:47:52PM +0100, Johannes Berg wrote:
> How does this compare and/or relate to the multicast-to-unicast feature
> we were going to add to the wifi stack, particularly mac80211? Do we
> perhaps not need that feature at all, if bridging will have it?
> 
> I suppose that the feature there could apply also to locally generated
> traffic when the AP interface isn't in a bridge, but I think I could
> live with requiring the AP to be put into a bridge to achieve a similar
> configuration?
> 
> Additionally, on an unrelated note, this seems to apply generically to
> all kinds of frames, losing information by replacing the address.
> Shouldn't it have similar limitations as the wifi stack feature has
> then, like only applying to ARP, IPv4, IPv6 and not general protocols?

(should all three be answered with Michael's and my reply to
Michael's mail, I think)

> 
> Also, it should probably come with the same caveat as we documented for
> the wifi feature:
> 
> Note that this may break certain expectations of the receiver,
> such as the ability to drop unicast IP packets received within
> multicast L2 frames, or the ability to not send ICMP destination
> unreachable messages for packets received in L2 multicast (which
> is required, but the receiver can't tell the difference if this
> new option is enabled.)

Actually, I do not quite understand that remark in the mac80211
multicast-to-unicast patch. IP should not care about the ethernet
header?


Re: [PATCH net-next] bridge: multicast to unicast

2017-01-07 Thread Linus Lüssing
On Fri, Jan 06, 2017 at 07:13:56PM -0800, Stephen Hemminger wrote:
> On Mon,  2 Jan 2017 20:32:14 +0100
> Linus Lüssing  wrote:
> 
> > This feature is intended for interface types which have a more reliable
> > and/or efficient way to deliver unicast packets than broadcast ones
> > (e.g. wifi).
> 
> 
> Why is this not done in MAC80211 rather than  bridge?

Because mac80211 does not have the IGMP/MLD snooping code as
the bridge has?

Reimplementing the snooping in mac80211 does not make sense
because of duplicating code. Moving the snooping code from the
bridge to mac80211 does not make sense either, because we want
multicast snooping, software based, (virtually) wired switches,
too.

The "best way" (TM) would probably be to migrate the IGMP/MLD
snooping from the bridge code to the net device code on the long
run to make such a database usable for any kind of device, without
needing this bridge hack.

But such a migration would also need a way more invasive patchset.

While Felix's idea might look a little "ugly" due it's hacky
nature, I think it is also quite beautiful thanks to it's
simplicity.


Re: [PATCH net-next] bridge: multicast to unicast

2017-01-07 Thread Linus Lüssing
On Sat, Jan 07, 2017 at 11:32:57AM +0100, M. Braun wrote:
> Am 06.01.2017 um 14:54 schrieb Johannes Berg:
> > 
> >> The bridge layer can use IGMP snooping to ensure that the multicast
> >> stream is only transmitted to clients that are actually a member of
> >> the group. Can the mac80211 feature do the same?
> > 
> > No, it'll convert the packet for all clients that are behind that
> > netdev. But that's an argument for dropping the mac80211 feature, which
> > hasn't been merged upstream yet, no?
> 
> But there is multicast/broadcast traffic like e.g. ARP and some IP
> multicast groups that are not covered by IGMP snooping. The mac80211
> patch converts this to unicast as well, which the bridge cannot do.
> 
> That way, these features both complement and overlap each other.

Right, I'd agree with that.

I didn't write it explicitly in the commit message, but yes, the
like anything concerning bridge multicast snooping, bridge
multicast-to-unicast can only affect packets as noted in
RFC4541 ("Considerations for Internet Group Management Protocol (IGMP)
and Multicast Listener Discovery (MLD) Snooping Switches"), too.

So it is only working for IPv4 multicast, excluding link-local
(224.0.0.0/24), and IPv6 multicast, excluding all-host-multicast
(ff02::1).

And does not concern ARP in any way.


The nice complementary effect is, that the bridge can first sieve
out those IP packets thanks to IGMP/MLD snooping knowledge and for
anything else, like ARP, 224.0.0.x or ff02::1, the mac80211
multicast-to-unicast could do its job.


For APs with a small number of STAs (like your private home AP),
you might want to enable both bridge multicast-to-unicast and
mac80211 multicast-to-unicast for this complementary effect. While
on public APs with 30 to 50 STAs with varying distances and bitrates,
you might only one to enable the bridge one, because sending an ARP
packet 50x might actually reduce performance and airtime
significantly.


[PATCH net-next] bridge: multicast to unicast

2017-01-02 Thread Linus Lüssing
Implements an optional, per bridge port flag and feature to deliver
multicast packets to any host on the according port via unicast
individually. This is done by copying the packet per host and
changing the multicast destination MAC to a unicast one accordingly.

multicast-to-unicast works on top of the multicast snooping feature of
the bridge. Which means unicast copies are only delivered to hosts which
are interested in it and signalized this via IGMP/MLD reports
previously.

This feature is intended for interface types which have a more reliable
and/or efficient way to deliver unicast packets than broadcast ones
(e.g. wifi).

However, it should only be enabled on interfaces where no IGMPv2/MLDv1
report suppression takes place. This feature is disabled by default.

The initial patch and idea is from Felix Fietkau.

Cc: Felix Fietkau 
Signed-off-by: Linus Lüssing 

---

This feature is used and enabled by default in OpenWRT and LEDE for AP
interfaces for more than a year now to allow both a more robust multicast
delivery and multicast at higher rates (e.g. multicast streaming).

In OpenWRT/LEDE the IGMP/MLD report suppression issue is overcome by
the network daemon enabling AP isolation and by that separating all STAs.
Delivery of STA-to-STA IP mulitcast is made possible again by
enabling and utilizing the bridge hairpin mode, which considers the
incoming port as a potential outgoing port, too.

Hairpin-mode is performed after multicast snooping, therefore leading to
only deliver reports to STAs running a multicast router.
---
 include/linux/if_bridge.h |  1 +
 net/bridge/br_forward.c   | 44 +--
 net/bridge/br_mdb.c   |  2 +-
 net/bridge/br_multicast.c | 92 ++-
 net/bridge/br_private.h   |  4 ++-
 net/bridge/br_sysfs_if.c  |  2 ++
 6 files changed, 115 insertions(+), 30 deletions(-)

diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index c6587c0..f1b0d78 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -46,6 +46,7 @@ struct br_ip_list {
 #define BR_LEARNING_SYNC   BIT(9)
 #define BR_PROXYARP_WIFI   BIT(10)
 #define BR_MCAST_FLOOD BIT(11)
+#define BR_MULTICAST_TO_UCAST  BIT(12)
 
 #define BR_DEFAULT_AGEING_TIME (300 * HZ)
 
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index 7cb41ae..49d742d 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -174,6 +174,33 @@ static struct net_bridge_port *maybe_deliver(
return p;
 }
 
+static struct net_bridge_port *maybe_deliver_addr(
+   struct net_bridge_port *prev, struct net_bridge_port *p,
+   struct sk_buff *skb, const unsigned char *addr,
+   bool local_orig)
+{
+   struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
+   const unsigned char *src = eth_hdr(skb)->h_source;
+
+   if (!should_deliver(p, skb))
+   return prev;
+
+   /* Even with hairpin, no soliloquies - prevent breaking IPv6 DAD */
+   if (skb->dev == p->dev && ether_addr_equal(src, addr))
+   return prev;
+
+   skb = skb_copy(skb, GFP_ATOMIC);
+   if (!skb) {
+   dev->stats.tx_dropped++;
+   return prev;
+   }
+
+   memcpy(eth_hdr(skb)->h_dest, addr, ETH_ALEN);
+   __br_forward(p, skb, local_orig);
+
+   return prev;
+}
+
 /* called under rcu_read_lock */
 void br_flood(struct net_bridge *br, struct sk_buff *skb,
  enum br_pkt_type pkt_type, bool local_rcv, bool local_orig)
@@ -231,6 +258,7 @@ void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
struct net_bridge_port *prev = NULL;
struct net_bridge_port_group *p;
struct hlist_node *rp;
+   const unsigned char *addr;
 
rp = rcu_dereference(hlist_first_rcu(&br->router_list));
p = mdst ? rcu_dereference(mdst->ports) : NULL;
@@ -241,10 +269,20 @@ void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
rport = rp ? hlist_entry(rp, struct net_bridge_port, rlist) :
 NULL;
 
-   port = (unsigned long)lport > (unsigned long)rport ?
-  lport : rport;
+   if ((unsigned long)lport > (unsigned long)rport) {
+   port = lport;
+   addr = p->unicast ? p->eth_addr : NULL;
+   } else {
+   port = rport;
+   addr = NULL;
+   }
+
+   if (addr)
+   prev = maybe_deliver_addr(prev, port, skb, addr,
+ local_orig);
+   else
+   prev = maybe_deliver(prev, port, skb, local_orig);
 
-   prev = maybe_deliver(prev, port, skb, local_orig);
if (IS_ERR(prev))
goto out;
if (prev == port)
diff --git a/net/bridge/br_mdb.c b/net/bridge/

Re: [PATCH] mac80211_hwsim: suggest nl80211 instead of wext driver in documentation

2016-10-17 Thread Linus Lüssing
On Mon, Oct 17, 2016 at 11:39:04AM +0200, Johannes Berg wrote:
> On Mon, 2016-10-17 at 00:39 +0200, Linus Lüssing wrote:
> > For mac80211_hwsim interfaces, suggest to use wpa_supplicant with the
> > more modern, netlink based driver instead of wext.
> 
> Makes sense, applied.
> 
> > Actually, I wasn't even able to make a connection with the
> > configuration
> > files and information provided in
> > Documentation/networking/mac80211_hwsim/{README,hostapd.conf/wpa_supp
> > licant.conf}
> > 
> This less so, we even have a few test cases we run regularly, but I
> don't know. Maybe there's something special in those configuration
> files that we don't test for otherwise.

I investigated a little further and the problem is probably that
I'm running a minimal Linux kernel which was compiled without
CONFIG_CFG80211_WEXT :-).

Anyways, thanks for applying the patch!

Regards, Linus


[PATCH] mac80211_hwsim: suggest nl80211 instead of wext driver in documentation

2016-10-16 Thread Linus Lüssing
For mac80211_hwsim interfaces, suggest to use wpa_supplicant with the more
modern, netlink based driver instead of wext.

Signed-off-by: Linus Lüssing 
---

Actually, I wasn't even able to make a connection with the configuration
files and information provided in
Documentation/networking/mac80211_hwsim/{README,hostapd.conf/wpa_supplicant.conf}

Changing -Dwext to -Dnl80211 helped and made the WPA-PSK connection with
mac80211_hwsim interfaces work for me.
---
 Documentation/networking/mac80211_hwsim/README | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/networking/mac80211_hwsim/README 
b/Documentation/networking/mac80211_hwsim/README
index 24ac91d..3566a72 100644
--- a/Documentation/networking/mac80211_hwsim/README
+++ b/Documentation/networking/mac80211_hwsim/README
@@ -60,7 +60,7 @@ modprobe mac80211_hwsim
 hostapd hostapd.conf
 
 # Run wpa_supplicant (station) for wlan1
-wpa_supplicant -Dwext -iwlan1 -c wpa_supplicant.conf
+wpa_supplicant -Dnl80211 -iwlan1 -c wpa_supplicant.conf
 
 
 More test cases are available in hostap.git:
-- 
2.1.4



[PATCH] cfg80211: Add stub for cfg80211_get_station()

2016-08-19 Thread Linus Lüssing
This allows modules using this function (currently: batman-adv) to
compile even if cfg80211 is not built at all, thus relaxing
dependencies.

Signed-off-by: Linus Lüssing 
---
 include/net/cfg80211.h | 9 +
 1 file changed, 9 insertions(+)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 9c23f4d3..beb7610 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1102,6 +1102,7 @@ struct station_info {
struct cfg80211_tid_stats pertid[IEEE80211_NUM_TIDS + 1];
 };
 
+#if IS_ENABLED(CONFIG_CFG80211)
 /**
  * cfg80211_get_station - retrieve information about a given station
  * @dev: the device where the station is supposed to be connected to
@@ -1114,6 +1115,14 @@ struct station_info {
  */
 int cfg80211_get_station(struct net_device *dev, const u8 *mac_addr,
 struct station_info *sinfo);
+#else
+static inline int cfg80211_get_station(struct net_device *dev,
+  const u8 *mac_addr,
+  struct station_info *sinfo)
+{
+   return -ENOENT;
+}
+#endif
 
 /**
  * enum monitor_flags - monitor flags
-- 
2.1.4



[PATCH] mailmap: Add Linus Lüssing

2016-07-06 Thread Linus Lüssing
For one thing, summarizes all non-umlaut versions into the umlaut one
(Linus Luessing -> Linus Lüssing).

For another, maps obosolete email addresses to the current @c0d3.blue
one.

Signed-off-by: Linus Lüssing 
---
 .mailmap | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/.mailmap b/.mailmap
index 52489f5..d4e7b66 100644
--- a/.mailmap
+++ b/.mailmap
@@ -91,6 +91,8 @@ Krzysztof Kozlowski  

 Kuninori Morimoto 
 Leonid I Ananiev 
 Linas Vepstas 
+Linus Lüssing  
+Linus Lüssing  
 Mark Brown 
 Matthieu CASTET 
 Mauro Carvalho Chehab   
   
 
-- 
2.1.4



Re: [PATCH net] Bridge: Fix ipv6 mc snooping if bridge has no ipv6 address

2016-06-28 Thread Linus Lüssing
On Tue, Jun 28, 2016 at 08:04:42AM -0400, David Miller wrote:
> From: Linus Lüssing 
> [...]
> > Fixes: 1d81d4c3dd88 ("bridge: check return value of ipv6_dev_get_saddr()")
> 
> You're missing an initial 'd' in that SHA1-ID.
> 
> With that fixed, applied and queued up for -stable.

Sorry :(. Thanks for taking care of it!


Re: [PATCH net] Bridge: Fix ipv6 mc snooping if bridge has no ipv6 address

2016-06-25 Thread Linus Lüssing
On Fri, Jun 24, 2016 at 12:35:18PM +0200, Daniel Danzberger wrote:
> The bridge is falsly dropping ipv6 mulitcast packets if there is:
>  1. No ipv6 address assigned on the brigde.
>  2. No external mld querier present.
>  3. The internal querier enabled.
> 
> When the bridge fails to build mld queries, because it has no
> ipv6 address, it slilently returns, but keeps the local querier enabled.
> This specific case causes confusing packet loss.
> 
> Ipv6 multicast snooping can only work if:
>  a) An external querier is present
>  OR
>  b) The bridge has an ipv6 address an is capable of sending own queries
> 
> Otherwise it has to forward/flood the ipv6 multicast traffic,
> because snooping cannot work.
> 
> This patch fixes the issue by adding a flag to the bridge struct that
> indicates that there is currently no ipv6 address assinged to the bridge
> and returns a false state for the local querier in
> __br_multicast_querier_exists().

Fixes: 1d81d4c3dd88 ("bridge: check return value of ipv6_dev_get_saddr()")


Re: [PATCH net] Bridge: Fix ipv6 mc snooping if bridge has no ipv6 address

2016-06-24 Thread Linus Lüssing
On Fri, Jun 24, 2016 at 12:35:18PM +0200, Daniel Danzberger wrote:
> The bridge is falsly dropping ipv6 mulitcast packets if there is:
>  1. No ipv6 address assigned on the brigde.
>  2. No external mld querier present.
>  3. The internal querier enabled.
> 
> When the bridge fails to build mld queries, because it has no
> ipv6 address, it slilently returns, but keeps the local querier enabled.
> This specific case causes confusing packet loss.
> 
> Ipv6 multicast snooping can only work if:
>  a) An external querier is present
>  OR
>  b) The bridge has an ipv6 address an is capable of sending own queries
> 
> Otherwise it has to forward/flood the ipv6 multicast traffic,
> because snooping cannot work.
> 
> This patch fixes the issue by adding a flag to the bridge struct that
> indicates that there is currently no ipv6 address assinged to the bridge
> and returns a false state for the local querier in
> __br_multicast_querier_exists().

Acked-by: Linus Lüssing 


Re: [PATCH 3.16 046/114] batman-adv: Fix broadcast/ogm queue limit on a removed interface

2016-06-13 Thread Linus Lüssing
On Mon, Jun 13, 2016 at 07:36:37PM +0100, Ben Hutchings wrote:
> 3.16.36-rc1 review patch.  If anyone has any objections, please let me know.
> 

Hi Ben,

This one looks weird. The version you added for 3.2.81-rc1 looked
better.

Cheers, Linus



> --
> 
> From: Linus Lüssing 
> 
> commit c4fdb6cff2aa0ae740c5f19b6f745cbbe786d42f upstream.
> 
> When removing a single interface while a broadcast or ogm packet is
> still pending then we will free the forward packet without releasing the
> queue slots again.
> 
> This patch is supposed to fix this issue.
> 
> Fixes: 6d5808d4ae1b ("batman-adv: Add missing hardif_free_ref in 
> forw_packet_free")
> Signed-off-by: Linus Lüssing 
> [s...@narfation.org: fix conflicts with current version]
> Signed-off-by: Sven Eckelmann 
> Signed-off-by: Marek Lindner 
> Signed-off-by: Antonio Quartulli 
> Signed-off-by: Ben Hutchings 
> ---
>  net/batman-adv/send.c | 6 ++
>  1 file changed, 6 insertions(+)
> 
> --- a/net/batman-adv/send.c
> +++ b/net/batman-adv/send.c
> @@ -638,6 +638,12 @@ batadv_purge_outstanding_packets(struct
>  
>   if (pending) {
>   hlist_del(&forw_packet->list);
> + if (!forw_packet->own)
> + atomic_inc(&bat_priv->bcast_queue_left);
> +
> + if (!forw_packet->own)
> + atomic_inc(&bat_priv->batman_queue_left);
> +
>   batadv_forw_packet_free(forw_packet);
>   }
>   }
> 


[PATCHv2 net] bridge: fix igmp / mld query parsing

2016-05-04 Thread Linus Lüssing
With the newly introduced helper functions the skb pulling is hidden
in the checksumming function - and undone before returning to the
caller.

The IGMP and MLD query parsing functions in the bridge still
assumed that the skb is pointing to the beginning of the IGMP/MLD
message while it is now kept at the beginning of the IPv4/6 header.

If there is a querier somewhere else, then this either causes
the multicast snooping to stay disabled even though it could be
enabled. Or, if we have the querier enabled too, then this can
create unnecessary IGMP / MLD query messages on the link.

Fixing this by taking the offset between IP and IGMP/MLD header into
account, too.

Fixes: 9afd85c9e455 ("net: Export IGMP/MLD message validation code")
Reported-by: Simon Wunderlich 
Signed-off-by: Linus Lüssing 
---
v2: changed "int" to "unsigned int"

 net/bridge/br_multicast.c |   12 +++-
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 03661d9..ea98937 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1270,6 +1270,7 @@ static int br_ip4_multicast_query(struct net_bridge *br,
struct br_ip saddr;
unsigned long max_delay;
unsigned long now = jiffies;
+   unsigned int offset = skb_transport_offset(skb);
__be32 group;
int err = 0;
 
@@ -1280,14 +1281,14 @@ static int br_ip4_multicast_query(struct net_bridge *br,
 
group = ih->group;
 
-   if (skb->len == sizeof(*ih)) {
+   if (skb->len == offset + sizeof(*ih)) {
max_delay = ih->code * (HZ / IGMP_TIMER_SCALE);
 
if (!max_delay) {
max_delay = 10 * HZ;
group = 0;
}
-   } else if (skb->len >= sizeof(*ih3)) {
+   } else if (skb->len >= offset + sizeof(*ih3)) {
ih3 = igmpv3_query_hdr(skb);
if (ih3->nsrcs)
goto out;
@@ -1348,6 +1349,7 @@ static int br_ip6_multicast_query(struct net_bridge *br,
struct br_ip saddr;
unsigned long max_delay;
unsigned long now = jiffies;
+   unsigned int offset = skb_transport_offset(skb);
const struct in6_addr *group = NULL;
bool is_general_query;
int err = 0;
@@ -1357,8 +1359,8 @@ static int br_ip6_multicast_query(struct net_bridge *br,
(port && port->state == BR_STATE_DISABLED))
goto out;
 
-   if (skb->len == sizeof(*mld)) {
-   if (!pskb_may_pull(skb, sizeof(*mld))) {
+   if (skb->len == offset + sizeof(*mld)) {
+   if (!pskb_may_pull(skb, offset + sizeof(*mld))) {
err = -EINVAL;
goto out;
}
@@ -1367,7 +1369,7 @@ static int br_ip6_multicast_query(struct net_bridge *br,
if (max_delay)
group = &mld->mld_mca;
} else {
-   if (!pskb_may_pull(skb, sizeof(*mld2q))) {
+   if (!pskb_may_pull(skb, offset + sizeof(*mld2q))) {
err = -EINVAL;
goto out;
}
-- 
1.7.10.4



Re: [PATCH net] bridge: fix igmp / mld query parsing

2016-05-04 Thread Linus Lüssing
On Tue, May 03, 2016 at 01:26:23PM -0700, Stephen Hemminger wrote:
> On Tue,  3 May 2016 22:18:54 +0200
> Linus Lüssing  wrote:
> 
> > diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
> > index 03661d9..7105cdf 100644
> > --- a/net/bridge/br_multicast.c
> > +++ b/net/bridge/br_multicast.c
> > @@ -1271,6 +1271,7 @@ static int br_ip4_multicast_query(struct net_bridge 
> > *br,
> > unsigned long max_delay;
> > unsigned long now = jiffies;
> > __be32 group;
> > +   int offset = skb_transport_offset(skb);
> shouldn't this be unsigned?

Yes, should always be unsigned here.

Ok, I'm changing that (even though skb_transport_offset() is "static
inline int").


[PATCH net] bridge: fix igmp / mld query parsing

2016-05-03 Thread Linus Lüssing
With the newly introduced helper functions the skb pulling is hidden
in the checksumming function - and undone before returning to the
caller.

The IGMP and MLD query parsing functions in the bridge still
assumed that the skb is pointing to the beginning of the IGMP/MLD
message while it is now kept at the beginning of the IPv4/6 header.

If there is a querier somewhere else, then this either causes
the multicast snooping to stay disabled even though it could be
enabled. Or, if we have the querier enabled too, then this can
create unnecessary IGMP / MLD query messages on the link.

Fixing this by taking the offset between IP and IGMP/MLD header into
account, too.

Fixes: 9afd85c9e455 ("net: Export IGMP/MLD message validation code")
Reported-by: Simon Wunderlich 
Signed-off-by: Linus Lüssing 
---
 net/bridge/br_multicast.c |   12 +++-
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 03661d9..7105cdf 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1271,6 +1271,7 @@ static int br_ip4_multicast_query(struct net_bridge *br,
unsigned long max_delay;
unsigned long now = jiffies;
__be32 group;
+   int offset = skb_transport_offset(skb);
int err = 0;
 
spin_lock(&br->multicast_lock);
@@ -1280,14 +1281,14 @@ static int br_ip4_multicast_query(struct net_bridge *br,
 
group = ih->group;
 
-   if (skb->len == sizeof(*ih)) {
+   if (skb->len == offset + sizeof(*ih)) {
max_delay = ih->code * (HZ / IGMP_TIMER_SCALE);
 
if (!max_delay) {
max_delay = 10 * HZ;
group = 0;
}
-   } else if (skb->len >= sizeof(*ih3)) {
+   } else if (skb->len >= offset + sizeof(*ih3)) {
ih3 = igmpv3_query_hdr(skb);
if (ih3->nsrcs)
goto out;
@@ -1350,6 +1351,7 @@ static int br_ip6_multicast_query(struct net_bridge *br,
unsigned long now = jiffies;
const struct in6_addr *group = NULL;
bool is_general_query;
+   int offset = skb_transport_offset(skb);
int err = 0;
 
spin_lock(&br->multicast_lock);
@@ -1357,8 +1359,8 @@ static int br_ip6_multicast_query(struct net_bridge *br,
(port && port->state == BR_STATE_DISABLED))
goto out;
 
-   if (skb->len == sizeof(*mld)) {
-   if (!pskb_may_pull(skb, sizeof(*mld))) {
+   if (skb->len == offset + sizeof(*mld)) {
+   if (!pskb_may_pull(skb, offset + sizeof(*mld))) {
err = -EINVAL;
goto out;
}
@@ -1367,7 +1369,7 @@ static int br_ip6_multicast_query(struct net_bridge *br,
if (max_delay)
group = &mld->mld_mca;
} else {
-   if (!pskb_may_pull(skb, sizeof(*mld2q))) {
+   if (!pskb_may_pull(skb, offset + sizeof(*mld2q))) {
err = -EINVAL;
goto out;
}
-- 
1.7.10.4



[PATCHv3] net: fix bridge multicast packet checksum validation

2016-02-23 Thread Linus Lüssing
We need to update the skb->csum after pulling the skb, otherwise
an unnecessary checksum (re)computation can ocure for IGMP/MLD packets
in the bridge code. Additionally this fixes the following splats for
network devices / bridge ports with support for and enabled RX checksum
offloading:

[...]
[   43.986968] eth0: hw csum failure
[   43.990344] CPU: 3 PID: 0 Comm: swapper/3 Not tainted 4.4.0 #2
[   43.996193] Hardware name: BCM2709
[   43.999647] [<800204e0>] (unwind_backtrace) from [<8001cf14>] 
(show_stack+0x10/0x14)
[   44.007432] [<8001cf14>] (show_stack) from [<801ab614>] 
(dump_stack+0x80/0x90)
[   44.014695] [<801ab614>] (dump_stack) from [<802e4548>] 
(__skb_checksum_complete+0x6c/0xac)
[   44.023090] [<802e4548>] (__skb_checksum_complete) from [<803a055c>] 
(ipv6_mc_validate_checksum+0x104/0x178)
[   44.032959] [<803a055c>] (ipv6_mc_validate_checksum) from [<802e111c>] 
(skb_checksum_trimmed+0x130/0x188)
[   44.042565] [<802e111c>] (skb_checksum_trimmed) from [<803a06e8>] 
(ipv6_mc_check_mld+0x118/0x338)
[   44.051501] [<803a06e8>] (ipv6_mc_check_mld) from [<803b2c98>] 
(br_multicast_rcv+0x5dc/0xd00)
[   44.060077] [<803b2c98>] (br_multicast_rcv) from [<803aa510>] 
(br_handle_frame_finish+0xac/0x51c)
[...]

Fixes: 9afd85c9e455 ("net: Export IGMP/MLD message validation code")
Reported-by: Álvaro Fernández Rojas 
Signed-off-by: Linus Lüssing 
---

v3:
* Missed that an skb_postpush_rcsum() was just added for v4.5, using that
  one instead

v2:
* substituted the storing of the csum with an skb_push_rcsum() approach
 (did some more reading about CHECKSUM_PARTIAL, and it seems to me that the
  skb_push direction is actually the easier/"safer" one, so there should be
  no resetting to CHECKSUM_NONE necessary)
* Rewording of commit message, this bug should not cause any packet loss
  due to "automatic" checksum recomputations in software if skb->csum
  is bogus (in the CHECKSUM_COMPLETE case)


 net/core/skbuff.c |   22 --
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 5bf88f5..8616d11 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -2948,6 +2948,24 @@ int skb_append_pagefrags(struct sk_buff *skb, struct 
page *page,
 EXPORT_SYMBOL_GPL(skb_append_pagefrags);
 
 /**
+ * skb_push_rcsum - push skb and update receive checksum
+ * @skb: buffer to update
+ * @len: length of data pulled
+ *
+ * This function performs an skb_push on the packet and updates
+ * the CHECKSUM_COMPLETE checksum.  It should be used on
+ * receive path processing instead of skb_push unless you know
+ * that the checksum difference is zero (e.g., a valid IP header)
+ * or you are setting ip_summed to CHECKSUM_NONE.
+ */
+static unsigned char *skb_push_rcsum(struct sk_buff *skb, unsigned len)
+{
+   skb_push(skb, len);
+   skb_postpush_rcsum(skb, skb->data, len);
+   return skb->data;
+}
+
+/**
  * skb_pull_rcsum - pull skb and update receive checksum
  * @skb: buffer to update
  * @len: length of data pulled
@@ -4084,9 +4102,9 @@ struct sk_buff *skb_checksum_trimmed(struct sk_buff *skb,
if (!pskb_may_pull(skb_chk, offset))
goto err;
 
-   __skb_pull(skb_chk, offset);
+   skb_pull_rcsum(skb_chk, offset);
ret = skb_chkf(skb_chk);
-   __skb_push(skb_chk, offset);
+   skb_push_rcsum(skb_chk, offset);
 
if (ret)
goto err;
-- 
1.7.10.4



[PATCHv2] net: fix bridge multicast packet checksum validation

2016-02-23 Thread Linus Lüssing
We need to update the skb->csum after pulling the skb, otherwise
an unnecessary checksum (re)computation can ocure for IGMP/MLD packets
in the bridge code. Additionally this fixes the following splats for
network devices / bridge ports with support for and enabled RX checksum
offloading:

[...]
[   43.986968] eth0: hw csum failure
[   43.990344] CPU: 3 PID: 0 Comm: swapper/3 Not tainted 4.4.0 #2
[   43.996193] Hardware name: BCM2709
[   43.999647] [<800204e0>] (unwind_backtrace) from [<8001cf14>] 
(show_stack+0x10/0x14)
[   44.007432] [<8001cf14>] (show_stack) from [<801ab614>] 
(dump_stack+0x80/0x90)
[   44.014695] [<801ab614>] (dump_stack) from [<802e4548>] 
(__skb_checksum_complete+0x6c/0xac)
[   44.023090] [<802e4548>] (__skb_checksum_complete) from [<803a055c>] 
(ipv6_mc_validate_checksum+0x104/0x178)
[   44.032959] [<803a055c>] (ipv6_mc_validate_checksum) from [<802e111c>] 
(skb_checksum_trimmed+0x130/0x188)
[   44.042565] [<802e111c>] (skb_checksum_trimmed) from [<803a06e8>] 
(ipv6_mc_check_mld+0x118/0x338)
[   44.051501] [<803a06e8>] (ipv6_mc_check_mld) from [<803b2c98>] 
(br_multicast_rcv+0x5dc/0xd00)
[   44.060077] [<803b2c98>] (br_multicast_rcv) from [<803aa510>] 
(br_handle_frame_finish+0xac/0x51c)
[...]

Fixes: 9afd85c9e455 ("net: Export IGMP/MLD message validation code")
Reported-by: Álvaro Fernández Rojas 
Signed-off-by: Linus Lüssing 
---

v2:
* substituted the storing of the csum with an skb_push_rcsum() approach
 (did some more reading about CHECKSUM_PARTIAL, and it seems to me that the
  skb_push direction is actually the easier/"safer" one, so there should be
  no resetting to CHECKSUM_NONE necessary)
* Rewording of commit message, this bug should not cause any packet loss
  due to "automatic" checksum recomputations in software if skb->csum
  is bogus (in the CHECKSUM_COMPLETE case)

 include/linux/skbuff.h |   17 +
 net/core/skbuff.c  |   22 --
 2 files changed, 37 insertions(+), 2 deletions(-)

diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 4ce9ff7..d66e007 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -2784,6 +2784,23 @@ static inline int skb_linearize_cow(struct sk_buff *skb)
 }
 
 /**
+ * skb_postpush_rcsum - update checksum for received skb after push
+ * @skb: buffer to update
+ * @start: start of data before push
+ * @len: length of data pushed
+ *
+ * After doing a push on a received packet, you need to call this to
+ * update the CHECKSUM_COMPLETE checksum.
+ */
+
+static inline void skb_postpush_rcsum(struct sk_buff *skb,
+ const void *start, unsigned int len)
+{
+   if (skb->ip_summed == CHECKSUM_COMPLETE)
+   skb->csum = csum_add(skb->csum, csum_partial(start, len, 0));
+}
+
+/**
  * skb_postpull_rcsum - update checksum for received skb after pull
  * @skb: buffer to update
  * @start: start of data before pull
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 5bf88f5..8616d11 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -2948,6 +2948,24 @@ int skb_append_pagefrags(struct sk_buff *skb, struct 
page *page,
 EXPORT_SYMBOL_GPL(skb_append_pagefrags);
 
 /**
+ * skb_push_rcsum - push skb and update receive checksum
+ * @skb: buffer to update
+ * @len: length of data pulled
+ *
+ * This function performs an skb_push on the packet and updates
+ * the CHECKSUM_COMPLETE checksum.  It should be used on
+ * receive path processing instead of skb_push unless you know
+ * that the checksum difference is zero (e.g., a valid IP header)
+ * or you are setting ip_summed to CHECKSUM_NONE.
+ */
+static unsigned char *skb_push_rcsum(struct sk_buff *skb, unsigned len)
+{
+   skb_push(skb, len);
+   skb_postpush_rcsum(skb, skb->data, len);
+   return skb->data;
+}
+
+/**
  * skb_pull_rcsum - pull skb and update receive checksum
  * @skb: buffer to update
  * @len: length of data pulled
@@ -4084,9 +4102,9 @@ struct sk_buff *skb_checksum_trimmed(struct sk_buff *skb,
if (!pskb_may_pull(skb_chk, offset))
goto err;
 
-   __skb_pull(skb_chk, offset);
+   skb_pull_rcsum(skb_chk, offset);
ret = skb_chkf(skb_chk);
-   __skb_push(skb_chk, offset);
+   skb_push_rcsum(skb_chk, offset);
 
if (ret)
goto err;
-- 
1.7.10.4



Re: [PATCH] net: fix bridge multicast packet checksum validation

2016-02-18 Thread Linus Lüssing
On Thu, Feb 18, 2016 at 01:51:34PM +0100, Steinar H. Gunderson wrote:
> On Mon, Feb 15, 2016 at 03:07:06AM +0100, Linus Lüssing wrote:
> > Steinar, can you check whether this fixes the bridge issues you reported on
> > bugzilla #99081? Not quite sure whether it is the same as yours as you
> > do not seem to have any such call traces.
> 
> It doesn't immediately sound like the same problem; why would promisc change
> anything if the problem is the checksumming?

The mdb you provided in the bugzilla ticket misses reports, so it
was unable to parse reports. Which could point to a checksumming
problem.

Enabling promisc probably did not fix the parsing for you, but instead
promisc forces to forward packets upstream on your interface independent
of the mdb. I would assume that even with promisc, your output
from "bridge mdb show" looks rather empty. Can you check?

> 
> I don't have any reboots scheduled for this machine right now, but I'll see
> what I can do wrt. testing.

Thanks :).


[PATCH] net: fix bridge multicast packet checksum validation

2016-02-14 Thread Linus Lüssing
We need to update the skb->csum after pulling the skb, otherwise
checksum validation will fail. This fixes multicast packet loss for
bridges and splats like the following:

[...]
[   43.986968] eth0: hw csum failure
[   43.990344] CPU: 3 PID: 0 Comm: swapper/3 Not tainted 4.4.0 #2
[   43.996193] Hardware name: BCM2709
[   43.999647] [<800204e0>] (unwind_backtrace) from [<8001cf14>] 
(show_stack+0x10/0x14)
[   44.007432] [<8001cf14>] (show_stack) from [<801ab614>] 
(dump_stack+0x80/0x90)
[   44.014695] [<801ab614>] (dump_stack) from [<802e4548>] 
(__skb_checksum_complete+0x6c/0xac)
[   44.023090] [<802e4548>] (__skb_checksum_complete) from [<803a055c>] 
(ipv6_mc_validate_checksum+0x104/0x178)
[   44.032959] [<803a055c>] (ipv6_mc_validate_checksum) from [<802e111c>] 
(skb_checksum_trimmed+0x130/0x188)
[   44.042565] [<802e111c>] (skb_checksum_trimmed) from [<803a06e8>] 
(ipv6_mc_check_mld+0x118/0x338)
[   44.051501] [<803a06e8>] (ipv6_mc_check_mld) from [<803b2c98>] 
(br_multicast_rcv+0x5dc/0xd00)
[   44.060077] [<803b2c98>] (br_multicast_rcv) from [<803aa510>] 
(br_handle_frame_finish+0xac/0x51c)
[...]

Fixes: 9afd85c9e455 ("net: Export IGMP/MLD message validation code")
Reported-by: Álvaro Fernández Rojas 
Signed-off-by: Linus Lüssing 
---

Steinar, can you check whether this fixes the bridge issues you reported on
bugzilla #99081? Not quite sure whether it is the same as yours as you
do not seem to have any such call traces.


I am not super happy with how this patch looks, but there is no "skb_push_rcsum"
available and skb_pull_rcsum() seems non-reversible as is. Alternative 
suggestions
always welcome.


 net/core/skbuff.c |   19 ++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 5bf88f5..6c34ef6 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -4076,6 +4076,11 @@ struct sk_buff *skb_checksum_trimmed(struct sk_buff *skb,
struct sk_buff *skb_chk;
unsigned int offset = skb_transport_offset(skb);
__sum16 ret;
+   int ip_summed;
+   int csum_valid;
+   int csum_level;
+   int csum_bad;
+   __wsum csum;
 
skb_chk = skb_checksum_maybe_trim(skb, transport_len);
if (!skb_chk)
@@ -4084,10 +4089,22 @@ struct sk_buff *skb_checksum_trimmed(struct sk_buff 
*skb,
if (!pskb_may_pull(skb_chk, offset))
goto err;
 
-   __skb_pull(skb_chk, offset);
+   ip_summed = skb->ip_summed;
+   csum_valid = skb->csum_valid;
+   csum_level = skb->csum_level;
+   csum_bad = skb->csum_bad;
+   csum = skb->csum;
+
+   skb_pull_rcsum(skb_chk, offset);
ret = skb_chkf(skb_chk);
__skb_push(skb_chk, offset);
 
+   skb->ip_summed = ip_summed;
+   skb->csum_valid = csum_valid;
+   skb->csum_level = csum_level;
+   skb->csum_bad = csum_bad;
+   skb->csum = csum;
+
if (ret)
goto err;
 
-- 
1.7.10.4



Re: [PATCH 4.1 15/29] bridge: fix igmpv3 / mldv2 report parsing

2015-10-01 Thread Linus Lüssing
Hi Greg,

On Thu, Oct 01, 2015 at 11:31:51AM +0200, Greg Kroah-Hartman wrote:
> 4.1-stable review patch.  If anyone has any objections, please let me know.
[...]
> Fixes: 9afd85c9e455 ("net: Export IGMP/MLD message validation code")

While it shouldn't(tm) break anything on 4.1, there's no need to
pull it here. 9afd85c9e455 introduced the bug and was added in 4.2
only.

Cheers, Linus
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH net] bridge: fix igmpv3 / mldv2 report parsing

2015-09-11 Thread Linus Lüssing
With the newly introduced helper functions the skb pulling is hidden in
the checksumming function - and undone before returning to the caller.

The IGMPv3 and MLDv2 report parsing functions in the bridge still
assumed that the skb is pointing to the beginning of the IGMP/MLD
message while it is now kept at the beginning of the IPv4/6 header,
breaking the message parsing and creating packet loss.

Fixing this by taking the offset between IP and IGMP/MLD header into
account, too.

Fixes: 9afd85c9e455 ("net: Export IGMP/MLD message validation code")
Reported-by: Tobias Powalowski 
Tested-by: Tobias Powalowski 
Signed-off-by: Linus Lüssing 
---
 net/bridge/br_multicast.c |4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 66efdc2..480b3de 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1006,7 +1006,7 @@ static int br_ip4_multicast_igmp3_report(struct 
net_bridge *br,
 
ih = igmpv3_report_hdr(skb);
num = ntohs(ih->ngrec);
-   len = sizeof(*ih);
+   len = skb_transport_offset(skb) + sizeof(*ih);
 
for (i = 0; i < num; i++) {
len += sizeof(*grec);
@@ -1067,7 +1067,7 @@ static int br_ip6_multicast_mld2_report(struct net_bridge 
*br,
 
icmp6h = icmp6_hdr(skb);
num = ntohs(icmp6h->icmp6_dataun.un_data16[1]);
-   len = sizeof(*icmp6h);
+   len = skb_transport_offset(skb) + sizeof(*icmp6h);
 
for (i = 0; i < num; i++) {
__be16 *nsrcs, _nsrcs;
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] net: fix wrong skb_get() usage / crash in IGMP/MLD parsing code

2015-08-12 Thread Linus Lüssing
The recent refactoring of the IGMP and MLD parsing code into
ipv6_mc_check_mld() / ip_mc_check_igmp() introduced a potential crash /
BUG() invocation for bridges:

I wrongly assumed that skb_get() could be used as a simple reference
counter for an skb which is not the case. skb_get() bears additional
semantics, a user count. This leads to a BUG() invocation in
pskb_expand_head() / kernel panic if pskb_may_pull() is called on an skb
with a user count greater than one - unfortunately the refactoring did
just that.

Fixing this by removing the skb_get() call and changing the API: The
caller of ipv6_mc_check_mld() / ip_mc_check_igmp() now needs to
additionally check whether the returned skb_trimmed is a clone.

Fixes: 9afd85c9e455 ("net: Export IGMP/MLD message validation code")
Reported-by: Brenden Blanco 
Signed-off-by: Linus Lüssing 
---
 net/bridge/br_multicast.c |4 ++--
 net/core/skbuff.c |   37 ++---
 net/ipv4/igmp.c   |   33 ++---
 net/ipv6/mcast_snoop.c|   33 ++---
 4 files changed, 56 insertions(+), 51 deletions(-)

diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 0b39dcc..1285eaf 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1591,7 +1591,7 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
break;
}
 
-   if (skb_trimmed)
+   if (skb_trimmed && skb_trimmed != skb)
kfree_skb(skb_trimmed);
 
return err;
@@ -1636,7 +1636,7 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
break;
}
 
-   if (skb_trimmed)
+   if (skb_trimmed && skb_trimmed != skb)
kfree_skb(skb_trimmed);
 
return err;
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index b6a19ca..bf9a5d9 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -4022,8 +4022,8 @@ EXPORT_SYMBOL(skb_checksum_setup);
  * Otherwise returns the provided skb. Returns NULL in error cases
  * (e.g. transport_len exceeds skb length or out-of-memory).
  *
- * Caller needs to set the skb transport header and release the returned skb.
- * Provided skb is consumed.
+ * Caller needs to set the skb transport header and free any returned skb if it
+ * differs from the provided skb.
  */
 static struct sk_buff *skb_checksum_maybe_trim(struct sk_buff *skb,
   unsigned int transport_len)
@@ -4032,16 +4032,12 @@ static struct sk_buff *skb_checksum_maybe_trim(struct 
sk_buff *skb,
unsigned int len = skb_transport_offset(skb) + transport_len;
int ret;
 
-   if (skb->len < len) {
-   kfree_skb(skb);
+   if (skb->len < len)
return NULL;
-   } else if (skb->len == len) {
+   else if (skb->len == len)
return skb;
-   }
 
skb_chk = skb_clone(skb, GFP_ATOMIC);
-   kfree_skb(skb);
-
if (!skb_chk)
return NULL;
 
@@ -4066,8 +4062,8 @@ static struct sk_buff *skb_checksum_maybe_trim(struct 
sk_buff *skb,
  * If the skb has data beyond the given transport length, then a
  * trimmed & cloned skb is checked and returned.
  *
- * Caller needs to set the skb transport header and release the returned skb.
- * Provided skb is consumed.
+ * Caller needs to set the skb transport header and free any returned skb if it
+ * differs from the provided skb.
  */
 struct sk_buff *skb_checksum_trimmed(struct sk_buff *skb,
 unsigned int transport_len,
@@ -4079,23 +4075,26 @@ struct sk_buff *skb_checksum_trimmed(struct sk_buff 
*skb,
 
skb_chk = skb_checksum_maybe_trim(skb, transport_len);
if (!skb_chk)
-   return NULL;
+   goto err;
 
-   if (!pskb_may_pull(skb_chk, offset)) {
-   kfree_skb(skb_chk);
-   return NULL;
-   }
+   if (!pskb_may_pull(skb_chk, offset))
+   goto err;
 
__skb_pull(skb_chk, offset);
ret = skb_chkf(skb_chk);
__skb_push(skb_chk, offset);
 
-   if (ret) {
-   kfree_skb(skb_chk);
-   return NULL;
-   }
+   if (ret)
+   goto err;
 
return skb_chk;
+
+err:
+   if (skb_chk && skb_chk != skb)
+   kfree_skb(skb_chk);
+
+   return NULL;
+
 }
 EXPORT_SYMBOL(skb_checksum_trimmed);
 
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 651cdf6..9fdfd9d 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -1435,33 +1435,35 @@ static int __ip_mc_check_igmp(struct sk_buff *skb, 
struct sk_buff **skb_trimmed)
struct sk_buff *skb_chk;
unsigned int transport_len;
unsigned int len = skb_transport_offset(skb) + sizeof(struct igmphdr);
-   int ret;
+   int ret = -EINVAL;
 
transport_len = ntohs(ip_hdr(skb)->tot_len

[PATCHv3 net-next] bridge: allow setting hash_max + multicast_router if interface is down

2015-05-22 Thread Linus Lüssing
Network managers like netifd (used in OpenWRT for instance) try to
configure interface options after creation but before setting the
interface up.

Unfortunately the sysfs / bridge currently only allows to configure the
hash_max and multicast_router options when the bridge interface is up.
But since br_multicast_init() doesn't start any timers and only sets
default values and initializes timers it should be save to reconfigure
the default values after that, before things actually get active after
the bridge is set up.

Signed-off-by: Linus Lüssing 
---
Changelog v3:
* Readded two breaks (cosmetic / for future safety reasons)

Changelog v2:
* remove another now unnecessary -ENOENT initialization
* consistently initialize to -EINVAL, allowing to shorten two switch-cases

 net/bridge/br_multicast.c |   24 +++-
 1 file changed, 3 insertions(+), 21 deletions(-)

diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 2d69d5c..28a87c2 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1772,11 +1772,9 @@ out:
 
 int br_multicast_set_router(struct net_bridge *br, unsigned long val)
 {
-   int err = -ENOENT;
+   int err = -EINVAL;
 
spin_lock_bh(&br->multicast_lock);
-   if (!netif_running(br->dev))
-   goto unlock;
 
switch (val) {
case 0:
@@ -1787,13 +1785,8 @@ int br_multicast_set_router(struct net_bridge *br, 
unsigned long val)
br->multicast_router = val;
err = 0;
break;
-
-   default:
-   err = -EINVAL;
-   break;
}
 
-unlock:
spin_unlock_bh(&br->multicast_lock);
 
return err;
@@ -1802,11 +1795,9 @@ unlock:
 int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val)
 {
struct net_bridge *br = p->br;
-   int err = -ENOENT;
+   int err = -EINVAL;
 
spin_lock(&br->multicast_lock);
-   if (!netif_running(br->dev) || p->state == BR_STATE_DISABLED)
-   goto unlock;
 
switch (val) {
case 0:
@@ -1828,13 +1819,8 @@ int br_multicast_set_port_router(struct net_bridge_port 
*p, unsigned long val)
 
br_multicast_add_router(br, p);
break;
-
-   default:
-   err = -EINVAL;
-   break;
}
 
-unlock:
spin_unlock(&br->multicast_lock);
 
return err;
@@ -1939,15 +1925,11 @@ unlock:
 
 int br_multicast_set_hash_max(struct net_bridge *br, unsigned long val)
 {
-   int err = -ENOENT;
+   int err = -EINVAL;
u32 old;
struct net_bridge_mdb_htable *mdb;
 
spin_lock_bh(&br->multicast_lock);
-   if (!netif_running(br->dev))
-   goto unlock;
-
-   err = -EINVAL;
if (!is_power_of_2(val))
goto unlock;
 
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCHv2 net-next] bridge: allow setting hash_max + multicast_router if interface is down

2015-05-22 Thread Linus Lüssing
Network managers like netifd (used in OpenWRT for instance) try to
configure interface options after creation but before setting the
interface up.

Unfortunately the sysfs / bridge currently only allows to configure the
hash_max and multicast_router options when the bridge interface is up.
But since br_multicast_init() doesn't start any timers and only sets
default values and initializes timers it should be save to reconfigure
the default values after that, before things actually get active after
the bridge is set up.

Signed-off-by: Linus Lüssing 
---
Changelog v2:
* remove another now unnecessary -ENOENT initialization
* consistently initialize to -EINVAL, allowing to shorten two switch-cases

 net/bridge/br_multicast.c |   26 +++---
 1 file changed, 3 insertions(+), 23 deletions(-)

diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 2d69d5c..9955fa4 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1772,11 +1772,9 @@ out:
 
 int br_multicast_set_router(struct net_bridge *br, unsigned long val)
 {
-   int err = -ENOENT;
+   int err = -EINVAL;
 
spin_lock_bh(&br->multicast_lock);
-   if (!netif_running(br->dev))
-   goto unlock;
 
switch (val) {
case 0:
@@ -1786,14 +1784,8 @@ int br_multicast_set_router(struct net_bridge *br, 
unsigned long val)
case 1:
br->multicast_router = val;
err = 0;
-   break;
-
-   default:
-   err = -EINVAL;
-   break;
}
 
-unlock:
spin_unlock_bh(&br->multicast_lock);
 
return err;
@@ -1802,11 +1794,9 @@ unlock:
 int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val)
 {
struct net_bridge *br = p->br;
-   int err = -ENOENT;
+   int err = -EINVAL;
 
spin_lock(&br->multicast_lock);
-   if (!netif_running(br->dev) || p->state == BR_STATE_DISABLED)
-   goto unlock;
 
switch (val) {
case 0:
@@ -1827,14 +1817,8 @@ int br_multicast_set_port_router(struct net_bridge_port 
*p, unsigned long val)
break;
 
br_multicast_add_router(br, p);
-   break;
-
-   default:
-   err = -EINVAL;
-   break;
}
 
-unlock:
spin_unlock(&br->multicast_lock);
 
return err;
@@ -1939,15 +1923,11 @@ unlock:
 
 int br_multicast_set_hash_max(struct net_bridge *br, unsigned long val)
 {
-   int err = -ENOENT;
+   int err = -EINVAL;
u32 old;
struct net_bridge_mdb_htable *mdb;
 
spin_lock_bh(&br->multicast_lock);
-   if (!netif_running(br->dev))
-   goto unlock;
-
-   err = -EINVAL;
if (!is_power_of_2(val))
goto unlock;
 
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH net-next] bridge: allow setting hash_max + multicast_router if interface is down

2015-05-21 Thread Linus Lüssing
Network managers like netifd (used in OpenWRT for instance) try to
configure interface options after creation but before setting the
interface up.

Unfortunately the sysfs / bridge currently only allows to configure the
hash_max and multicast_router options when the bridge interface is up.
But since br_multicast_init() doesn't start any timers and only sets
default values and initializes timers it should be save to reconfigure
the default values after that, before things actually get active after
the bridge is set up.

With this patch hash_max and multicast_router attributes can be
changed even if the according bridge (port) is down, just like other
other bridge (port) attributes allow too.

Signed-off-by: Linus Lüssing 
---
Changelog:
* [RFC PATCH net-next] -> [PATCH net-next]


 net/bridge/br_multicast.c |   15 ++-
 1 file changed, 2 insertions(+), 13 deletions(-)

diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 2d69d5c..066199e 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1775,8 +1775,6 @@ int br_multicast_set_router(struct net_bridge *br, 
unsigned long val)
int err = -ENOENT;
 
spin_lock_bh(&br->multicast_lock);
-   if (!netif_running(br->dev))
-   goto unlock;
 
switch (val) {
case 0:
@@ -1793,7 +1791,6 @@ int br_multicast_set_router(struct net_bridge *br, 
unsigned long val)
break;
}
 
-unlock:
spin_unlock_bh(&br->multicast_lock);
 
return err;
@@ -1802,18 +1799,15 @@ unlock:
 int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val)
 {
struct net_bridge *br = p->br;
-   int err = -ENOENT;
+   int err = 0;
 
spin_lock(&br->multicast_lock);
-   if (!netif_running(br->dev) || p->state == BR_STATE_DISABLED)
-   goto unlock;
 
switch (val) {
case 0:
case 1:
case 2:
p->multicast_router = val;
-   err = 0;
 
if (val < 2 && !hlist_unhashed(&p->rlist))
hlist_del_init_rcu(&p->rlist);
@@ -1834,7 +1828,6 @@ int br_multicast_set_port_router(struct net_bridge_port 
*p, unsigned long val)
break;
}
 
-unlock:
spin_unlock(&br->multicast_lock);
 
return err;
@@ -1939,15 +1932,11 @@ unlock:
 
 int br_multicast_set_hash_max(struct net_bridge *br, unsigned long val)
 {
-   int err = -ENOENT;
+   int err = -EINVAL;
u32 old;
struct net_bridge_mdb_htable *mdb;
 
spin_lock_bh(&br->multicast_lock);
-   if (!netif_running(br->dev))
-   goto unlock;
-
-   err = -EINVAL;
if (!is_power_of_2(val))
goto unlock;
 
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [RFC PATCH net-next] bridge: allow setting hash_max + multicast_router if interface is down

2015-05-21 Thread Linus Lüssing
On Thu, May 21, 2015 at 11:49:21AM +0800, Herbert Xu wrote:
> The timer operations are all supposed to be idempotent.  So enabling
> a port twice or stopping it twice should be OK.

Oki doki.

> 
> > * Might calls to br_multicast_add_router() via br_multicast_enable_port()
> >   cause unintended side-effects?
> 
> What do you mean? How does add_router get called from enable_port?

Sorry, ment br_multicast_add_router() via
br_multicast_set_port_router(). But it's not modifying any timers,
and other modifications are locked by the multicast lock, right.

> See above.  It's there so that you don't readd a timer when we're
> calling del_timer_sync.  del_timer_sync has to be called without
> the multicast lock so that's why we need another mechanism to
> prevent the timers from being readded.

Right, all the touched functions never rearm a timer. The
multicast_router timer may only get readded upon receiving a
multicast query.
(br_multicast_query_received()->br_multicast_mark_router() )
By removing the netif_running check we might only delete a timer
which wasn't running anyway which as you said already is safe.

> 
> AFAICS the spots you patched aren't adding timers so they *should*
> be OK.

Okay, thanks for your thorough explanations about the timers and
how the locking is supposed to work. After your explanations I
went over the code a few more times and am fairly confident too
now, that this patch is supposed to work fine.

Going to resend this patch without the RFC tag.

Cheers, Linus
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[RFC PATCH net-next] bridge: allow setting hash_max + multicast_router if interface is down

2015-05-20 Thread Linus Lüssing
Network managers like netifd (used in OpenWRT for instance) try to
configure interface options after creation but before setting the
interface up.

Unfortunately the sysfs / bridge currently only allows to configure the
hash_max and multicast_router options when the bridge interface is up.
But since br_multicast_init() doesn't start any timers and only sets
default values and initializes timers it should be save to reconfigure
the default values after that, before things actually get active after
the bridge is set up.

With this patch hash_max and multicast_router attributes can be
changed even if the according bridge (port) is down, just like other
other bridge (port) attributes allow too.

Signed-off-by: Linus Lüssing 
---

I'm currently a little unsure about a few things (that's why I'm sending
this as an RFC):

* For i=br_multicast_init(), e=br_multicast_enable() and
  s=br_multicast_stop() is the order i->e->s->e->s->e->... always
  ensured by the netdev API? Will this work even if I have
  many fast and wild calls to "ip link set up dev br0" and
  "ip link set down dev br0" and some changes to hash_max and
  multicast_router in between?

* Might calls to br_multicast_add_router() via br_multicast_enable_port()
  cause unintended side-effects?

* (maybe independent of this patch: )
  Can fast changes to the multicast_router attribute of a bridge (port)
  cause race conditions because a del_timer() instead of a
  del_timer_sync() is used in br_multicast_set_{port,}router()?
  (or: why does br_multicast_stop() use del_timer_sync() while
   br_multicast_disable_port() doesn't?)

* @Herbert: Do you remember whether there was a reason for
  checking netif_running() or the bridge port state which
  I might have overlooked?


PS: Running this patch didn't create any crashes for me so far
and multicast traffic still runs fine. No locust infestation in sight
yet either. Still careful though :P.

 net/bridge/br_multicast.c |   15 ++-
 1 file changed, 2 insertions(+), 13 deletions(-)

diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 2d69d5c..066199e 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1775,8 +1775,6 @@ int br_multicast_set_router(struct net_bridge *br, 
unsigned long val)
int err = -ENOENT;
 
spin_lock_bh(&br->multicast_lock);
-   if (!netif_running(br->dev))
-   goto unlock;
 
switch (val) {
case 0:
@@ -1793,7 +1791,6 @@ int br_multicast_set_router(struct net_bridge *br, 
unsigned long val)
break;
}
 
-unlock:
spin_unlock_bh(&br->multicast_lock);
 
return err;
@@ -1802,18 +1799,15 @@ unlock:
 int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val)
 {
struct net_bridge *br = p->br;
-   int err = -ENOENT;
+   int err = 0;
 
spin_lock(&br->multicast_lock);
-   if (!netif_running(br->dev) || p->state == BR_STATE_DISABLED)
-   goto unlock;
 
switch (val) {
case 0:
case 1:
case 2:
p->multicast_router = val;
-   err = 0;
 
if (val < 2 && !hlist_unhashed(&p->rlist))
hlist_del_init_rcu(&p->rlist);
@@ -1834,7 +1828,6 @@ int br_multicast_set_port_router(struct net_bridge_port 
*p, unsigned long val)
break;
}
 
-unlock:
spin_unlock(&br->multicast_lock);
 
return err;
@@ -1939,15 +1932,11 @@ unlock:
 
 int br_multicast_set_hash_max(struct net_bridge *br, unsigned long val)
 {
-   int err = -ENOENT;
+   int err = -EINVAL;
u32 old;
struct net_bridge_mdb_htable *mdb;
 
spin_lock_bh(&br->multicast_lock);
-   if (!netif_running(br->dev))
-   goto unlock;
-
-   err = -EINVAL;
if (!is_power_of_2(val))
goto unlock;
 
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH net-next] net: fix two sparse warnings introduced by IGMP/MLD parsing exports

2015-05-04 Thread Linus Lüssing
> net/core/skbuff.c:4108:13: sparse: incorrect type in assignment (different 
> base types)
> net/ipv6/mcast_snoop.c:63 ipv6_mc_check_exthdrs() warn: unsigned 'offset' is 
> never less than zero.

Introduced by 9afd85c9e4552b276e2f4cfefd622bdeeffbbf26
("net: Export IGMP/MLD message validation code")

Reported-by: kbuild test robot 
Signed-off-by: Linus Lüssing 
---
 net/core/skbuff.c  |2 +-
 net/ipv6/mcast_snoop.c |2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 1e4278a..b9eb90b 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -4093,7 +4093,7 @@ struct sk_buff *skb_checksum_trimmed(struct sk_buff *skb,
 {
struct sk_buff *skb_chk;
unsigned int offset = skb_transport_offset(skb);
-   int ret;
+   __sum16 ret;
 
skb_chk = skb_checksum_maybe_trim(skb, transport_len);
if (!skb_chk)
diff --git a/net/ipv6/mcast_snoop.c b/net/ipv6/mcast_snoop.c
index 1a2cbc1..df8afe5 100644
--- a/net/ipv6/mcast_snoop.c
+++ b/net/ipv6/mcast_snoop.c
@@ -47,7 +47,7 @@ static int ipv6_mc_check_ip6hdr(struct sk_buff *skb)
 static int ipv6_mc_check_exthdrs(struct sk_buff *skb)
 {
const struct ipv6hdr *ip6h;
-   unsigned int offset;
+   int offset;
u8 nexthdr;
__be16 frag_off;
 
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCHv3 net-next 1/2] bridge: multicast: call skb_checksum_{simple_, }validate

2015-05-02 Thread Linus Lüssing
Let's use these new, neat helpers.

Signed-off-by: Linus Lüssing 
---
 net/bridge/br_multicast.c |   28 
 1 file changed, 4 insertions(+), 24 deletions(-)

diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 4b6722f..b52f4cb 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1610,16 +1610,8 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
if (!pskb_may_pull(skb2, sizeof(*ih)))
goto out;
 
-   switch (skb2->ip_summed) {
-   case CHECKSUM_COMPLETE:
-   if (!csum_fold(skb2->csum))
-   break;
-   /* fall through */
-   case CHECKSUM_NONE:
-   skb2->csum = 0;
-   if (skb_checksum_complete(skb2))
-   goto out;
-   }
+   if (skb_checksum_simple_validate(skb2))
+   goto out;
 
err = 0;
 
@@ -1737,20 +1729,8 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
 
ip6h = ipv6_hdr(skb2);
 
-   switch (skb2->ip_summed) {
-   case CHECKSUM_COMPLETE:
-   if (!csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, skb2->len,
-   IPPROTO_ICMPV6, skb2->csum))
-   break;
-   /*FALLTHROUGH*/
-   case CHECKSUM_NONE:
-   skb2->csum = ~csum_unfold(csum_ipv6_magic(&ip6h->saddr,
-   &ip6h->daddr,
-   skb2->len,
-   IPPROTO_ICMPV6, 0));
-   if (__skb_checksum_complete(skb2))
-   goto out;
-   }
+   if (skb_checksum_validate(skb2, IPPROTO_ICMPV6, ip6_compute_pseudo))
+   goto out;
 
err = 0;
 
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCHv3 net-next 2/2] net: Export IGMP/MLD message validation code

2015-05-02 Thread Linus Lüssing
With this patch, the IGMP and MLD message validation functions are moved
from the bridge code to IPv4/IPv6 multicast files. Some small
refactoring was done to enhance readibility and to iron out some
differences in behaviour between the IGMP and MLD parsing code (e.g. the
skb-cloning of MLD messages is now only done if necessary, just like the
IGMP part always did).

Finally, these IGMP and MLD message validation functions are exported so
that not only the bridge can use it but batman-adv later, too.

Signed-off-by: Linus Lüssing 
---
 include/linux/igmp.h  |1 +
 include/linux/skbuff.h|3 +
 include/net/addrconf.h|1 +
 net/bridge/br_multicast.c |  218 +++--
 net/core/skbuff.c |   87 ++
 net/ipv4/igmp.c   |  162 +
 net/ipv6/Makefile |1 +
 net/ipv6/mcast_snoop.c|  213 +++
 8 files changed, 498 insertions(+), 188 deletions(-)
 create mode 100644 net/ipv6/mcast_snoop.c

diff --git a/include/linux/igmp.h b/include/linux/igmp.h
index 2c677af..193ad48 100644
--- a/include/linux/igmp.h
+++ b/include/linux/igmp.h
@@ -130,5 +130,6 @@ extern void ip_mc_unmap(struct in_device *);
 extern void ip_mc_remap(struct in_device *);
 extern void ip_mc_dec_group(struct in_device *in_dev, __be32 addr);
 extern void ip_mc_inc_group(struct in_device *in_dev, __be32 addr);
+int ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed);
 
 #endif
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 66e374d..cd34010 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -3417,6 +3417,9 @@ static inline void skb_checksum_none_assert(const struct 
sk_buff *skb)
 bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off);
 
 int skb_checksum_setup(struct sk_buff *skb, bool recalculate);
+struct sk_buff *skb_checksum_trimmed(struct sk_buff *skb,
+unsigned int transport_len,
+__sum16(*skb_chkf)(struct sk_buff *skb));
 
 u32 skb_get_poff(const struct sk_buff *skb);
 u32 __skb_get_poff(const struct sk_buff *skb, void *data,
diff --git a/include/net/addrconf.h b/include/net/addrconf.h
index 80456f7..def59d3 100644
--- a/include/net/addrconf.h
+++ b/include/net/addrconf.h
@@ -142,6 +142,7 @@ void ipv6_mc_unmap(struct inet6_dev *idev);
 void ipv6_mc_remap(struct inet6_dev *idev);
 void ipv6_mc_init_dev(struct inet6_dev *idev);
 void ipv6_mc_destroy_dev(struct inet6_dev *idev);
+int ipv6_mc_check_mld(struct sk_buff *skb, struct sk_buff **skb_trimmed);
 void addrconf_dad_failure(struct inet6_ifaddr *ifp);
 
 bool ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group,
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index b52f4cb..2d69d5c 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -975,9 +975,6 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge 
*br,
int err = 0;
__be32 group;
 
-   if (!pskb_may_pull(skb, sizeof(*ih)))
-   return -EINVAL;
-
ih = igmpv3_report_hdr(skb);
num = ntohs(ih->ngrec);
len = sizeof(*ih);
@@ -1248,25 +1245,14 @@ static int br_ip4_multicast_query(struct net_bridge *br,
max_delay = 10 * HZ;
group = 0;
}
-   } else {
-   if (!pskb_may_pull(skb, sizeof(struct igmpv3_query))) {
-   err = -EINVAL;
-   goto out;
-   }
-
+   } else if (skb->len >= sizeof(*ih3)) {
ih3 = igmpv3_query_hdr(skb);
if (ih3->nsrcs)
goto out;
 
max_delay = ih3->code ?
IGMPV3_MRC(ih3->code) * (HZ / IGMP_TIMER_SCALE) : 1;
-   }
-
-   /* RFC2236+RFC3376 (IGMPv2+IGMPv3) require the multicast link layer
-* all-systems destination addresses (224.0.0.1) for general queries
-*/
-   if (!group && iph->daddr != htonl(INADDR_ALLHOSTS_GROUP)) {
-   err = -EINVAL;
+   } else {
goto out;
}
 
@@ -1329,12 +1315,6 @@ static int br_ip6_multicast_query(struct net_bridge *br,
(port && port->state == BR_STATE_DISABLED))
goto out;
 
-   /* RFC2710+RFC3810 (MLDv1+MLDv2) require link-local source addresses */
-   if (!(ipv6_addr_type(&ip6h->saddr) & IPV6_ADDR_LINKLOCAL)) {
-   err = -EINVAL;
-   goto out;
-   }
-
if (skb->len == sizeof(*mld)) {
if (!pskb_may_pull(skb, sizeof(*mld))) {
err = -EINVAL;
@@ -1358,14 +1338,6 @@ static int br_ip6_multicast_query(struct net_bridge *br,
 
is_general_query = group && ipv6_addr_any(group);
 
-   /* RFC2710+RFC3810 (MLDv1+MLDv2) req

[PATCHv3 net-next 0/2] Exporting IGMP/MLD checking from bridge code

2015-05-02 Thread Linus Lüssing
The multicast optimizations in batman-adv are yet only usable and
enabled in non-bridged scenarios. To be able to support bridged setups
batman-adv needs to be able to detect IGMP/MLD queriers and reports on
mesh nodes without bridges, too. See the following link for details:

http://www.open-mesh.org/projects/batman-adv/wiki/Multicast-optimizations-listener-reports

To avoid duplicate code between the bridge and batman-adv, the IGMP/MLD
message validation code is moved from the bridge to the IPv4/IPv6 stack.

On the way, some refactoring to increase readability and to iron out
some subtle differences between the IGMP and MLD parsing code is done.

Cheers, Linus


Changelog v3:
* changed interface / restructuring of skb_checksum_trimmed()
* kernel doc for skb_checksum_trimmed()/skb_checksum_maybe_trim()
* fixed a memory leak in the cloned skb case in skb_checksum_trimmed()
* fixed transport_len calculation in __ipv6_mc_check_mld(),
  make it relative to the skb transport header offset
  (= exclude the hop-by-hop option size in transport_len)

Changelog v2:
* Updated copyright for mcast_snoop.c

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCHv2 net-next 2/2] net: Export IGMP/MLD message validation code

2015-04-13 Thread Linus Lüssing
With this patch, the IGMP and MLD message validation functions are moved
from the bridge code to IPv4/IPv6 multicast files. Some small
refactoring was done to enhance readibility and to iron out some
differences in behaviour between the IGMP and MLD parsing code (e.g. the
skb-cloning of MLD messages is now only done if necessary, just like the
IGMP part always did).

Finally, these IGMP and MLD message validation functions are exported so
that not only the bridge can use it but batman-adv later, too.

Signed-off-by: Linus Lüssing 
---
 include/linux/igmp.h  |1 +
 include/linux/skbuff.h|3 +
 include/net/addrconf.h|1 +
 net/bridge/br_multicast.c |  218 +++--
 net/core/skbuff.c |   38 
 net/ipv4/igmp.c   |  152 +++
 net/ipv6/Makefile |1 +
 net/ipv6/mcast_snoop.c|  202 +
 8 files changed, 428 insertions(+), 188 deletions(-)
 create mode 100644 net/ipv6/mcast_snoop.c

diff --git a/include/linux/igmp.h b/include/linux/igmp.h
index 2c677af..193ad48 100644
--- a/include/linux/igmp.h
+++ b/include/linux/igmp.h
@@ -130,5 +130,6 @@ extern void ip_mc_unmap(struct in_device *);
 extern void ip_mc_remap(struct in_device *);
 extern void ip_mc_dec_group(struct in_device *in_dev, __be32 addr);
 extern void ip_mc_inc_group(struct in_device *in_dev, __be32 addr);
+int ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed);
 
 #endif
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 0991259..79d8e8b 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -3404,6 +3404,9 @@ static inline void skb_checksum_none_assert(const struct 
sk_buff *skb)
 bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off);
 
 int skb_checksum_setup(struct sk_buff *skb, bool recalculate);
+int skb_checksum_trimmed(struct sk_buff *skb, unsigned int transport_len,
+__sum16(*skb_check_func)(struct sk_buff *skb),
+struct sk_buff **skb_trimmed);
 
 u32 skb_get_poff(const struct sk_buff *skb);
 u32 __skb_get_poff(const struct sk_buff *skb, void *data,
diff --git a/include/net/addrconf.h b/include/net/addrconf.h
index 80456f7..def59d3 100644
--- a/include/net/addrconf.h
+++ b/include/net/addrconf.h
@@ -142,6 +142,7 @@ void ipv6_mc_unmap(struct inet6_dev *idev);
 void ipv6_mc_remap(struct inet6_dev *idev);
 void ipv6_mc_init_dev(struct inet6_dev *idev);
 void ipv6_mc_destroy_dev(struct inet6_dev *idev);
+int ipv6_mc_check_mld(struct sk_buff *skb, struct sk_buff **skb_trimmed);
 void addrconf_dad_failure(struct inet6_ifaddr *ifp);
 
 bool ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group,
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index b52f4cb..c2115b1 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -975,9 +975,6 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge 
*br,
int err = 0;
__be32 group;
 
-   if (!pskb_may_pull(skb, sizeof(*ih)))
-   return -EINVAL;
-
ih = igmpv3_report_hdr(skb);
num = ntohs(ih->ngrec);
len = sizeof(*ih);
@@ -1248,25 +1245,14 @@ static int br_ip4_multicast_query(struct net_bridge *br,
max_delay = 10 * HZ;
group = 0;
}
-   } else {
-   if (!pskb_may_pull(skb, sizeof(struct igmpv3_query))) {
-   err = -EINVAL;
-   goto out;
-   }
-
+   } else if (skb->len >= sizeof(*ih3)) {
ih3 = igmpv3_query_hdr(skb);
if (ih3->nsrcs)
goto out;
 
max_delay = ih3->code ?
IGMPV3_MRC(ih3->code) * (HZ / IGMP_TIMER_SCALE) : 1;
-   }
-
-   /* RFC2236+RFC3376 (IGMPv2+IGMPv3) require the multicast link layer
-* all-systems destination addresses (224.0.0.1) for general queries
-*/
-   if (!group && iph->daddr != htonl(INADDR_ALLHOSTS_GROUP)) {
-   err = -EINVAL;
+   } else {
goto out;
}
 
@@ -1329,12 +1315,6 @@ static int br_ip6_multicast_query(struct net_bridge *br,
(port && port->state == BR_STATE_DISABLED))
goto out;
 
-   /* RFC2710+RFC3810 (MLDv1+MLDv2) require link-local source addresses */
-   if (!(ipv6_addr_type(&ip6h->saddr) & IPV6_ADDR_LINKLOCAL)) {
-   err = -EINVAL;
-   goto out;
-   }
-
if (skb->len == sizeof(*mld)) {
if (!pskb_may_pull(skb, sizeof(*mld))) {
err = -EINVAL;
@@ -1358,14 +1338,6 @@ static int br_ip6_multicast_query(struct net_bridge *br,
 
is_general_query = group && ipv6_addr_any(group);
 
-   /* RFC2710+RFC3810 (MLDv1+MLDv2) require the multi

[PATCHv2 net-next 1/2] bridge: multicast: call skb_checksum_{simple_, }validate

2015-04-13 Thread Linus Lüssing
Let's use these new, neat helpers.

Signed-off-by: Linus Lüssing 
---
 net/bridge/br_multicast.c |   28 
 1 file changed, 4 insertions(+), 24 deletions(-)

diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 4b6722f..b52f4cb 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1610,16 +1610,8 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
if (!pskb_may_pull(skb2, sizeof(*ih)))
goto out;
 
-   switch (skb2->ip_summed) {
-   case CHECKSUM_COMPLETE:
-   if (!csum_fold(skb2->csum))
-   break;
-   /* fall through */
-   case CHECKSUM_NONE:
-   skb2->csum = 0;
-   if (skb_checksum_complete(skb2))
-   goto out;
-   }
+   if (skb_checksum_simple_validate(skb2))
+   goto out;
 
err = 0;
 
@@ -1737,20 +1729,8 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
 
ip6h = ipv6_hdr(skb2);
 
-   switch (skb2->ip_summed) {
-   case CHECKSUM_COMPLETE:
-   if (!csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, skb2->len,
-   IPPROTO_ICMPV6, skb2->csum))
-   break;
-   /*FALLTHROUGH*/
-   case CHECKSUM_NONE:
-   skb2->csum = ~csum_unfold(csum_ipv6_magic(&ip6h->saddr,
-   &ip6h->daddr,
-   skb2->len,
-   IPPROTO_ICMPV6, 0));
-   if (__skb_checksum_complete(skb2))
-   goto out;
-   }
+   if (skb_checksum_validate(skb2, IPPROTO_ICMPV6, ip6_compute_pseudo))
+   goto out;
 
err = 0;
 
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCHv2 net-next 0/2] Exporting IGMP/MLD checking from bridge code

2015-04-13 Thread Linus Lüssing
The multicast optimizations in batman-adv are yet only usable and
enabled in non-bridged scenarios. To be able to support bridged setups
batman-adv needs to be able to detect IGMP/MLD queriers and reports on
mesh nodes without bridges, too. See the following link for details:

http://www.open-mesh.org/projects/batman-adv/wiki/Multicast-optimizations-listener-reports

To avoid duplicate code between the bridge and batman-adv, the IGMP/MLD
message validation code is moved from the bridge to the IPv4/IPv6 stack.

On the way, some refactoring to increase readability and to iron out
some subtle differences between the IGMP and MLD parsing code is done.

Cheers, Linus


Changelog v2:
* Updated copyright for mcast_snoop.c

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [B.A.T.M.A.N.] [PATCH 2/2] net: Export IGMP/MLD message validation code

2015-04-10 Thread Linus Lüssing
On Fri, Apr 10, 2015 at 07:46:39PM +0200, Linus Lüssing wrote:
> diff --git a/net/ipv6/mcast_snoop.c b/net/ipv6/mcast_snoop.c
> new file mode 100644
> index 000..95b34c0
> --- /dev/null
> +++ b/net/ipv6/mcast_snoop.c
> @@ -0,0 +1,198 @@
> +/* Copyright (C) 2015: Linus Lüssing 

PS: I'm a little uncertain how this is usually done. If I should
add someone (maybe Hideaki YOSHIFUJI, the original author of the
bridge IPv6/MLD support?), then please let me know.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: bride: IPv6 multicast snooping enhancements

2015-02-12 Thread Linus Lüssing
On Tue, Feb 10, 2015 at 04:59:09PM +0300, Vasily Averin wrote:
> I'm trying to fix ICMPv6 processing broken in OpenVZ after rebase to last 
> RHEL6u6 kernel.
> After some unclear manipulation bridge begins to forward icmp6 NS (fe02::1) 
> into wrong port,
> and at present I do not found the reason of this failure.

fe02::1 seems uncommon for ICMPv6 NS messages. Would you mind
making some dumps for ~10 minutes with tcpdump on all bridge ports
and the bridge interface itself with a filter "icmp6" and uploading the
result somewhere?

Also provide a dump from "bridge mdb show dev $bridge" please (if
possible - not sure whether that's available on the ancient 2.6.32
kernel as used on RHEL6u6).

Cheers, Linus
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: bride: IPv6 multicast snooping enhancements

2015-02-10 Thread Linus Lüssing
Hi Vasily,

On Tue, Feb 10, 2015 at 11:44:29AM +0300, Vasily Averin wrote:
> This patch prevent forwarding of ICMPv6 in bridges,
> so containers/VMs with virtual eth adapters connected in local bridge cannot 
> ping each other via ipv6 (but can do it via ipv4)

If a host wants to receive packets, then it needs to signalize
that via MLD. If your host does not do that, then it is expected
to not receive ICMPv6 echo requests to multicast addresses. An
exception is ff02::1, that should always work.

> 
> Could you please clarify, is it expected behavior?
> Do we need to enable multicast routing or multicast_snooping on all local 
> ports on such bridges to enable just ICMPv6?

Nope, you shouldn't. You'd need multicast listeners. You shouldn't
need to play with the bridge settings to fix protocols.

> I believe ICMPv6 is an exception and should not be filtered by multicast 
> spoofing.

Signaling multicast joins is mandatory by the IPv6 standard. If
your protocol/application does not do that, then it seems to me
that the application might be broken.


By the way, which kernel version(s) are you using?

Cheers, Linus
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] bridge: fix netfilter/NF_BR_LOCAL_OUT for own, locally generated queries

2014-11-16 Thread Linus Lüssing
On Mon, Nov 03, 2014 at 06:01:46AM +0800, Herbert Xu wrote:
> On Mon, Sep 22, 2014 at 01:32:44AM +0200, Linus Lüssing wrote:
> > Signed-off-by: Linus Lüssing 
> 
> Acked-by: Herbert Xu 

Hi David,

are there any unanswered questions left?

Cheers, Linus
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] bridge: fix netfilter/NF_BR_LOCAL_OUT for own, locally generated queries

2014-11-02 Thread Linus Lüssing
On Mon, Sep 22, 2014 at 01:32:44AM +0200, Linus Lüssing wrote:
> Ebtables on the OUTPUT chain (NF_BR_LOCAL_OUT) would not work as expected
> for both locally generated IGMP and MLD queries. The IP header specific
> filter options are off by 14 Bytes for netfilter (actual output on
> interfaces is fine).
> 
> NF_HOOK() expects the skb->data to point to the IP header, not the
> ethernet one (while dev_queue_xmit() does not). Luckily there is an
> br_dev_queue_push_xmit() helper function already - let's just use that.

bump
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] bridge: fix netfilter/NF_BR_LOCAL_OUT for own, locally generated queries

2014-09-21 Thread Linus Lüssing
Ebtables on the OUTPUT chain (NF_BR_LOCAL_OUT) would not work as expected
for both locally generated IGMP and MLD queries. The IP header specific
filter options are off by 14 Bytes for netfilter (actual output on
interfaces is fine).

NF_HOOK() expects the skb->data to point to the IP header, not the
ethernet one (while dev_queue_xmit() does not). Luckily there is an
br_dev_queue_push_xmit() helper function already - let's just use that.

Introduced by eb1d16414339a6e113d89e2cca2556005d7ce919
("bridge: Add core IGMP snooping support")

Ebtables example:

$ ebtables -I OUTPUT -p IPv6 -o eth1 --logical-out br0 \
--log --log-level 6 --log-ip6 --log-prefix="~EBT: " -j DROP

before (broken):

~EBT:  IN= OUT=eth1 MAC source = 02:04:64:a4:39:c2 \
MAC dest = 33:33:00:00:00:01 proto = 0x86dd IPv6 \
SRC=64a4:39c2:86dd:6000::0020:0001:fe80 IPv6 \
DST=:::0004:64ff:fea4:39c2:ff02, \
IPv6 priority=0x3, Next Header=2

after (working):

~EBT:  IN= OUT=eth1 MAC source = 02:04:64:a4:39:c2 \
MAC dest = 33:33:00:00:00:01 proto = 0x86dd IPv6 \
SRC=fe80::::0004:64ff:fea4:39c2 IPv6 \
DST=ff02:::::::0001, \
IPv6 priority=0x0, Next Header=0

Signed-off-by: Linus Lüssing 
---
 net/bridge/br_multicast.c |3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 7751c92..9d02e6c 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -813,10 +813,9 @@ static void __br_multicast_send_query(struct net_bridge 
*br,
return;
 
if (port) {
-   __skb_push(skb, sizeof(struct ethhdr));
skb->dev = port->dev;
NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
-   dev_queue_xmit);
+   br_dev_queue_push_xmit);
} else {
br_multicast_select_own_querier(br, ip, skb);
netif_rx(skb);
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH net-next 0/4] bridge: multicast snooping exports #2

2014-07-06 Thread Linus Lüssing
Hi,

Some people pointed out to me that it might be helpful to add stubs for
the newly added multicast exports. That way e.g. batman-adv should continue
to be compile and useable without having to have a kernel compiled
with bridge code in the future. This is what the first patch is supposed
to do.

The second patch adds a third multicast export for the bridge which
e.g. batman-adv is supposed to use, too, soon: Just like the bridge
disables its multicast snooping activities if no querier is present,
batman-adv needs to do the same if bridges are involved.


These three exports should be the final ones needed to marry the bridge
multicast snooping with the batman-adv multicast optimizations recently
added for the 3.15 kernel, allowing to use these optimzations in common
setups having a bridge on top of e.g. bat0, too. So far these bridged
setups would fall back to simple flooding through the batman-adv mesh
network for any multicast packet entering bat0.

More information about the batman-adv multicast optimizations currently
implemented can be found here:

http://www.open-mesh.org/projects/batman-adv/wiki/Basic-multicast-optimizations

The integration on the batman-adv side could afterwards look like this,
for instance (now including the third export):

http://git.open-mesh.org/batman-adv.git/commitdiff/61e4f6af4b7a21ed4040f2e711d50c778e5b6d93?hp=6ae4281474675fbca5bedcf768972a32db586eb6

Cheers, Linus

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH net-next 2/2] bridge: export knowledge about the presence of IGMP/MLD queriers

2014-07-06 Thread Linus Lüssing
With this patch other modules are able to ask the bridge whether an
IGMP or MLD querier exists on the according, bridged link layer.

Multicast snooping can only be performed if a valid, selected querier
exists on a link.

Just like the bridge only enables its multicast snooping if a querier
exists, e.g. batman-adv too can only activate its multicast
snooping in bridged scenarios if a querier is present.

For instance this export avoids having to reimplement IGMP/MLD
querier message snooping and parsing in e.g. batman-adv, when
multicast optimizations for bridged scenarios are added in the
future.

Signed-off-by: Linus Lüssing 
---
 include/linux/if_bridge.h |6 ++
 net/bridge/br_multicast.c |   37 +
 2 files changed, 43 insertions(+)

diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index e0c575c..808dcb8 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -40,6 +40,7 @@ extern br_should_route_hook_t __rcu *br_should_route_hook;
 #if IS_ENABLED(CONFIG_BRIDGE) && IS_ENABLED(CONFIG_BRIDGE_IGMP_SNOOPING)
 int br_multicast_list_adjacent(struct net_device *dev,
   struct list_head *br_ip_list);
+bool br_multicast_has_querier_anywhere(struct net_device *dev, int proto);
 bool br_multicast_has_querier_adjacent(struct net_device *dev, int proto);
 #else
 static inline int br_multicast_list_adjacent(struct net_device *dev,
@@ -47,6 +48,11 @@ static inline int br_multicast_list_adjacent(struct 
net_device *dev,
 {
return 0;
 }
+static inline bool br_multicast_has_querier_anywhere(struct net_device *dev,
+int proto)
+{
+   return false;
+}
 static inline bool br_multicast_has_querier_adjacent(struct net_device *dev,
 int proto)
 {
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index abfa0b65..b4845f4 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -2216,6 +2216,43 @@ unlock:
 EXPORT_SYMBOL_GPL(br_multicast_list_adjacent);
 
 /**
+ * br_multicast_has_querier_anywhere - Checks for a querier on a bridge
+ * @dev: The bridge port providing the bridge on which to check for a querier
+ * @proto: The protocol family to check for: IGMP -> ETH_P_IP, MLD -> 
ETH_P_IPV6
+ *
+ * Checks whether the given interface has a bridge on top and if so returns
+ * true if a valid querier exists anywhere on the bridged link layer.
+ * Otherwise returns false.
+ */
+bool br_multicast_has_querier_anywhere(struct net_device *dev, int proto)
+{
+   struct net_bridge *br;
+   struct net_bridge_port *port;
+   struct ethhdr eth;
+   bool ret = false;
+
+   rcu_read_lock();
+   if (!br_port_exists(dev))
+   goto unlock;
+
+   port = br_port_get_rcu(dev);
+   if (!port || !port->br)
+   goto unlock;
+
+   br = port->br;
+
+   memset(ð, 0, sizeof(eth));
+   eth.h_proto = htons(proto);
+
+   ret = br_multicast_querier_exists(br, ð);
+
+unlock:
+   rcu_read_unlock();
+   return ret;
+}
+EXPORT_SYMBOL_GPL(br_multicast_has_querier_anywhere);
+
+/**
  * br_multicast_has_querier_adjacent - Checks for a querier behind a bridge 
port
  * @dev: The bridge port adjacent to which to check for a querier
  * @proto: The protocol family to check for: IGMP -> ETH_P_IP, MLD -> 
ETH_P_IPV6
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH net-next 1/2] bridge: adding stubs for multicast exports

2014-07-06 Thread Linus Lüssing
To make users (e.g. batman-adv soon) load- and runnable even if the
bridge was compiled without snooping capabilities - or even if the
kernel was compiled without any bridge code at all.

Signed-off-by: Linus Lüssing 
---
 include/linux/if_bridge.h |   14 ++
 1 file changed, 14 insertions(+)

diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index fd22789..e0c575c 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -36,8 +36,22 @@ extern void brioctl_set(int (*ioctl_hook)(struct net *, 
unsigned int, void __use
 
 typedef int br_should_route_hook_t(struct sk_buff *skb);
 extern br_should_route_hook_t __rcu *br_should_route_hook;
+
+#if IS_ENABLED(CONFIG_BRIDGE) && IS_ENABLED(CONFIG_BRIDGE_IGMP_SNOOPING)
 int br_multicast_list_adjacent(struct net_device *dev,
   struct list_head *br_ip_list);
 bool br_multicast_has_querier_adjacent(struct net_device *dev, int proto);
+#else
+static inline int br_multicast_list_adjacent(struct net_device *dev,
+struct list_head *br_ip_list)
+{
+   return 0;
+}
+static inline bool br_multicast_has_querier_adjacent(struct net_device *dev,
+int proto)
+{
+   return false;
+}
+#endif
 
 #endif
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 2/2] bridge: fix compile error when compiling without IPv6 support

2014-06-11 Thread Linus Lüssing
Some fields in "struct net_bridge" aren't available when compiling the
kernel without IPv6 support. Therefore adding a check/macro to skip the
complaining code sections in that case.

Introduced by 2cd4143192e8c60f66cb32c3a30c76d0470a372d
("bridge: memorize and export selected IGMP/MLD querier port")

Reported-by: kbuild test robot 
Signed-off-by: Linus Lüssing 
---
 net/bridge/br_multicast.c |2 ++
 1 file changed, 2 insertions(+)

diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 876e5fb..abfa0b65 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -2246,11 +2246,13 @@ bool br_multicast_has_querier_adjacent(struct 
net_device *dev, int proto)
rcu_dereference(br->ip4_querier.port) == port)
goto unlock;
break;
+#if IS_ENABLED(CONFIG_IPV6)
case ETH_P_IPV6:
if (!timer_pending(&br->ip6_other_query.timer) ||
rcu_dereference(br->ip6_querier.port) == port)
goto unlock;
break;
+#endif
default:
goto unlock;
}
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 0/2 net-next] bridge: fix bugs introduced by last multicast patchset

2014-06-11 Thread Linus Lüssing
Once my last patchset got applied, I got slapped by an automatic smatch
and build bot. Here are two patches fixing the according issues, a potential
null pointer dereference and a compile error when compiling without IPv6.

[PATCH 1/2] is probably not the ideal solution - the assignment of the
group and max_delay is still a mess and has subtle differences between
IGMPv2, IGMPv3, MLDv1 and MLDv2. That should probably be fixed $later.
But for now, I think the easier fix might be better, restoring the
behaviour before my "adhere to querier mechanism" patch and therefore
keeping things bisect'able.

Cheers, Linus
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 1/2] bridge: fix smatch warning / potential null pointer dereference

2014-06-11 Thread Linus Lüssing
 "New smatch warnings:
  net/bridge/br_multicast.c:1368 br_ip6_multicast_query() error:
we previously assumed 'group' could be null (see line 1349)"

In the rare (sort of broken) case of a query having a Maximum
Response Delay of zero, we could create a potential null pointer
dereference.

Fixing this by skipping the multicast specific MLD Query parsing again
if no multicast group address is available.

Introduced by dc4eb53a996a78bfb8ea07b47423ff5a3aadc362
("bridge: adhere to querier election mechanism specified by RFCs")

Reported-by: Dan Carpenter 
Signed-off-by: Linus Lüssing 
---
 net/bridge/br_multicast.c |2 ++
 1 file changed, 2 insertions(+)

diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index cd3cf39..876e5fb 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1373,6 +1373,8 @@ static int br_ip6_multicast_query(struct net_bridge *br,
br_multicast_query_received(br, port, &br->ip6_other_query,
&saddr, max_delay);
goto out;
+   } else if (!group) {
+   goto out;
}
 
mp = br_mdb_ip6_get(mlock_dereference(br->mdb, br), group, vid);
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCHv4 net-next 0/4] bridge: multicast snooping patches / exports

2014-06-07 Thread Linus Lüssing
The first patch is simply a cosmetic patch. So far I (and maybe others
too?) have been regularly confusing these two structs, therefore I'd
suggest renaming them and therefore making the follow-up patches easier
to understand and nicer to fit in.

The second patch fixes a minor issue, but probably not worth for stable.


On the other hand the first two patches are also preparations for the
third and fourth patch:

These two patches are exporting functionality needed to marry the bridge
multicast snooping with the batman-adv multicast optimizations recently
added for the 3.15 kernel, allowing to use these optimzations in common
setups having a bridge on top of e.g. bat0, too. So far these bridged
setups would fall back to simple flooding through the batman-adv mesh
network for any multicast packet entering bat0.

More information about the batman-adv multicast optimizations currently
implemented can be found here:

http://www.open-mesh.org/projects/batman-adv/wiki/Basic-multicast-optimizations

The integration on the batman-adv side could afterwards look like this,
for instance:

http://git.open-mesh.org/batman-adv.git/commitdiff/576b59dd3e34737c702e548b21fa72059262f796?hp=f95ce7131746c65fbcdffcf2089cab59e2c2f7ac


Changes in v4:
 - merged header postings from all previous patchset versions

Changes in v3:
 - use EXPORT_SYMBOL_GPL() instead of EXPORT_SYMBOL()

Changes in v2:
 - fix a nasty typo in PATCH 1/4, br_multicast_update_query_timer():
   "br->multicast_query_interval" vs. "br->multicast_querier_interval"
   => this accidentally reduced the other querier present timer 
  from 255 to 125 seconds
 - fix a typo in PATCH 2/4, br_ip{4,6}_multicast_query():
   ntohs(ETH_P_{IP,IPV6}) vs. htons(ETH_P_{IP,IPV6})
 - add missing ntohl()s before address comparison in PATCH 2/4,
   br_ip4_multicast_select_querier() (thanks David!)

Cheers, Linus

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCHv4 net-next 2/4] bridge: adhere to querier election mechanism specified by RFCs

2014-06-07 Thread Linus Lüssing
MLDv1 (RFC2710 section 6), MLDv2 (RFC3810 section 7.6.2), IGMPv2
(RFC2236 section 3) and IGMPv3 (RFC3376 section 6.6.2) specify that the
querier with lowest source address shall become the selected
querier.

So far the bridge stopped its querier as soon as it heard another
querier regardless of its source address. This results in the "wrong"
querier potentially becoming the active querier or a potential,
unnecessary querying delay.

With this patch the bridge memorizes the source address of the currently
selected querier and ignores queries from queriers with a higher source
address than the currently selected one. This slight optimization is
supposed to make it more RFC compliant (but is rather uncritical and
therefore probably not necessary to be queued for stable kernels).

Signed-off-by: Linus Lüssing 
---
 net/bridge/br_multicast.c |  101 +++--
 net/bridge/br_private.h   |7 
 2 files changed, 95 insertions(+), 13 deletions(-)

diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 5ccac62..b3f17c9 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -789,6 +789,18 @@ static void br_ip6_multicast_querier_expired(unsigned long 
data)
 }
 #endif
 
+static void br_multicast_select_own_querier(struct net_bridge *br,
+   struct br_ip *ip,
+   struct sk_buff *skb)
+{
+   if (ip->proto == htons(ETH_P_IP))
+   br->ip4_querier.addr.u.ip4 = ip_hdr(skb)->saddr;
+#if IS_ENABLED(CONFIG_IPV6)
+   else
+   br->ip6_querier.addr.u.ip6 = ipv6_hdr(skb)->saddr;
+#endif
+}
+
 static void __br_multicast_send_query(struct net_bridge *br,
  struct net_bridge_port *port,
  struct br_ip *ip)
@@ -804,8 +816,10 @@ static void __br_multicast_send_query(struct net_bridge 
*br,
skb->dev = port->dev;
NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
dev_queue_xmit);
-   } else
+   } else {
+   br_multicast_select_own_querier(br, ip, skb);
netif_rx(skb);
+   }
 }
 
 static void br_multicast_send_query(struct net_bridge *br,
@@ -1065,6 +1079,62 @@ static int br_ip6_multicast_mld2_report(struct 
net_bridge *br,
 }
 #endif
 
+static bool br_ip4_multicast_select_querier(struct net_bridge *br,
+   __be32 saddr)
+{
+   if (!timer_pending(&br->ip4_own_query.timer) &&
+   !timer_pending(&br->ip4_other_query.timer))
+   goto update;
+
+   if (!br->ip4_querier.addr.u.ip4)
+   goto update;
+
+   if (ntohl(saddr) <= ntohl(br->ip4_querier.addr.u.ip4))
+   goto update;
+
+   return false;
+
+update:
+   br->ip4_querier.addr.u.ip4 = saddr;
+
+   return true;
+}
+
+#if IS_ENABLED(CONFIG_IPV6)
+static bool br_ip6_multicast_select_querier(struct net_bridge *br,
+   struct in6_addr *saddr)
+{
+   if (!timer_pending(&br->ip6_own_query.timer) &&
+   !timer_pending(&br->ip6_other_query.timer))
+   goto update;
+
+   if (ipv6_addr_cmp(saddr, &br->ip6_querier.addr.u.ip6) <= 0)
+   goto update;
+
+   return false;
+
+update:
+   br->ip6_querier.addr.u.ip6 = *saddr;
+
+   return true;
+}
+#endif
+
+static bool br_multicast_select_querier(struct net_bridge *br,
+   struct br_ip *saddr)
+{
+   switch (saddr->proto) {
+   case htons(ETH_P_IP):
+   return br_ip4_multicast_select_querier(br, saddr->u.ip4);
+#if IS_ENABLED(CONFIG_IPV6)
+   case htons(ETH_P_IPV6):
+   return br_ip6_multicast_select_querier(br, &saddr->u.ip6);
+#endif
+   }
+
+   return false;
+}
+
 static void
 br_multicast_update_query_timer(struct net_bridge *br,
struct bridge_mcast_other_query *query,
@@ -1127,15 +1197,13 @@ timer:
 static void br_multicast_query_received(struct net_bridge *br,
struct net_bridge_port *port,
struct bridge_mcast_other_query *query,
-   int saddr,
-   bool is_general_query,
+   struct br_ip *saddr,
unsigned long max_delay)
 {
-   if (saddr && is_general_query)
-   br_multicast_update_query_timer(br, query, max_delay);
-   else if (timer_pending(&query->timer))
+   if (!br_multicast_select_querier(br, saddr))
return;
 
+   br_multicast_update_query_timer(br, query, max_delay);
br_

[PATCHv4 net-next 1/4] bridge: rename struct bridge_mcast_query/querier

2014-06-07 Thread Linus Lüssing
The current naming of these two structs is very random, in that
reversing their naming would not make any semantical difference.

This patch tries to make the naming less confusing by giving them a more
specific, distinguishable naming.

This is also useful for the upcoming patches reintroducing the
"struct bridge_mcast_querier" but for storing information about the
selected querier (no matter if our own or a foreign querier).

Signed-off-by: Linus Lüssing 
---
 net/bridge/br_mdb.c   |4 +-
 net/bridge/br_multicast.c |  169 +++--
 net/bridge/br_private.h   |   22 +++---
 3 files changed, 100 insertions(+), 95 deletions(-)

diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c
index b7b1914..5df0526 100644
--- a/net/bridge/br_mdb.c
+++ b/net/bridge/br_mdb.c
@@ -418,13 +418,13 @@ static int __br_mdb_del(struct net_bridge *br, struct 
br_mdb_entry *entry)
 
ip.proto = entry->addr.proto;
if (ip.proto == htons(ETH_P_IP)) {
-   if (timer_pending(&br->ip4_querier.timer))
+   if (timer_pending(&br->ip4_other_query.timer))
return -EBUSY;
 
ip.u.ip4 = entry->addr.u.ip4;
 #if IS_ENABLED(CONFIG_IPV6)
} else {
-   if (timer_pending(&br->ip6_querier.timer))
+   if (timer_pending(&br->ip6_other_query.timer))
return -EBUSY;
 
ip.u.ip6 = entry->addr.u.ip6;
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 7b757b5..5ccac62 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -35,7 +35,7 @@
 #include "br_private.h"
 
 static void br_multicast_start_querier(struct net_bridge *br,
-  struct bridge_mcast_query *query);
+  struct bridge_mcast_own_query *query);
 unsigned int br_mdb_rehash_seq;
 
 static inline int br_ip_equal(const struct br_ip *a, const struct br_ip *b)
@@ -761,7 +761,7 @@ static void br_multicast_local_router_expired(unsigned long 
data)
 }
 
 static void br_multicast_querier_expired(struct net_bridge *br,
-struct bridge_mcast_query *query)
+struct bridge_mcast_own_query *query)
 {
spin_lock(&br->multicast_lock);
if (!netif_running(br->dev) || br->multicast_disabled)
@@ -777,7 +777,7 @@ static void br_ip4_multicast_querier_expired(unsigned long 
data)
 {
struct net_bridge *br = (void *)data;
 
-   br_multicast_querier_expired(br, &br->ip4_query);
+   br_multicast_querier_expired(br, &br->ip4_own_query);
 }
 
 #if IS_ENABLED(CONFIG_IPV6)
@@ -785,7 +785,7 @@ static void br_ip6_multicast_querier_expired(unsigned long 
data)
 {
struct net_bridge *br = (void *)data;
 
-   br_multicast_querier_expired(br, &br->ip6_query);
+   br_multicast_querier_expired(br, &br->ip6_own_query);
 }
 #endif
 
@@ -810,11 +810,11 @@ static void __br_multicast_send_query(struct net_bridge 
*br,
 
 static void br_multicast_send_query(struct net_bridge *br,
struct net_bridge_port *port,
-   struct bridge_mcast_query *query)
+   struct bridge_mcast_own_query *own_query)
 {
unsigned long time;
struct br_ip br_group;
-   struct bridge_mcast_querier *querier = NULL;
+   struct bridge_mcast_other_query *other_query = NULL;
 
if (!netif_running(br->dev) || br->multicast_disabled ||
!br->multicast_querier)
@@ -822,31 +822,32 @@ static void br_multicast_send_query(struct net_bridge *br,
 
memset(&br_group.u, 0, sizeof(br_group.u));
 
-   if (port ? (query == &port->ip4_query) :
-  (query == &br->ip4_query)) {
-   querier = &br->ip4_querier;
+   if (port ? (own_query == &port->ip4_own_query) :
+  (own_query == &br->ip4_own_query)) {
+   other_query = &br->ip4_other_query;
br_group.proto = htons(ETH_P_IP);
 #if IS_ENABLED(CONFIG_IPV6)
} else {
-   querier = &br->ip6_querier;
+   other_query = &br->ip6_other_query;
br_group.proto = htons(ETH_P_IPV6);
 #endif
}
 
-   if (!querier || timer_pending(&querier->timer))
+   if (!other_query || timer_pending(&other_query->timer))
return;
 
__br_multicast_send_query(br, port, &br_group);
 
time = jiffies;
-   time += query->startup_sent < br->multicast_startup_query_count ?
+   time += own_query->startup_sent < br->multicast_startup_query_count ?
br->multicast_startup_query_interval :
  

[PATCHv4 net-next 4/4] bridge: memorize and export selected IGMP/MLD querier port

2014-06-07 Thread Linus Lüssing
Adding bridge support to the batman-adv multicast optimization requires
batman-adv knowing about the existence of bridged-in IGMP/MLD queriers
to be able to reliably serve any multicast listener behind this same
bridge.

Signed-off-by: Linus Lüssing 
---
 include/linux/if_bridge.h |1 +
 net/bridge/br_multicast.c |   72 +
 net/bridge/br_private.h   |1 +
 3 files changed, 68 insertions(+), 6 deletions(-)

diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index 44d6eb0..fd22789 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -38,5 +38,6 @@ typedef int br_should_route_hook_t(struct sk_buff *skb);
 extern br_should_route_hook_t __rcu *br_should_route_hook;
 int br_multicast_list_adjacent(struct net_device *dev,
   struct list_head *br_ip_list);
+bool br_multicast_has_querier_adjacent(struct net_device *dev, int proto);
 
 #endif
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 772476b..cd3cf39 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1081,6 +1081,7 @@ static int br_ip6_multicast_mld2_report(struct net_bridge 
*br,
 #endif
 
 static bool br_ip4_multicast_select_querier(struct net_bridge *br,
+   struct net_bridge_port *port,
__be32 saddr)
 {
if (!timer_pending(&br->ip4_own_query.timer) &&
@@ -1098,11 +1099,15 @@ static bool br_ip4_multicast_select_querier(struct 
net_bridge *br,
 update:
br->ip4_querier.addr.u.ip4 = saddr;
 
+   /* update protected by general multicast_lock by caller */
+   rcu_assign_pointer(br->ip4_querier.port, port);
+
return true;
 }
 
 #if IS_ENABLED(CONFIG_IPV6)
 static bool br_ip6_multicast_select_querier(struct net_bridge *br,
+   struct net_bridge_port *port,
struct in6_addr *saddr)
 {
if (!timer_pending(&br->ip6_own_query.timer) &&
@@ -1117,19 +1122,23 @@ static bool br_ip6_multicast_select_querier(struct 
net_bridge *br,
 update:
br->ip6_querier.addr.u.ip6 = *saddr;
 
+   /* update protected by general multicast_lock by caller */
+   rcu_assign_pointer(br->ip6_querier.port, port);
+
return true;
 }
 #endif
 
 static bool br_multicast_select_querier(struct net_bridge *br,
+   struct net_bridge_port *port,
struct br_ip *saddr)
 {
switch (saddr->proto) {
case htons(ETH_P_IP):
-   return br_ip4_multicast_select_querier(br, saddr->u.ip4);
+   return br_ip4_multicast_select_querier(br, port, saddr->u.ip4);
 #if IS_ENABLED(CONFIG_IPV6)
case htons(ETH_P_IPV6):
-   return br_ip6_multicast_select_querier(br, &saddr->u.ip6);
+   return br_ip6_multicast_select_querier(br, port, &saddr->u.ip6);
 #endif
}
 
@@ -1201,7 +1210,7 @@ static void br_multicast_query_received(struct net_bridge 
*br,
struct br_ip *saddr,
unsigned long max_delay)
 {
-   if (!br_multicast_select_querier(br, saddr))
+   if (!br_multicast_select_querier(br, port, saddr))
return;
 
br_multicast_update_query_timer(br, query, max_delay);
@@ -1804,12 +1813,14 @@ int br_multicast_rcv(struct net_bridge *br, struct 
net_bridge_port *port,
 }
 
 static void br_multicast_query_expired(struct net_bridge *br,
-  struct bridge_mcast_own_query *query)
+  struct bridge_mcast_own_query *query,
+  struct bridge_mcast_querier *querier)
 {
spin_lock(&br->multicast_lock);
if (query->startup_sent < br->multicast_startup_query_count)
query->startup_sent++;
 
+   rcu_assign_pointer(querier, NULL);
br_multicast_send_query(br, NULL, query);
spin_unlock(&br->multicast_lock);
 }
@@ -1818,7 +1829,7 @@ static void br_ip4_multicast_query_expired(unsigned long 
data)
 {
struct net_bridge *br = (void *)data;
 
-   br_multicast_query_expired(br, &br->ip4_own_query);
+   br_multicast_query_expired(br, &br->ip4_own_query, &br->ip4_querier);
 }
 
 #if IS_ENABLED(CONFIG_IPV6)
@@ -1826,7 +1837,7 @@ static void br_ip6_multicast_query_expired(unsigned long 
data)
 {
struct net_bridge *br = (void *)data;
 
-   br_multicast_query_expired(br, &br->ip6_own_query);
+   br_multicast_query_expired(br, &br->ip6_own_query, &br->ip6_querier);
 }
 #endif
 
@@ -1849,8 +1860,10 @@ void br_multicast_init(struct net_bridge *br)
br->multicast_membership_interva

[PATCHv4 net-next 3/4] bridge: add export of multicast database adjacent to net_dev

2014-06-07 Thread Linus Lüssing
With this new, exported function br_multicast_list_adjacent(net_dev) a
list of IPv4/6 addresses is returned. This list contains all multicast
addresses sensed by the bridge multicast snooping feature on all bridge
ports of the bridge interface of net_dev, excluding addresses from the
specified net_device itself.

Adding bridge support to the batman-adv multicast optimization requires
batman-adv knowing about the existence of bridged-in multicast
listeners to be able to reliably serve them with multicast packets.

Signed-off-by: Linus Lüssing 
---
 include/linux/if_bridge.h |   18 ++
 net/bridge/br_multicast.c |   58 +
 net/bridge/br_private.h   |   12 --
 3 files changed, 76 insertions(+), 12 deletions(-)

diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index 1085ffe..44d6eb0 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -16,9 +16,27 @@
 #include 
 #include 
 
+struct br_ip {
+   union {
+   __be32  ip4;
+#if IS_ENABLED(CONFIG_IPV6)
+   struct in6_addr ip6;
+#endif
+   } u;
+   __be16  proto;
+   __u16   vid;
+};
+
+struct br_ip_list {
+   struct list_head list;
+   struct br_ip addr;
+};
+
 extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void 
__user *));
 
 typedef int br_should_route_hook_t(struct sk_buff *skb);
 extern br_should_route_hook_t __rcu *br_should_route_hook;
+int br_multicast_list_adjacent(struct net_device *dev,
+  struct list_head *br_ip_list);
 
 #endif
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index b3f17c9..772476b 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -11,6 +11,7 @@
  */
 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -2141,3 +2142,60 @@ unlock:
 
return err;
 }
+
+/**
+ * br_multicast_list_adjacent - Returns snooped multicast addresses
+ * @dev:   The bridge port adjacent to which to retrieve addresses
+ * @br_ip_list:The list to store found, snooped multicast IP addresses 
in
+ *
+ * Creates a list of IP addresses (struct br_ip_list) sensed by the multicast
+ * snooping feature on all bridge ports of dev's bridge device, excluding
+ * the addresses from dev itself.
+ *
+ * Returns the number of items added to br_ip_list.
+ *
+ * Notes:
+ * - br_ip_list needs to be initialized by caller
+ * - br_ip_list might contain duplicates in the end
+ *   (needs to be taken care of by caller)
+ * - br_ip_list needs to be freed by caller
+ */
+int br_multicast_list_adjacent(struct net_device *dev,
+  struct list_head *br_ip_list)
+{
+   struct net_bridge *br;
+   struct net_bridge_port *port;
+   struct net_bridge_port_group *group;
+   struct br_ip_list *entry;
+   int count = 0;
+
+   rcu_read_lock();
+   if (!br_ip_list || !br_port_exists(dev))
+   goto unlock;
+
+   port = br_port_get_rcu(dev);
+   if (!port || !port->br)
+   goto unlock;
+
+   br = port->br;
+
+   list_for_each_entry_rcu(port, &br->port_list, list) {
+   if (!port->dev || port->dev == dev)
+   continue;
+
+   hlist_for_each_entry_rcu(group, &port->mglist, mglist) {
+   entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
+   if (!entry)
+   goto unlock;
+
+   entry->addr = group->addr;
+   list_add(&entry->list, br_ip_list);
+   count++;
+   }
+   }
+
+unlock:
+   rcu_read_unlock();
+   return count;
+}
+EXPORT_SYMBOL_GPL(br_multicast_list_adjacent);
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 97c5e46..50e2ab0 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -54,18 +54,6 @@ struct mac_addr
unsigned char   addr[ETH_ALEN];
 };
 
-struct br_ip
-{
-   union {
-   __be32  ip4;
-#if IS_ENABLED(CONFIG_IPV6)
-   struct in6_addr ip6;
-#endif
-   } u;
-   __be16  proto;
-   __u16   vid;
-};
-
 #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
 /* our own querier */
 struct bridge_mcast_own_query {
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


  1   2   >