Commit 0ede9f41 authored by Marek Lindner's avatar Marek Lindner

batman-adv: protect bit operations to count OGMs with spinlock

Reported-by: default avatarLinus Lüssing <linus.luessing@saxnet.de>
Signed-off-by: default avatarMarek Lindner <lindner_marek@yahoo.de>
parent ed75ccbe
...@@ -155,7 +155,8 @@ static int is_bidirectional_neigh(struct orig_node *orig_node, ...@@ -155,7 +155,8 @@ static int is_bidirectional_neigh(struct orig_node *orig_node,
struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL; struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL;
struct hlist_node *node; struct hlist_node *node;
unsigned char total_count; unsigned char total_count;
int ret = 0; uint8_t orig_eq_count, neigh_rq_count, tq_own;
int tq_asym_penalty, ret = 0;
if (orig_node == orig_neigh_node) { if (orig_node == orig_neigh_node) {
rcu_read_lock(); rcu_read_lock();
...@@ -216,23 +217,25 @@ static int is_bidirectional_neigh(struct orig_node *orig_node, ...@@ -216,23 +217,25 @@ static int is_bidirectional_neigh(struct orig_node *orig_node,
orig_node->last_valid = jiffies; orig_node->last_valid = jiffies;
spin_lock_bh(&orig_node->ogm_cnt_lock);
orig_eq_count = orig_neigh_node->bcast_own_sum[if_incoming->if_num];
neigh_rq_count = neigh_node->real_packet_count;
spin_unlock_bh(&orig_node->ogm_cnt_lock);
/* pay attention to not get a value bigger than 100 % */ /* pay attention to not get a value bigger than 100 % */
total_count = (orig_neigh_node->bcast_own_sum[if_incoming->if_num] > total_count = (orig_eq_count > neigh_rq_count ?
neigh_node->real_packet_count ? neigh_rq_count : orig_eq_count);
neigh_node->real_packet_count :
orig_neigh_node->bcast_own_sum[if_incoming->if_num]);
/* if we have too few packets (too less data) we set tq_own to zero */ /* if we have too few packets (too less data) we set tq_own to zero */
/* if we receive too few packets it is not considered bidirectional */ /* if we receive too few packets it is not considered bidirectional */
if ((total_count < TQ_LOCAL_BIDRECT_SEND_MINIMUM) || if ((total_count < TQ_LOCAL_BIDRECT_SEND_MINIMUM) ||
(neigh_node->real_packet_count < TQ_LOCAL_BIDRECT_RECV_MINIMUM)) (neigh_rq_count < TQ_LOCAL_BIDRECT_RECV_MINIMUM))
orig_neigh_node->tq_own = 0; tq_own = 0;
else else
/* neigh_node->real_packet_count is never zero as we /* neigh_node->real_packet_count is never zero as we
* only purge old information when getting new * only purge old information when getting new
* information */ * information */
orig_neigh_node->tq_own = (TQ_MAX_VALUE * total_count) / tq_own = (TQ_MAX_VALUE * total_count) / neigh_rq_count;
neigh_node->real_packet_count;
/* /*
* 1 - ((1-x) ** 3), normalized to TQ_MAX_VALUE this does * 1 - ((1-x) ** 3), normalized to TQ_MAX_VALUE this does
...@@ -240,20 +243,16 @@ static int is_bidirectional_neigh(struct orig_node *orig_node, ...@@ -240,20 +243,16 @@ static int is_bidirectional_neigh(struct orig_node *orig_node,
* punishes asymmetric links more. This will give a value * punishes asymmetric links more. This will give a value
* between 0 and TQ_MAX_VALUE * between 0 and TQ_MAX_VALUE
*/ */
orig_neigh_node->tq_asym_penalty = tq_asym_penalty = TQ_MAX_VALUE - (TQ_MAX_VALUE *
TQ_MAX_VALUE - (TQ_LOCAL_WINDOW_SIZE - neigh_rq_count) *
(TQ_MAX_VALUE * (TQ_LOCAL_WINDOW_SIZE - neigh_rq_count) *
(TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count) * (TQ_LOCAL_WINDOW_SIZE - neigh_rq_count)) /
(TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count) * (TQ_LOCAL_WINDOW_SIZE *
(TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count)) / TQ_LOCAL_WINDOW_SIZE *
(TQ_LOCAL_WINDOW_SIZE * TQ_LOCAL_WINDOW_SIZE);
TQ_LOCAL_WINDOW_SIZE *
TQ_LOCAL_WINDOW_SIZE); batman_packet->tq = ((batman_packet->tq * tq_own * tq_asym_penalty) /
(TQ_MAX_VALUE * TQ_MAX_VALUE));
batman_packet->tq = ((batman_packet->tq *
orig_neigh_node->tq_own *
orig_neigh_node->tq_asym_penalty) /
(TQ_MAX_VALUE * TQ_MAX_VALUE));
bat_dbg(DBG_BATMAN, bat_priv, bat_dbg(DBG_BATMAN, bat_priv,
"bidirectional: " "bidirectional: "
...@@ -261,8 +260,7 @@ static int is_bidirectional_neigh(struct orig_node *orig_node, ...@@ -261,8 +260,7 @@ static int is_bidirectional_neigh(struct orig_node *orig_node,
"real recv = %2i, local tq: %3i, asym_penalty: %3i, " "real recv = %2i, local tq: %3i, asym_penalty: %3i, "
"total tq: %3i\n", "total tq: %3i\n",
orig_node->orig, orig_neigh_node->orig, total_count, orig_node->orig, orig_neigh_node->orig, total_count,
neigh_node->real_packet_count, orig_neigh_node->tq_own, neigh_rq_count, tq_own, tq_asym_penalty, batman_packet->tq);
orig_neigh_node->tq_asym_penalty, batman_packet->tq);
/* if link has the minimum required transmission quality /* if link has the minimum required transmission quality
* consider it bidirectional */ * consider it bidirectional */
...@@ -559,18 +557,19 @@ static char count_real_packets(struct ethhdr *ethhdr, ...@@ -559,18 +557,19 @@ static char count_real_packets(struct ethhdr *ethhdr,
char is_duplicate = 0; char is_duplicate = 0;
int32_t seq_diff; int32_t seq_diff;
int need_update = 0; int need_update = 0;
int set_mark; int set_mark, ret = -1;
orig_node = get_orig_node(bat_priv, batman_packet->orig); orig_node = get_orig_node(bat_priv, batman_packet->orig);
if (!orig_node) if (!orig_node)
return 0; return 0;
spin_lock_bh(&orig_node->ogm_cnt_lock);
seq_diff = batman_packet->seqno - orig_node->last_real_seqno; seq_diff = batman_packet->seqno - orig_node->last_real_seqno;
/* signalize caller that the packet is to be dropped. */ /* signalize caller that the packet is to be dropped. */
if (window_protected(bat_priv, seq_diff, if (window_protected(bat_priv, seq_diff,
&orig_node->batman_seqno_reset)) &orig_node->batman_seqno_reset))
goto err; goto out;
rcu_read_lock(); rcu_read_lock();
hlist_for_each_entry_rcu(tmp_neigh_node, node, hlist_for_each_entry_rcu(tmp_neigh_node, node,
...@@ -603,12 +602,12 @@ static char count_real_packets(struct ethhdr *ethhdr, ...@@ -603,12 +602,12 @@ static char count_real_packets(struct ethhdr *ethhdr,
orig_node->last_real_seqno = batman_packet->seqno; orig_node->last_real_seqno = batman_packet->seqno;
} }
kref_put(&orig_node->refcount, orig_node_free_ref); ret = is_duplicate;
return is_duplicate;
err: out:
spin_unlock_bh(&orig_node->ogm_cnt_lock);
kref_put(&orig_node->refcount, orig_node_free_ref); kref_put(&orig_node->refcount, orig_node_free_ref);
return -1; return ret;
} }
void receive_bat_packet(struct ethhdr *ethhdr, void receive_bat_packet(struct ethhdr *ethhdr,
......
...@@ -70,8 +70,6 @@ struct orig_node { ...@@ -70,8 +70,6 @@ struct orig_node {
struct neigh_node *router; struct neigh_node *router;
unsigned long *bcast_own; unsigned long *bcast_own;
uint8_t *bcast_own_sum; uint8_t *bcast_own_sum;
uint8_t tq_own;
int tq_asym_penalty;
unsigned long last_valid; unsigned long last_valid;
unsigned long bcast_seqno_reset; unsigned long bcast_seqno_reset;
unsigned long batman_seqno_reset; unsigned long batman_seqno_reset;
...@@ -89,7 +87,9 @@ struct orig_node { ...@@ -89,7 +87,9 @@ struct orig_node {
struct kref refcount; struct kref refcount;
struct bat_priv *bat_priv; struct bat_priv *bat_priv;
unsigned long last_frag_packet; unsigned long last_frag_packet;
spinlock_t ogm_cnt_lock; /* protects ogm counter */ spinlock_t ogm_cnt_lock; /* protects: bcast_own, bcast_own_sum,
* neigh_node->real_bits,
* neigh_node->real_packet_count */
atomic_t bond_candidates; atomic_t bond_candidates;
struct list_head bond_list; struct list_head bond_list;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment