batman-adv: Make MCAST capability changes atomic
Bitwise OR/AND assignments in C aren't guaranteed to be atomic. One
OGM handler might undo the set/clear of a specific bit from another
handler run in between.
Fix this by using the atomic set_bit()/clear_bit()/test_bit() functions.
Fixes: 60432d756c
("batman-adv: Announce new capability via multicast TVLV")
Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
Signed-off-by: Marek Lindner <mareklindner@neomailbox.ch>
Signed-off-by: Antonio Quartulli <antonio@meshcoding.com>
This commit is contained in:
parent
ac4eebd484
commit
9c936e3f4c
|
@ -19,6 +19,7 @@
|
|||
#include "main.h"
|
||||
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/byteorder/generic.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/etherdevice.h>
|
||||
|
@ -697,29 +698,30 @@ static void batadv_mcast_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv,
|
|||
uint8_t mcast_flags = BATADV_NO_FLAGS;
|
||||
bool orig_initialized;
|
||||
|
||||
orig_initialized = orig->capa_initialized & BATADV_ORIG_CAPA_HAS_MCAST;
|
||||
orig_initialized = test_bit(BATADV_ORIG_CAPA_HAS_MCAST,
|
||||
&orig->capa_initialized);
|
||||
|
||||
/* If mcast support is turned on decrease the disabled mcast node
|
||||
* counter only if we had increased it for this node before. If this
|
||||
* is a completely new orig_node no need to decrease the counter.
|
||||
*/
|
||||
if (orig_mcast_enabled &&
|
||||
!(orig->capabilities & BATADV_ORIG_CAPA_HAS_MCAST)) {
|
||||
!test_bit(BATADV_ORIG_CAPA_HAS_MCAST, &orig->capabilities)) {
|
||||
if (orig_initialized)
|
||||
atomic_dec(&bat_priv->mcast.num_disabled);
|
||||
orig->capabilities |= BATADV_ORIG_CAPA_HAS_MCAST;
|
||||
set_bit(BATADV_ORIG_CAPA_HAS_MCAST, &orig->capabilities);
|
||||
/* If mcast support is being switched off or if this is an initial
|
||||
* OGM without mcast support then increase the disabled mcast
|
||||
* node counter.
|
||||
*/
|
||||
} else if (!orig_mcast_enabled &&
|
||||
(orig->capabilities & BATADV_ORIG_CAPA_HAS_MCAST ||
|
||||
(test_bit(BATADV_ORIG_CAPA_HAS_MCAST, &orig->capabilities) ||
|
||||
!orig_initialized)) {
|
||||
atomic_inc(&bat_priv->mcast.num_disabled);
|
||||
orig->capabilities &= ~BATADV_ORIG_CAPA_HAS_MCAST;
|
||||
clear_bit(BATADV_ORIG_CAPA_HAS_MCAST, &orig->capabilities);
|
||||
}
|
||||
|
||||
orig->capa_initialized |= BATADV_ORIG_CAPA_HAS_MCAST;
|
||||
set_bit(BATADV_ORIG_CAPA_HAS_MCAST, &orig->capa_initialized);
|
||||
|
||||
if (orig_mcast_enabled && tvlv_value &&
|
||||
(tvlv_value_len >= sizeof(mcast_flags)))
|
||||
|
@ -763,8 +765,8 @@ void batadv_mcast_purge_orig(struct batadv_orig_node *orig)
|
|||
{
|
||||
struct batadv_priv *bat_priv = orig->bat_priv;
|
||||
|
||||
if (!(orig->capabilities & BATADV_ORIG_CAPA_HAS_MCAST) &&
|
||||
orig->capa_initialized & BATADV_ORIG_CAPA_HAS_MCAST)
|
||||
if (!test_bit(BATADV_ORIG_CAPA_HAS_MCAST, &orig->capabilities) &&
|
||||
test_bit(BATADV_ORIG_CAPA_HAS_MCAST, &orig->capa_initialized))
|
||||
atomic_dec(&bat_priv->mcast.num_disabled);
|
||||
|
||||
batadv_mcast_want_unsnoop_update(bat_priv, orig, BATADV_NO_FLAGS);
|
||||
|
|
|
@ -316,7 +316,7 @@ enum batadv_orig_capabilities {
|
|||
BATADV_ORIG_CAPA_HAS_DAT,
|
||||
BATADV_ORIG_CAPA_HAS_NC,
|
||||
BATADV_ORIG_CAPA_HAS_TT,
|
||||
BATADV_ORIG_CAPA_HAS_MCAST = BIT(3),
|
||||
BATADV_ORIG_CAPA_HAS_MCAST,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue