|
|
|
|
@ -26,8 +26,10 @@
|
|
|
|
|
#include <linux/jhash.h>
|
|
|
|
|
#include <linux/jiffies.h>
|
|
|
|
|
#include <linux/kref.h>
|
|
|
|
|
#include <linux/limits.h>
|
|
|
|
|
#include <linux/list.h>
|
|
|
|
|
#include <linux/lockdep.h>
|
|
|
|
|
#include <linux/minmax.h>
|
|
|
|
|
#include <linux/net.h>
|
|
|
|
|
#include <linux/netdevice.h>
|
|
|
|
|
#include <linux/netlink.h>
|
|
|
|
|
@ -253,7 +255,8 @@ static int batadv_tt_len(int changes_num)
|
|
|
|
|
*
|
|
|
|
|
* Return: local translation table size in bytes.
|
|
|
|
|
*/
|
|
|
|
|
static int batadv_tt_local_transmit_size(u16 num_vlan, u16 num_entries)
|
|
|
|
|
static int batadv_tt_local_transmit_size(unsigned int num_vlan,
|
|
|
|
|
unsigned int num_entries)
|
|
|
|
|
{
|
|
|
|
|
int hdr_size;
|
|
|
|
|
|
|
|
|
|
@ -266,6 +269,25 @@ static int batadv_tt_local_transmit_size(u16 num_vlan, u16 num_entries)
|
|
|
|
|
return hdr_size + batadv_tt_len(num_entries);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* batadv_tt_local_transmit_size_max() - get the maximum size of a full local table
|
|
|
|
|
* response
|
|
|
|
|
* @bat_priv: the bat priv with all the mesh interface information
|
|
|
|
|
*
|
|
|
|
|
* The full table response is sent as a single unicast TVLV packet. Its
|
|
|
|
|
* tvlv_len, which covers the TVLV header and the TT TVLV, is only 16 bit wide.
|
|
|
|
|
* This limits the response size even when packet_size_max is larger.
|
|
|
|
|
*
|
|
|
|
|
* Return: maximum size of a full local table response in bytes
|
|
|
|
|
*/
|
|
|
|
|
static int batadv_tt_local_transmit_size_max(struct batadv_priv *bat_priv)
|
|
|
|
|
{
|
|
|
|
|
int tvlv_size_max = sizeof(struct batadv_unicast_tvlv_packet) + U16_MAX;
|
|
|
|
|
int packet_size_max = READ_ONCE(bat_priv->packet_size_max);
|
|
|
|
|
|
|
|
|
|
return min(packet_size_max, tvlv_size_max);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* batadv_tt_local_reserve() - reserve room in the transmittable local table
|
|
|
|
|
* @bat_priv: the bat priv with all the mesh interface information
|
|
|
|
|
@ -290,22 +312,23 @@ static int batadv_tt_local_transmit_size(u16 num_vlan, u16 num_entries)
|
|
|
|
|
static bool batadv_tt_local_reserve(struct batadv_priv *bat_priv, u16 num_vlan,
|
|
|
|
|
u16 num_entries, int *table_size)
|
|
|
|
|
{
|
|
|
|
|
int packet_size_max = READ_ONCE(bat_priv->packet_size_max);
|
|
|
|
|
int size_max = batadv_tt_local_transmit_size_max(bat_priv);
|
|
|
|
|
unsigned int entries;
|
|
|
|
|
unsigned int vlans;
|
|
|
|
|
|
|
|
|
|
scoped_guard(spinlock_bh, &bat_priv->tt.reserve_lock) {
|
|
|
|
|
bat_priv->tt.reserved_vlans += num_vlan;
|
|
|
|
|
bat_priv->tt.reserved_entries += num_entries;
|
|
|
|
|
vlans = bat_priv->tt.reserved_vlans + num_vlan;
|
|
|
|
|
entries = bat_priv->tt.reserved_entries + num_entries;
|
|
|
|
|
|
|
|
|
|
*table_size = batadv_tt_local_transmit_size(bat_priv->tt.reserved_vlans,
|
|
|
|
|
bat_priv->tt.reserved_entries);
|
|
|
|
|
if (*table_size <= packet_size_max)
|
|
|
|
|
return true;
|
|
|
|
|
*table_size = batadv_tt_local_transmit_size(vlans, entries);
|
|
|
|
|
if (*table_size > size_max)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
bat_priv->tt.reserved_vlans -= num_vlan;
|
|
|
|
|
bat_priv->tt.reserved_entries -= num_entries;
|
|
|
|
|
bat_priv->tt.reserved_vlans = vlans;
|
|
|
|
|
bat_priv->tt.reserved_entries = entries;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@ -339,9 +362,10 @@ static bool batadv_tt_local_reserve_entry(struct batadv_priv *bat_priv,
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
net_ratelimited_function(batadv_info, bat_priv->mesh_iface,
|
|
|
|
|
"Local translation table size (%i) exceeds maximum packet size (%i); Ignoring new local tt entry: %pM\n",
|
|
|
|
|
"Local translation table size (%i) exceeds maximum table response size (%i); Ignoring new local tt entry: %pM\n",
|
|
|
|
|
table_size,
|
|
|
|
|
READ_ONCE(bat_priv->packet_size_max), addr);
|
|
|
|
|
batadv_tt_local_transmit_size_max(bat_priv),
|
|
|
|
|
addr);
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
@ -374,8 +398,9 @@ bool batadv_tt_local_reserve_vlan(struct batadv_priv *bat_priv,
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
net_ratelimited_function(batadv_info, bat_priv->mesh_iface,
|
|
|
|
|
"Local translation table size (%i) exceeds maximum packet size (%i); Ignoring new VLAN: %d\n",
|
|
|
|
|
table_size, READ_ONCE(bat_priv->packet_size_max),
|
|
|
|
|
"Local translation table size (%i) exceeds maximum table response size (%i); Ignoring new VLAN: %d\n",
|
|
|
|
|
table_size,
|
|
|
|
|
batadv_tt_local_transmit_size_max(bat_priv),
|
|
|
|
|
batadv_print_vid(vid));
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
@ -622,6 +647,9 @@ static u16 batadv_tt_flags_get(struct batadv_tt_common_entry *common)
|
|
|
|
|
* @bat_priv: the bat priv with all the mesh interface information
|
|
|
|
|
* @common: the TT entry involved in the event
|
|
|
|
|
* @flags: flags of the TT entry combined with the event flags
|
|
|
|
|
*
|
|
|
|
|
* Only a single change per client is queued. It describes the latest state of
|
|
|
|
|
* the client and a new event therefore replaces an already queued one.
|
|
|
|
|
*/
|
|
|
|
|
static void __batadv_tt_local_event(struct batadv_priv *bat_priv,
|
|
|
|
|
const struct batadv_tt_common_entry *common,
|
|
|
|
|
@ -631,7 +659,6 @@ static void __batadv_tt_local_event(struct batadv_priv *bat_priv,
|
|
|
|
|
struct batadv_tt_change_node *entry;
|
|
|
|
|
struct batadv_tt_change_node *safe;
|
|
|
|
|
bool del_op_requested;
|
|
|
|
|
bool del_op_entry;
|
|
|
|
|
size_t changes;
|
|
|
|
|
|
|
|
|
|
tt_change_node = kmem_cache_alloc(batadv_tt_change_cache, GFP_ATOMIC);
|
|
|
|
|
@ -643,9 +670,17 @@ static void __batadv_tt_local_event(struct batadv_priv *bat_priv,
|
|
|
|
|
ether_addr_copy(tt_change_node->change.addr, common->addr);
|
|
|
|
|
tt_change_node->change.vid = htons(common->vid);
|
|
|
|
|
|
|
|
|
|
tt_change_node->change.flags = flags;
|
|
|
|
|
del_op_requested = flags & BATADV_TT_CLIENT_DEL;
|
|
|
|
|
|
|
|
|
|
/* the ROAM flag is only meaningful for the receiver in combination
|
|
|
|
|
* with a DEL. An ADD with ROAM would be interpreted as a roaming
|
|
|
|
|
* advertisement
|
|
|
|
|
*/
|
|
|
|
|
if (!del_op_requested)
|
|
|
|
|
flags &= ~BATADV_TT_CLIENT_ROAM;
|
|
|
|
|
|
|
|
|
|
tt_change_node->change.flags = flags;
|
|
|
|
|
|
|
|
|
|
/* check for ADD+DEL, DEL+ADD, ADD+ADD or DEL+DEL events */
|
|
|
|
|
spin_lock_bh(&bat_priv->tt.changes_list_lock);
|
|
|
|
|
changes = READ_ONCE(bat_priv->tt.local_changes);
|
|
|
|
|
@ -657,25 +692,12 @@ static void __batadv_tt_local_event(struct batadv_priv *bat_priv,
|
|
|
|
|
if (entry->change.vid != tt_change_node->change.vid)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
del_op_entry = entry->change.flags & BATADV_TT_CLIENT_DEL;
|
|
|
|
|
if (del_op_requested != del_op_entry) {
|
|
|
|
|
/* DEL+ADD in the same orig interval have no effect and
|
|
|
|
|
* can be removed to avoid silly behaviour on the
|
|
|
|
|
* receiver side. The other way around (ADD+DEL) can
|
|
|
|
|
* happen in case of roaming of a client still in the
|
|
|
|
|
* NEW state. Roaming of NEW clients is now possible due
|
|
|
|
|
* to automatically recognition of "temporary" clients
|
|
|
|
|
*/
|
|
|
|
|
list_del(&entry->list);
|
|
|
|
|
kmem_cache_free(batadv_tt_change_cache, entry);
|
|
|
|
|
changes--;
|
|
|
|
|
} else {
|
|
|
|
|
/* this is a second add or del in the same originator
|
|
|
|
|
* interval. It could mean that flags have been changed
|
|
|
|
|
* (e.g. double add): update them
|
|
|
|
|
*/
|
|
|
|
|
entry->change.flags = flags;
|
|
|
|
|
}
|
|
|
|
|
/* the other nodes may know the client with different
|
|
|
|
|
* flags. A DEL+ADD must therefore still announce the
|
|
|
|
|
* current flags and an ADD+DEL must still remove the
|
|
|
|
|
* client. ADD+ADD and DEL+DEL only update the flags
|
|
|
|
|
*/
|
|
|
|
|
entry->change.flags = flags;
|
|
|
|
|
|
|
|
|
|
kmem_cache_free(batadv_tt_change_cache, tt_change_node);
|
|
|
|
|
goto update_changes;
|
|
|
|
|
@ -727,9 +749,9 @@ static u16 batadv_tt_entries(u16 tt_len)
|
|
|
|
|
*/
|
|
|
|
|
static int batadv_tt_local_table_transmit_size(struct batadv_priv *bat_priv)
|
|
|
|
|
{
|
|
|
|
|
unsigned int tt_local_entries = 0;
|
|
|
|
|
struct batadv_meshif_vlan *vlan;
|
|
|
|
|
u16 tt_local_entries = 0;
|
|
|
|
|
u16 num_vlan = 0;
|
|
|
|
|
unsigned int num_vlan = 0;
|
|
|
|
|
|
|
|
|
|
rcu_read_lock();
|
|
|
|
|
hlist_for_each_entry_rcu(vlan, &bat_priv->meshif_vlan_list, list) {
|
|
|
|
|
@ -811,14 +833,21 @@ static void batadv_tt_local_add_roam(struct batadv_priv *bat_priv,
|
|
|
|
|
if (!tt_global)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* Check whether it is a roaming, but don't do anything if the roaming
|
|
|
|
|
* process has already been handled
|
|
|
|
|
/* Handle newly roamed client - but not roamed back client.
|
|
|
|
|
*
|
|
|
|
|
* A client which roamed back must always be reclaimed from the
|
|
|
|
|
* originator(s) which sent the ROAMING_ADV. The global entry created by
|
|
|
|
|
* this ROAMING_ADV might still carry BATADV_TT_CLIENT_ROAM because the
|
|
|
|
|
* new originator did not yet announce the client.
|
|
|
|
|
*/
|
|
|
|
|
scoped_guard(spinlock_bh, &tt_global->common.flags_lock) {
|
|
|
|
|
if (tt_global->common.flags & BATADV_TT_CLIENT_ROAM)
|
|
|
|
|
return;
|
|
|
|
|
if (!roamed_back) {
|
|
|
|
|
scoped_guard(spinlock_bh, &tt_global->common.flags_lock) {
|
|
|
|
|
/* Check whether it is a roaming, but don't do anything
|
|
|
|
|
* if the roaming process has already been handled.
|
|
|
|
|
*/
|
|
|
|
|
if (tt_global->common.flags & BATADV_TT_CLIENT_ROAM)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (!roamed_back) {
|
|
|
|
|
/* The global entry has to be marked as ROAMING and has to be
|
|
|
|
|
* kept for consistency purpose.
|
|
|
|
|
*
|
|
|
|
|
@ -886,6 +915,7 @@ static bool batadv_tt_local_add_existing(struct batadv_priv *bat_priv,
|
|
|
|
|
bool *roamed_back)
|
|
|
|
|
{
|
|
|
|
|
struct batadv_tt_common_entry *common = &tt_local->common;
|
|
|
|
|
bool readded = false;
|
|
|
|
|
|
|
|
|
|
tt_local->last_seen = jiffies;
|
|
|
|
|
|
|
|
|
|
@ -900,8 +930,7 @@ static bool batadv_tt_local_add_existing(struct batadv_priv *bat_priv,
|
|
|
|
|
* flag can be reset like it was never enqueued
|
|
|
|
|
*/
|
|
|
|
|
common->flags &= ~BATADV_TT_CLIENT_PENDING;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
readded = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (common->flags & BATADV_TT_CLIENT_ROAM) {
|
|
|
|
|
@ -918,7 +947,7 @@ static bool batadv_tt_local_add_existing(struct batadv_priv *bat_priv,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
return readded;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@ -1319,22 +1348,24 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv,
|
|
|
|
|
* batadv_tt_tvlv_container_update() - update the translation table tvlv
|
|
|
|
|
* container after local tt changes have been committed
|
|
|
|
|
* @bat_priv: the bat priv with all the mesh interface information
|
|
|
|
|
* @changes_list: list of committed changes which will be consumed
|
|
|
|
|
* @tt_diff_entries_num: number of entries in @changes_list
|
|
|
|
|
*/
|
|
|
|
|
static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv)
|
|
|
|
|
static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv,
|
|
|
|
|
struct list_head *changes_list,
|
|
|
|
|
int tt_diff_entries_num)
|
|
|
|
|
{
|
|
|
|
|
struct batadv_tvlv_tt_change *tt_change;
|
|
|
|
|
struct batadv_tt_change_node *entry;
|
|
|
|
|
struct batadv_tvlv_tt_data *tt_data;
|
|
|
|
|
struct batadv_tt_change_node *safe;
|
|
|
|
|
int tt_diff_entries_count = 0;
|
|
|
|
|
int tt_diff_entries_num = 0;
|
|
|
|
|
bool drop_changes = false;
|
|
|
|
|
size_t tt_extra_len = 0;
|
|
|
|
|
int tt_change_len = 0;
|
|
|
|
|
int tt_diff_len;
|
|
|
|
|
u16 tvlv_len;
|
|
|
|
|
|
|
|
|
|
tt_diff_entries_num = READ_ONCE(bat_priv->tt.local_changes);
|
|
|
|
|
tt_diff_len = batadv_tt_len(tt_diff_entries_num);
|
|
|
|
|
|
|
|
|
|
/* if we have too many changes for one packet don't send any
|
|
|
|
|
@ -1352,19 +1383,39 @@ static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv)
|
|
|
|
|
|
|
|
|
|
tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, &tt_data,
|
|
|
|
|
&tt_change, &tt_diff_len);
|
|
|
|
|
if (!tvlv_len)
|
|
|
|
|
if (!tvlv_len) {
|
|
|
|
|
/* the changes are lost and the other nodes have to request the
|
|
|
|
|
* full table. Don't answer TT requests for the new TTVN with
|
|
|
|
|
* the stale changeset of the previous TTVN. Without changes, the
|
|
|
|
|
* TTVN was not incremented and the last changeset is still valid
|
|
|
|
|
*/
|
|
|
|
|
if (drop_changes || tt_diff_entries_num > 0) {
|
|
|
|
|
list_for_each_entry_safe(entry, safe, changes_list,
|
|
|
|
|
list) {
|
|
|
|
|
list_del(&entry->list);
|
|
|
|
|
kmem_cache_free(batadv_tt_change_cache, entry);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
spin_lock_bh(&bat_priv->tt.last_changeset_lock);
|
|
|
|
|
kfree(bat_priv->tt.last_changeset);
|
|
|
|
|
bat_priv->tt.last_changeset = NULL;
|
|
|
|
|
bat_priv->tt.last_changeset_len = 0;
|
|
|
|
|
spin_unlock_bh(&bat_priv->tt.last_changeset_lock);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* announce the already committed TTVN in the next OGM interval
|
|
|
|
|
* instead of waiting for BATADV_TT_OGM_APPEND_MAX idle rounds
|
|
|
|
|
*/
|
|
|
|
|
atomic_set(&bat_priv->tt.ogm_append_cnt, 0);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tt_data->flags = BATADV_TT_OGM_DIFF;
|
|
|
|
|
|
|
|
|
|
if (!drop_changes && tt_diff_len == 0)
|
|
|
|
|
goto container_register;
|
|
|
|
|
|
|
|
|
|
spin_lock_bh(&bat_priv->tt.changes_list_lock);
|
|
|
|
|
WRITE_ONCE(bat_priv->tt.local_changes, 0);
|
|
|
|
|
|
|
|
|
|
list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list,
|
|
|
|
|
list) {
|
|
|
|
|
list_for_each_entry_safe(entry, safe, changes_list, list) {
|
|
|
|
|
if (tt_diff_entries_count < tt_diff_entries_num) {
|
|
|
|
|
memcpy(tt_change + tt_diff_entries_count,
|
|
|
|
|
&entry->change,
|
|
|
|
|
@ -1374,7 +1425,6 @@ static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv)
|
|
|
|
|
list_del(&entry->list);
|
|
|
|
|
kmem_cache_free(batadv_tt_change_cache, entry);
|
|
|
|
|
}
|
|
|
|
|
spin_unlock_bh(&bat_priv->tt.changes_list_lock);
|
|
|
|
|
|
|
|
|
|
tt_extra_len = batadv_tt_len(tt_diff_entries_num -
|
|
|
|
|
tt_diff_entries_count);
|
|
|
|
|
@ -3342,8 +3392,12 @@ static bool batadv_tt_local_valid(void *entry_ptr,
|
|
|
|
|
if (tt_flags & BATADV_TT_CLIENT_NEW)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
/* the entry is (still) announced. A ROAM flag of an entry which is
|
|
|
|
|
* pending to be removed must not be transmitted. Otherwise, the
|
|
|
|
|
* receiver would handle it like a roaming advertisement
|
|
|
|
|
*/
|
|
|
|
|
if (flags)
|
|
|
|
|
*flags = tt_flags;
|
|
|
|
|
*flags = tt_flags & ~BATADV_TT_CLIENT_ROAM;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
@ -3922,21 +3976,30 @@ static void _batadv_tt_update_changes(struct batadv_priv *bat_priv,
|
|
|
|
|
u16 tt_num_changes, u8 ttvn)
|
|
|
|
|
{
|
|
|
|
|
int roams;
|
|
|
|
|
u8 flags;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < tt_num_changes; i++) {
|
|
|
|
|
if ((tt_change + i)->flags & BATADV_TT_CLIENT_DEL) {
|
|
|
|
|
roams = (tt_change + i)->flags & BATADV_TT_CLIENT_ROAM;
|
|
|
|
|
flags = (tt_change + i)->flags;
|
|
|
|
|
|
|
|
|
|
if (flags & BATADV_TT_CLIENT_DEL) {
|
|
|
|
|
roams = flags & BATADV_TT_CLIENT_ROAM;
|
|
|
|
|
batadv_tt_global_del(bat_priv, orig_node,
|
|
|
|
|
(tt_change + i)->addr,
|
|
|
|
|
ntohs((tt_change + i)->vid),
|
|
|
|
|
"tt removed by changes",
|
|
|
|
|
roams);
|
|
|
|
|
} else {
|
|
|
|
|
/* an announced client cannot have roamed away from
|
|
|
|
|
* orig_node. Only a ROAMING_ADV is allowed to add a
|
|
|
|
|
* global entry with the ROAM flag
|
|
|
|
|
*/
|
|
|
|
|
flags &= ~BATADV_TT_CLIENT_ROAM;
|
|
|
|
|
|
|
|
|
|
if (!batadv_tt_global_add(bat_priv, orig_node,
|
|
|
|
|
(tt_change + i)->addr,
|
|
|
|
|
ntohs((tt_change + i)->vid),
|
|
|
|
|
(tt_change + i)->flags, ttvn))
|
|
|
|
|
flags, ttvn))
|
|
|
|
|
/* In case of problem while storing a
|
|
|
|
|
* global_entry, we stop the updating
|
|
|
|
|
* procedure without committing the
|
|
|
|
|
@ -4412,11 +4475,25 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv)
|
|
|
|
|
*/
|
|
|
|
|
static void batadv_tt_local_commit_changes_nolock(struct batadv_priv *bat_priv)
|
|
|
|
|
{
|
|
|
|
|
LIST_HEAD(changes_list);
|
|
|
|
|
int changes_num;
|
|
|
|
|
|
|
|
|
|
lockdep_assert_held(&bat_priv->tt.commit_lock);
|
|
|
|
|
|
|
|
|
|
if (READ_ONCE(bat_priv->tt.local_changes) == 0) {
|
|
|
|
|
/* atomically get the list of changes. The TTVN decision and the
|
|
|
|
|
* announced changeset must cover the same events. Events queued
|
|
|
|
|
* afterwards stay in the tt.changes_list for the next TT round
|
|
|
|
|
*/
|
|
|
|
|
spin_lock_bh(&bat_priv->tt.changes_list_lock);
|
|
|
|
|
list_splice_init(&bat_priv->tt.changes_list, &changes_list);
|
|
|
|
|
changes_num = READ_ONCE(bat_priv->tt.local_changes);
|
|
|
|
|
WRITE_ONCE(bat_priv->tt.local_changes, 0);
|
|
|
|
|
spin_unlock_bh(&bat_priv->tt.changes_list_lock);
|
|
|
|
|
|
|
|
|
|
if (changes_num == 0) {
|
|
|
|
|
if (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt))
|
|
|
|
|
batadv_tt_tvlv_container_update(bat_priv);
|
|
|
|
|
batadv_tt_tvlv_container_update(bat_priv, &changes_list,
|
|
|
|
|
changes_num);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -4433,7 +4510,7 @@ static void batadv_tt_local_commit_changes_nolock(struct batadv_priv *bat_priv)
|
|
|
|
|
|
|
|
|
|
/* reset the sending counter */
|
|
|
|
|
atomic_set(&bat_priv->tt.ogm_append_cnt, BATADV_TT_OGM_APPEND_MAX);
|
|
|
|
|
batadv_tt_tvlv_container_update(bat_priv);
|
|
|
|
|
batadv_tt_tvlv_container_update(bat_priv, &changes_list, changes_num);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@ -4675,16 +4752,16 @@ void batadv_tt_local_resize_to_mtu(struct net_device *mesh_iface)
|
|
|
|
|
struct batadv_priv *bat_priv = netdev_priv(mesh_iface);
|
|
|
|
|
int timeout = BATADV_TT_LOCAL_TIMEOUT / 2;
|
|
|
|
|
bool reduced = false;
|
|
|
|
|
int packet_size_max;
|
|
|
|
|
int table_size;
|
|
|
|
|
int size_max;
|
|
|
|
|
|
|
|
|
|
packet_size_max = READ_ONCE(bat_priv->packet_size_max);
|
|
|
|
|
size_max = batadv_tt_local_transmit_size_max(bat_priv);
|
|
|
|
|
|
|
|
|
|
spin_lock_bh(&bat_priv->tt.commit_lock);
|
|
|
|
|
|
|
|
|
|
while (timeout) {
|
|
|
|
|
table_size = batadv_tt_local_table_transmit_size(bat_priv);
|
|
|
|
|
if (packet_size_max >= table_size)
|
|
|
|
|
if (size_max >= table_size)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
batadv_tt_local_purge(bat_priv, timeout);
|
|
|
|
|
@ -4693,8 +4770,8 @@ void batadv_tt_local_resize_to_mtu(struct net_device *mesh_iface)
|
|
|
|
|
timeout /= 2;
|
|
|
|
|
reduced = true;
|
|
|
|
|
net_ratelimited_function(batadv_info, mesh_iface,
|
|
|
|
|
"Forced to purge local tt entries to fit new maximum fragment MTU (%i)\n",
|
|
|
|
|
packet_size_max);
|
|
|
|
|
"Forced to purge local tt entries to fit new maximum table response size (%i)\n",
|
|
|
|
|
size_max);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* commit these changes immediately, to avoid synchronization problem
|
|
|
|
|
|