here I have a fix intended for net/linux-3.5.
The bug, discovered by Guido Iribarren and fixed by Simon Wunderlich, is caused by the wrong interaction between the Bridge Loop Avoidance and the Gateway feature of batman-adv.
Let me know if there are problems.
Thank you, Antonio
The following changes since commit 9e85a6f9dc231f3ed3c1dc1b12217505d970142a:
Merge tag 'clk-fixes-for-linus' of git://git.linaro.org/people/mturquette/linux (2012-07-03 18:06:49 -0700)
are available in the git repository at:
git://git.open-mesh.org/linux-merge.git tags/batman-adv-fix-for-davem
for you to fetch changes up to 2d3f6ccc4ea5c74d4b4af1b47c56b4cff4bbfcb7:
batman-adv: check incoming packet type for bla (2012-07-06 00:08:46 +0200)
---------------------------------------------------------------- Included changes: - fix a bug generated by the wrong interaction between the GW feature and the Bridge Loop Avoidance
---------------------------------------------------------------- Simon Wunderlich (1): batman-adv: check incoming packet type for bla
net/batman-adv/bridge_loop_avoidance.c | 15 +++++++++++---- net/batman-adv/bridge_loop_avoidance.h | 5 +++-- net/batman-adv/soft-interface.c | 6 +++++- 3 files changed, 19 insertions(+), 7 deletions(-)
From: Simon Wunderlich simon.wunderlich@s2003.tu-chemnitz.de
If the gateway functionality is used, some broadcast packets (DHCP requests) may be transmitted as unicast packets. As the bridge loop avoidance code now only considers the payload Ethernet destination, it may drop the DHCP request for clients which are claimed by other backbone gateways, because it falsely infers from the broadcast address that the right backbone gateway should havehandled the broadcast.
Fix this by checking and delegating the batman-adv packet type used for transmission.
Reported-by: Guido Iribarren guidoiribarren@buenosaireslibre.org Signed-off-by: Simon Wunderlich siwu@hrz.tu-chemnitz.de --- net/batman-adv/bridge_loop_avoidance.c | 15 +++++++++++---- net/batman-adv/bridge_loop_avoidance.h | 5 +++-- net/batman-adv/soft-interface.c | 6 +++++- 3 files changed, 19 insertions(+), 7 deletions(-)
diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c index 8bf9751..c5863f4 100644 --- a/net/batman-adv/bridge_loop_avoidance.c +++ b/net/batman-adv/bridge_loop_avoidance.c @@ -1351,6 +1351,7 @@ void bla_free(struct bat_priv *bat_priv) * @bat_priv: the bat priv with all the soft interface information * @skb: the frame to be checked * @vid: the VLAN ID of the frame + * @is_bcast: the packet came in a broadcast packet type. * * bla_rx avoidance checks if: * * we have to race for a claim @@ -1361,7 +1362,8 @@ void bla_free(struct bat_priv *bat_priv) * process the skb. * */ -int bla_rx(struct bat_priv *bat_priv, struct sk_buff *skb, short vid) +int bla_rx(struct bat_priv *bat_priv, struct sk_buff *skb, short vid, + bool is_bcast) { struct ethhdr *ethhdr; struct claim search_claim, *claim = NULL; @@ -1380,7 +1382,7 @@ int bla_rx(struct bat_priv *bat_priv, struct sk_buff *skb, short vid)
if (unlikely(atomic_read(&bat_priv->bla_num_requests))) /* don't allow broadcasts while requests are in flight */ - if (is_multicast_ether_addr(ethhdr->h_dest)) + if (is_multicast_ether_addr(ethhdr->h_dest) && is_bcast) goto handled;
memcpy(search_claim.addr, ethhdr->h_source, ETH_ALEN); @@ -1406,8 +1408,13 @@ int bla_rx(struct bat_priv *bat_priv, struct sk_buff *skb, short vid) }
/* if it is a broadcast ... */ - if (is_multicast_ether_addr(ethhdr->h_dest)) { - /* ... drop it. the responsible gateway is in charge. */ + if (is_multicast_ether_addr(ethhdr->h_dest) && is_bcast) { + /* ... drop it. the responsible gateway is in charge. + * + * We need to check is_bcast because with the gateway + * feature, broadcasts (like DHCP requests) may be sent + * using a unicast packet type. + */ goto handled; } else { /* seems the client considers us as its best gateway. diff --git a/net/batman-adv/bridge_loop_avoidance.h b/net/batman-adv/bridge_loop_avoidance.h index e39f93a..dc5227b 100644 --- a/net/batman-adv/bridge_loop_avoidance.h +++ b/net/batman-adv/bridge_loop_avoidance.h @@ -23,7 +23,8 @@ #define _NET_BATMAN_ADV_BLA_H_
#ifdef CONFIG_BATMAN_ADV_BLA -int bla_rx(struct bat_priv *bat_priv, struct sk_buff *skb, short vid); +int bla_rx(struct bat_priv *bat_priv, struct sk_buff *skb, short vid, + bool is_bcast); int bla_tx(struct bat_priv *bat_priv, struct sk_buff *skb, short vid); int bla_is_backbone_gw(struct sk_buff *skb, struct orig_node *orig_node, int hdr_size); @@ -41,7 +42,7 @@ void bla_free(struct bat_priv *bat_priv); #else /* ifdef CONFIG_BATMAN_ADV_BLA */
static inline int bla_rx(struct bat_priv *bat_priv, struct sk_buff *skb, - short vid) + short vid, bool is_bcast) { return 0; } diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index 6e2530b..a0ec0e4 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -256,7 +256,11 @@ void interface_rx(struct net_device *soft_iface, struct bat_priv *bat_priv = netdev_priv(soft_iface); struct ethhdr *ethhdr; struct vlan_ethhdr *vhdr; + struct batman_header *batadv_header = (struct batman_header *)skb->data; short vid __maybe_unused = -1; + bool is_bcast; + + is_bcast = (batadv_header->packet_type == BAT_BCAST);
/* check if enough space is available for pulling, and pull */ if (!pskb_may_pull(skb, hdr_size)) @@ -302,7 +306,7 @@ void interface_rx(struct net_device *soft_iface, /* Let the bridge loop avoidance check the packet. If will * not handle it, we can safely push it up. */ - if (bla_rx(bat_priv, skb, vid)) + if (bla_rx(bat_priv, skb, vid, is_bcast)) goto out;
netif_rx(skb);
On Fri, Jul 06, 2012 at 12:48:33 +0200, Antonio Quartulli wrote:
here I have a fix intended for net/linux-3.5.
...
Hello David,
here you have our instructions to resolve the conflicts that you will hit while merging net into net-next:
Conflict 1 (bridge_loop_avoidance.c): <<<<<<< int batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb, short vid) ======= int bla_rx(struct bat_priv *bat_priv, struct sk_buff *skb, short vid, bool is_bcast)
>
resolves to: int batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb, short vid, bool is_bcast)
Conflict 2 (bridge_loop_avoidance.h): <<<<<<< int batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb, short vid); int batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb, short vid); int batadv_bla_is_backbone_gw(struct sk_buff *skb, struct batadv_orig_node *orig_node, int hdr_size); int batadv_bla_claim_table_seq_print_text(struct seq_file *seq, void *offset); int batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, uint8_t *orig); int batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv, struct batadv_bcast_packet *bcast_packet, int hdr_size); void batadv_bla_update_orig_address(struct batadv_priv *bat_priv, struct batadv_hard_iface *primary_if, struct batadv_hard_iface *oldif); int batadv_bla_init(struct batadv_priv *bat_priv); void batadv_bla_free(struct batadv_priv *bat_priv); ======= int bla_rx(struct bat_priv *bat_priv, struct sk_buff *skb, short vid, bool is_bcast); int bla_tx(struct bat_priv *bat_priv, struct sk_buff *skb, short vid); int bla_is_backbone_gw(struct sk_buff *skb, struct orig_node *orig_node, int hdr_size); int bla_claim_table_seq_print_text(struct seq_file *seq, void *offset); int bla_is_backbone_gw_orig(struct bat_priv *bat_priv, uint8_t *orig); int bla_check_bcast_duplist(struct bat_priv *bat_priv, struct bcast_packet *bcast_packet, int hdr_size); void bla_update_orig_address(struct bat_priv *bat_priv, struct hard_iface *primary_if, struct hard_iface *oldif); int bla_init(struct bat_priv *bat_priv); void bla_free(struct bat_priv *bat_priv);
>
resolves to: int batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb, short vid, bool is_bcast); int batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb, short vid); int batadv_bla_is_backbone_gw(struct sk_buff *skb, struct batadv_orig_node *orig_node, int hdr_size); int batadv_bla_claim_table_seq_print_text(struct seq_file *seq, void *offset); int batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, uint8_t *orig); int batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv, struct batadv_bcast_packet *bcast_packet, int hdr_size); void batadv_bla_update_orig_address(struct batadv_priv *bat_priv, struct batadv_hard_iface *primary_if, struct batadv_hard_iface *oldif); int batadv_bla_init(struct batadv_priv *bat_priv); void batadv_bla_free(struct batadv_priv *bat_priv);
Conflict 3 (bridge_loop_avoidance.h): <<<<<<< static inline int batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb, short vid) ======= static inline int bla_rx(struct bat_priv *bat_priv, struct sk_buff *skb, short vid, bool is_bcast)
>
resolves to: static inline int batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb, short vid, bool is_bcast)
Conflict 4 (soft-interface.c): <<<<<<< __be16 ethertype = __constant_htons(BATADV_ETH_P_BATMAN); ======= bool is_bcast;
is_bcast = (batadv_header->packet_type == BAT_BCAST);
>
resolves to: bool is_bcast; __be16 ethertype = __constant_htons(BATADV_ETH_P_BATMAN);
is_bcast = (batadv_header->packet_type == BATADV_BCAST);
Conflict 5 (soft-interface.c): <<<<<<< if (batadv_bla_rx(bat_priv, skb, vid)) ======= if (bla_rx(bat_priv, skb, vid, is_bcast))
>
resolves to: if (batadv_bla_rx(bat_priv, skb, vid, is_bcast))
Wrong merge by git (soft-interface.c): line 270 must look like this: struct batadv_header *batadv_header = (struct batadv_header *)skb->data;
From: Antonio Quartulli ordex@autistici.org Date: Fri, 6 Jul 2012 00:51:40 +0200
here you have our instructions to resolve the conflicts that you will hit while merging net into net-next:
Thanks for this.
From: Antonio Quartulli ordex@autistici.org Date: Fri, 6 Jul 2012 00:48:33 +0200
git://git.open-mesh.org/linux-merge.git tags/batman-adv-fix-for-davem
Pulled, thanks.
b.a.t.m.a.n@lists.open-mesh.org