Release 4.11 net/batman-adv/network-coding.c
/* Copyright (C) 2012-2017 B.A.T.M.A.N. contributors:
*
* Martin Hundebøll, Jeppe Ledet-Pedersen
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "network-coding.h"
#include "main.h"
#include <linux/atomic.h>
#include <linux/bitops.h>
#include <linux/byteorder/generic.h>
#include <linux/compiler.h>
#include <linux/debugfs.h>
#include <linux/errno.h>
#include <linux/etherdevice.h>
#include <linux/fs.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <linux/init.h>
#include <linux/jhash.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/kref.h>
#include <linux/list.h>
#include <linux/lockdep.h>
#include <linux/netdevice.h>
#include <linux/printk.h>
#include <linux/random.h>
#include <linux/rculist.h>
#include <linux/rcupdate.h>
#include <linux/seq_file.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/stddef.h>
#include <linux/string.h>
#include <linux/workqueue.h>
#include "hard-interface.h"
#include "hash.h"
#include "log.h"
#include "originator.h"
#include "packet.h"
#include "routing.h"
#include "send.h"
#include "tvlv.h"
static struct lock_class_key batadv_nc_coding_hash_lock_class_key;
static struct lock_class_key batadv_nc_decoding_hash_lock_class_key;
static void batadv_nc_worker(struct work_struct *work);
static int batadv_nc_recv_coded_packet(struct sk_buff *skb,
struct batadv_hard_iface *recv_if);
/**
* batadv_nc_init - one-time initialization for network coding
*
* Return: 0 on success or negative error number in case of failure
*/
int __init batadv_nc_init(void)
{
int ret;
/* Register our packet type */
ret = batadv_recv_handler_register(BATADV_CODED,
batadv_nc_recv_coded_packet);
return ret;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Matthias Schiffer | 24 | 100.00% | 1 | 100.00% |
Total | 24 | 100.00% | 1 | 100.00% |
/**
* batadv_nc_start_timer - initialise the nc periodic worker
* @bat_priv: the bat priv with all the soft interface information
*/
static void batadv_nc_start_timer(struct batadv_priv *bat_priv)
{
queue_delayed_work(batadv_event_workqueue, &bat_priv->nc.work,
msecs_to_jiffies(10));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin Hundeböll | 28 | 100.00% | 1 | 100.00% |
Total | 28 | 100.00% | 1 | 100.00% |
/**
* batadv_nc_tvlv_container_update - update the network coding tvlv container
* after network coding setting change
* @bat_priv: the bat priv with all the soft interface information
*/
static void batadv_nc_tvlv_container_update(struct batadv_priv *bat_priv)
{
char nc_mode;
nc_mode = atomic_read(&bat_priv->network_coding);
switch (nc_mode) {
case 0:
batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_NC, 1);
break;
case 1:
batadv_tvlv_container_register(bat_priv, BATADV_TVLV_NC, 1,
NULL, 0);
break;
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Marek Lindner | 60 | 100.00% | 1 | 100.00% |
Total | 60 | 100.00% | 1 | 100.00% |
/**
* batadv_nc_status_update - update the network coding tvlv container after
* network coding setting change
* @net_dev: the soft interface net device
*/
void batadv_nc_status_update(struct net_device *net_dev)
{
struct batadv_priv *bat_priv = netdev_priv(net_dev);
batadv_nc_tvlv_container_update(bat_priv);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Marek Lindner | 25 | 100.00% | 1 | 100.00% |
Total | 25 | 100.00% | 1 | 100.00% |
/**
* batadv_nc_tvlv_ogm_handler_v1 - process incoming nc tvlv container
* @bat_priv: the bat priv with all the soft interface information
* @orig: the orig_node of the ogm
* @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags)
* @tvlv_value: tvlv buffer containing the gateway data
* @tvlv_value_len: tvlv buffer length
*/
static void batadv_nc_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig,
u8 flags,
void *tvlv_value, u16 tvlv_value_len)
{
if (flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND)
clear_bit(BATADV_ORIG_CAPA_HAS_NC, &orig->capabilities);
else
set_bit(BATADV_ORIG_CAPA_HAS_NC, &orig->capabilities);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Marek Lindner | 39 | 73.58% | 1 | 33.33% |
Linus Lüssing | 12 | 22.64% | 1 | 33.33% |
Sven Eckelmann | 2 | 3.77% | 1 | 33.33% |
Total | 53 | 100.00% | 3 | 100.00% |
/**
* batadv_nc_mesh_init - initialise coding hash table and start house keeping
* @bat_priv: the bat priv with all the soft interface information
*
* Return: 0 on success or negative error number in case of failure
*/
int batadv_nc_mesh_init(struct batadv_priv *bat_priv)
{
bat_priv->nc.timestamp_fwd_flush = jiffies;
bat_priv->nc.timestamp_sniffed_purge = jiffies;
if (bat_priv->nc.coding_hash || bat_priv->nc.decoding_hash)
return 0;
bat_priv->nc.coding_hash = batadv_hash_new(128);
if (!bat_priv->nc.coding_hash)
goto err;
batadv_hash_set_lock_class(bat_priv->nc.coding_hash,
&batadv_nc_coding_hash_lock_class_key);
bat_priv->nc.decoding_hash = batadv_hash_new(128);
if (!bat_priv->nc.decoding_hash)
goto err;
batadv_hash_set_lock_class(bat_priv->nc.decoding_hash,
&batadv_nc_decoding_hash_lock_class_key);
INIT_DELAYED_WORK(&bat_priv->nc.work, batadv_nc_worker);
batadv_nc_start_timer(bat_priv);
batadv_tvlv_handler_register(bat_priv, batadv_nc_tvlv_ogm_handler_v1,
NULL, BATADV_TVLV_NC, 1,
BATADV_TVLV_HANDLER_OGM_CIFNOTFND);
batadv_nc_tvlv_container_update(bat_priv);
return 0;
err:
return -ENOMEM;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin Hundeböll | 138 | 86.79% | 4 | 66.67% |
Marek Lindner | 20 | 12.58% | 1 | 16.67% |
Matthias Schiffer | 1 | 0.63% | 1 | 16.67% |
Total | 159 | 100.00% | 6 | 100.00% |
/**
* batadv_nc_init_bat_priv - initialise the nc specific bat_priv variables
* @bat_priv: the bat priv with all the soft interface information
*/
void batadv_nc_init_bat_priv(struct batadv_priv *bat_priv)
{
atomic_set(&bat_priv->network_coding, 0);
bat_priv->nc.min_tq = 200;
bat_priv->nc.max_fwd_delay = 10;
bat_priv->nc.max_buffer_time = 200;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin Hundeböll | 43 | 97.73% | 4 | 80.00% |
Sven Eckelmann | 1 | 2.27% | 1 | 20.00% |
Total | 44 | 100.00% | 5 | 100.00% |
/**
* batadv_nc_init_orig - initialise the nc fields of an orig_node
* @orig_node: the orig_node which is going to be initialised
*/
void batadv_nc_init_orig(struct batadv_orig_node *orig_node)
{
INIT_LIST_HEAD(&orig_node->in_coding_list);
INIT_LIST_HEAD(&orig_node->out_coding_list);
spin_lock_init(&orig_node->in_coding_list_lock);
spin_lock_init(&orig_node->out_coding_list_lock);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin Hundeböll | 42 | 100.00% | 2 | 100.00% |
Total | 42 | 100.00% | 2 | 100.00% |
/**
* batadv_nc_node_release - release nc_node from lists and queue for free after
* rcu grace period
* @ref: kref pointer of the nc_node
*/
static void batadv_nc_node_release(struct kref *ref)
{
struct batadv_nc_node *nc_node;
nc_node = container_of(ref, struct batadv_nc_node, refcount);
batadv_orig_node_put(nc_node->orig_node);
kfree_rcu(nc_node, rcu);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Sven Eckelmann | 26 | 61.90% | 3 | 60.00% |
Martin Hundeböll | 16 | 38.10% | 2 | 40.00% |
Total | 42 | 100.00% | 5 | 100.00% |
/**
* batadv_nc_node_put - decrement the nc_node refcounter and possibly
* release it
* @nc_node: nc_node to be free'd
*/
static void batadv_nc_node_put(struct batadv_nc_node *nc_node)
{
kref_put(&nc_node->refcount, batadv_nc_node_release);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin Hundeböll | 17 | 80.95% | 2 | 40.00% |
Sven Eckelmann | 4 | 19.05% | 3 | 60.00% |
Total | 21 | 100.00% | 5 | 100.00% |
/**
* batadv_nc_path_release - release nc_path from lists and queue for free after
* rcu grace period
* @ref: kref pointer of the nc_path
*/
static void batadv_nc_path_release(struct kref *ref)
{
struct batadv_nc_path *nc_path;
nc_path = container_of(ref, struct batadv_nc_path, refcount);
kfree_rcu(nc_path, rcu);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Sven Eckelmann | 35 | 100.00% | 1 | 100.00% |
Total | 35 | 100.00% | 1 | 100.00% |
/**
* batadv_nc_path_put - decrement the nc_path refcounter and possibly
* release it
* @nc_path: nc_path to be free'd
*/
static void batadv_nc_path_put(struct batadv_nc_path *nc_path)
{
kref_put(&nc_path->refcount, batadv_nc_path_release);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin Hundeböll | 18 | 85.71% | 1 | 33.33% |
Sven Eckelmann | 3 | 14.29% | 2 | 66.67% |
Total | 21 | 100.00% | 3 | 100.00% |
/**
* batadv_nc_packet_free - frees nc packet
* @nc_packet: the nc packet to free
* @dropped: whether the packet is freed because is is dropped
*/
static void batadv_nc_packet_free(struct batadv_nc_packet *nc_packet,
bool dropped)
{
if (dropped)
kfree_skb(nc_packet->skb);
else
consume_skb(nc_packet->skb);
batadv_nc_path_put(nc_packet->nc_path);
kfree(nc_packet);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin Hundeböll | 29 | 64.44% | 1 | 33.33% |
Sven Eckelmann | 16 | 35.56% | 2 | 66.67% |
Total | 45 | 100.00% | 3 | 100.00% |
/**
* batadv_nc_to_purge_nc_node - checks whether an nc node has to be purged
* @bat_priv: the bat priv with all the soft interface information
* @nc_node: the nc node to check
*
* Return: true if the entry has to be purged now, false otherwise
*/
static bool batadv_nc_to_purge_nc_node(struct batadv_priv *bat_priv,
struct batadv_nc_node *nc_node)
{
if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
return true;
return batadv_has_timed_out(nc_node->last_seen, BATADV_NC_NODE_TIMEOUT);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin Hundeböll | 41 | 100.00% | 2 | 100.00% |
Total | 41 | 100.00% | 2 | 100.00% |
/**
* batadv_nc_to_purge_nc_path_coding - checks whether an nc path has timed out
* @bat_priv: the bat priv with all the soft interface information
* @nc_path: the nc path to check
*
* Return: true if the entry has to be purged now, false otherwise
*/
static bool batadv_nc_to_purge_nc_path_coding(struct batadv_priv *bat_priv,
struct batadv_nc_path *nc_path)
{
if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
return true;
/* purge the path when no packets has been added for 10 times the
* max_fwd_delay time
*/
return batadv_has_timed_out(nc_path->last_valid,
bat_priv->nc.max_fwd_delay * 10);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin Hundeböll | 48 | 100.00% | 1 | 100.00% |
Total | 48 | 100.00% | 1 | 100.00% |
/**
* batadv_nc_to_purge_nc_path_decoding - checks whether an nc path has timed out
* @bat_priv: the bat priv with all the soft interface information
* @nc_path: the nc path to check
*
* Return: true if the entry has to be purged now, false otherwise
*/
static bool batadv_nc_to_purge_nc_path_decoding(struct batadv_priv *bat_priv,
struct batadv_nc_path *nc_path)
{
if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
return true;
/* purge the path when no packets has been added for 10 times the
* max_buffer time
*/
return batadv_has_timed_out(nc_path->last_valid,
bat_priv->nc.max_buffer_time * 10);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin Hundeböll | 48 | 100.00% | 1 | 100.00% |
Total | 48 | 100.00% | 1 | 100.00% |
/**
* batadv_nc_purge_orig_nc_nodes - go through list of nc nodes and purge stale
* entries
* @bat_priv: the bat priv with all the soft interface information
* @list: list of nc nodes
* @lock: nc node list lock
* @to_purge: function in charge to decide whether an entry has to be purged or
* not. This function takes the nc node as argument and has to return
* a boolean value: true if the entry has to be deleted, false
* otherwise
*/
static void
batadv_nc_purge_orig_nc_nodes(struct batadv_priv *bat_priv,
struct list_head *list,
spinlock_t *lock,
bool (*to_purge)(struct batadv_priv *,
struct batadv_nc_node *))
{
struct batadv_nc_node *nc_node, *nc_node_tmp;
/* For each nc_node in list */
spin_lock_bh(lock);
list_for_each_entry_safe(nc_node, nc_node_tmp, list, list) {
/* if an helper function has been passed as parameter,
* ask it if the entry has to be purged or not
*/
if (to_purge && !to_purge(bat_priv, nc_node))
continue;
batadv_dbg(BATADV_DBG_NC, bat_priv,
"Removing nc_node %pM -> %pM\n",
nc_node->addr, nc_node->orig_node->orig);
list_del_rcu(&nc_node->list);
batadv_nc_node_put(nc_node);
}
spin_unlock_bh(lock);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin Hundeböll | 111 | 99.11% | 2 | 66.67% |
Sven Eckelmann | 1 | 0.89% | 1 | 33.33% |
Total | 112 | 100.00% | 3 | 100.00% |
/**
* batadv_nc_purge_orig - purges all nc node data attached of the given
* originator
* @bat_priv: the bat priv with all the soft interface information
* @orig_node: orig_node with the nc node entries to be purged
* @to_purge: function in charge to decide whether an entry has to be purged or
* not. This function takes the nc node as argument and has to return
* a boolean value: true is the entry has to be deleted, false
* otherwise
*/
void batadv_nc_purge_orig(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node,
bool (*to_purge)(struct batadv_priv *,
struct batadv_nc_node *))
{
/* Check ingoing nc_node's of this orig_node */
batadv_nc_purge_orig_nc_nodes(bat_priv, &orig_node->in_coding_list,
&orig_node->in_coding_list_lock,
to_purge);
/* Check outgoing nc_node's of this orig_node */
batadv_nc_purge_orig_nc_nodes(bat_priv, &orig_node->out_coding_list,
&orig_node->out_coding_list_lock,
to_purge);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin Hundeböll | 66 | 100.00% | 2 | 100.00% |
Total | 66 | 100.00% | 2 | 100.00% |
/**
* batadv_nc_purge_orig_hash - traverse entire originator hash to check if they
* have timed out nc nodes
* @bat_priv: the bat priv with all the soft interface information
*/
static void batadv_nc_purge_orig_hash(struct batadv_priv *bat_priv)
{
struct batadv_hashtable *hash = bat_priv->orig_hash;
struct hlist_head *head;
struct batadv_orig_node *orig_node;
u32 i;
if (!hash)
return;
/* For each orig_node */
for (i = 0; i < hash->size; i++) {
head = &hash->table[i];
rcu_read_lock();
hlist_for_each_entry_rcu(orig_node, head, hash_entry)
batadv_nc_purge_orig(bat_priv, orig_node,
batadv_nc_to_purge_nc_node);
rcu_read_unlock();
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin Hundeböll | 89 | 98.89% | 1 | 50.00% |
Sven Eckelmann | 1 | 1.11% | 1 | 50.00% |
Total | 90 | 100.00% | 2 | 100.00% |
/**
* batadv_nc_purge_paths - traverse all nc paths part of the hash and remove
* unused ones
* @bat_priv: the bat priv with all the soft interface information
* @hash: hash table containing the nc paths to check
* @to_purge: function in charge to decide whether an entry has to be purged or
* not. This function takes the nc node as argument and has to return
* a boolean value: true is the entry has to be deleted, false
* otherwise
*/
static void batadv_nc_purge_paths(struct batadv_priv *bat_priv,
struct batadv_hashtable *hash,
bool (*to_purge)(struct batadv_priv *,
struct batadv_nc_path *))
{
struct hlist_head *head;
struct hlist_node *node_tmp;
struct batadv_nc_path *nc_path;
spinlock_t *lock; /* Protects lists in hash */
u32 i;
for (i = 0; i < hash->size; i++) {
head = &hash->table[i];
lock = &hash->list_locks[i];
/* For each nc_path in this bin */
spin_lock_bh(lock);
hlist_for_each_entry_safe(nc_path, node_tmp, head, hash_entry) {
/* if an helper function has been passed as parameter,
* ask it if the entry has to be purged or not
*/
if (to_purge && !to_purge(bat_priv, nc_path))
continue;
/* purging an non-empty nc_path should never happen, but
* is observed under high CPU load. Delay the purging
* until next iteration to allow the packet_list to be
* emptied first.
*/
if (!unlikely(list_empty(&nc_path->packet_list))) {
net_ratelimited_function(printk,
KERN_WARNING
"Skipping free of non-empty nc_path (%pM -> %pM)!\n",
nc_path->prev_hop,
nc_path->next_hop);
continue;
}
/* nc_path is unused, so remove it */
batadv_dbg(BATADV_DBG_NC, bat_priv,
"Remove nc_path %pM -> %pM\n",
nc_path->prev_hop, nc_path->next_hop);
hlist_del_rcu(&nc_path->hash_entry);
batadv_nc_path_put(nc_path);
}
spin_unlock_bh(lock);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin Hundeböll | 191 | 98.96% | 2 | 50.00% |
Sven Eckelmann | 2 | 1.04% | 2 | 50.00% |
Total | 193 | 100.00% | 4 | 100.00% |
/**
* batadv_nc_hash_key_gen - computes the nc_path hash key
* @key: buffer to hold the final hash key
* @src: source ethernet mac address going into the hash key
* @dst: destination ethernet mac address going into the hash key
*/
static void batadv_nc_hash_key_gen(struct batadv_nc_path *key, const char *src,
const char *dst)
{
memcpy(key->prev_hop, src, sizeof(key->prev_hop));
memcpy(key->next_hop, dst, sizeof(key->next_hop));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin Hundeböll | 53 | 100.00% | 2 | 100.00% |
Total | 53 | 100.00% | 2 | 100.00% |
/**
* batadv_nc_hash_choose - compute the hash value for an nc path
* @data: data to hash
* @size: size of the hash table
*
* Return: the selected index in the hash table for the given data.
*/
static u32 batadv_nc_hash_choose(const void *data, u32 size)
{
const struct batadv_nc_path *nc_path = data;
u32 hash = 0;
hash = jhash(&nc_path->prev_hop, sizeof(nc_path->prev_hop), hash);
hash = jhash(&nc_path->next_hop, sizeof(nc_path->next_hop), hash);
return hash % size;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin Hundeböll | 61 | 87.14% | 2 | 50.00% |
Sven Eckelmann | 9 | 12.86% | 2 | 50.00% |
Total | 70 | 100.00% | 4 | 100.00% |
/**
* batadv_nc_hash_compare - comparing function used in the network coding hash
* tables
* @node: node in the local table
* @data2: second object to compare the node to
*
* Return: true if the two entry are the same, false otherwise
*/
static bool batadv_nc_hash_compare(const struct hlist_node *node,
const void *data2)
{
const struct batadv_nc_path *nc_path1, *nc_path2;
nc_path1 = container_of(node, struct batadv_nc_path, hash_entry);
nc_path2 = data2;
/* Return 1 if the two keys are identical */
if (!batadv_compare_eth(nc_path1->prev_hop, nc_path2->prev_hop))
return false;
if (!batadv_compare_eth(nc_path1->next_hop, nc_path2->next_hop))
return false;
return true;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin Hundeböll | 72 | 90.00% | 2 | 50.00% |
Sven Eckelmann | 4 | 5.00% | 1 | 25.00% |
Antonio Quartulli | 4 | 5.00% | 1 | 25.00% |
Total | 80 | 100.00% | 4 | 100.00% |
/**
* batadv_nc_hash_find - search for an existing nc path and return it
* @hash: hash table containing the nc path
* @data: search key
*
* Return: the nc_path if found, NULL otherwise.
*/
static struct batadv_nc_path *
batadv_nc_hash_find(struct batadv_hashtable *hash,
void *data)
{
struct hlist_head *head;
struct batadv_nc_path *nc_path, *nc_path_tmp = NULL;
int index;
if (!hash)
return NULL;
index = batadv_nc_hash_choose(data, hash->size);
head = &hash->table[index];
rcu_read_lock();
hlist_for_each_entry_rcu(nc_path, head, hash_entry) {
if (!batadv_nc_hash_compare(&nc_path->hash_entry, data))
continue;
if (!kref_get_unless_zero(&nc_path->refcount))
continue;
nc_path_tmp = nc_path;
break;
}
rcu_read_unlock();
return nc_path_tmp;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin Hundeböll | 113 | 99.12% | 2 | 66.67% |
Sven Eckelmann | 1 | 0.88% | 1 | 33.33% |
Total | 114 | 100.00% | 3 | 100.00% |
/**
* batadv_nc_send_packet - send non-coded packet and free nc_packet struct
* @nc_packet: the nc packet to send
*/
static void batadv_nc_send_packet(struct batadv_nc_packet *nc_packet)
{
batadv_send_unicast_skb(nc_packet->skb, nc_packet->neigh_node);
nc_packet->skb = NULL;
batadv_nc_packet_free(nc_packet, false);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin Hundeböll | 32 | 91.43% | 1 | 33.33% |
Sven Eckelmann | 2 | 5.71% | 1 | 33.33% |
Antonio Quartulli | 1 | 2.86% | 1 | 33.33% |
Total | 35 | 100.00% | 3 | 100.00% |
/**
* batadv_nc_sniffed_purge - Checks timestamp of given sniffed nc_packet.
* @bat_priv: the bat priv with all the soft interface information
* @nc_path: the nc path the packet belongs to
* @nc_packet: the nc packet to be checked
*
* Checks whether the given sniffed (overheard) nc_packet has hit its buffering
* timeout. If so, the packet is no longer kept and the entry deleted from the
* queue. Has to be called with the appropriate locks.
*
* Return: false as soon as the entry in the fifo queue has not been timed out
* yet and true otherwise.
*/
static bool batadv_nc_sniffed_purge(struct batadv_priv *bat_priv,
struct batadv_nc_path *nc_path,
struct batadv_nc_packet *nc_packet)
{
unsigned long timeout = bat_priv->nc.max_buffer_time;
bool res = false;
lockdep_assert_held(&nc_path->packet_list_lock);
/* Packets are added to tail, so the remaining packets did not time
* out and we can stop processing the current queue
*/
if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_ACTIVE &&
!batadv_has_timed_out(nc_packet->timestamp, timeout))
goto out;
/* purge nc packet */
list_del(&nc_packet->list);
batadv_nc_packet_free(nc_packet, true);
res = true;
out:
return res;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin Hundeböll | 85 | 89.47% | 1 | 33.33% |
Sven Eckelmann | 10 | 10.53% | 2 | 66.67% |
Total | 95 | 100.00% | 3 | 100.00% |
/**
* batadv_nc_fwd_flush - Checks the timestamp of the given nc packet.
* @bat_priv: the bat priv with all the soft interface information
* @nc_path: the nc path the packet belongs to
* @nc_packet: the nc packet to be checked
*
* Checks whether the given nc packet has hit its forward timeout. If so, the
* packet is no longer delayed, immediately sent and the entry deleted from the
* queue. Has to be called with the appropriate locks.
*
* Return: false as soon as the entry in the fifo queue has not been timed out
* yet and true otherwise.
*/
static bool batadv_nc_fwd_flush(struct batadv_priv *bat_priv,
struct batadv_nc_path *nc_path,
struct batadv_nc_packet *nc_packet)
{
unsigned long timeout = bat_priv->nc.max_fwd_delay;
lockdep_assert_held(&nc_path->packet_list_lock);
/* Packets are added to tail, so the remaining packets did not time
* out and we can stop processing the current queue
*/
if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_ACTIVE &&
!batadv_has_timed_out(nc_packet->timestamp, timeout))
return false;
/* Send packet */
batadv_inc_counter(bat_priv, BATADV_CNT_FORWARD);
batadv_add_counter(bat_priv, BATADV_CNT_FORWARD_BYTES,
nc_packet->skb->len + ETH_HLEN);
list_del(&nc_packet->list);
batadv_nc_send_packet(nc_packet);
return true;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin Hundeböll | 96 | 92.31% | 1 | 50.00% |
Sven Eckelmann | 8 | 7.69% | 1 | 50.00% |
Total | 104 | 100.00% | 2 | 100.00% |
/**
* batadv_nc_process_nc_paths - traverse given nc packet pool and free timed out
* nc packets
* @bat_priv: the bat priv with all the soft interface information
* @hash: to be processed hash table
* @process_fn: Function called to process given nc packet. Should return true
* to encourage this function to proceed with the next packet.
* Otherwise the rest of the current queue is skipped.
*/
static void
batadv_nc_process_nc_paths(struct batadv_priv *bat_priv,
struct batadv_hashtable *hash,
bool (*process_fn)(struct batadv_priv *,
struct batadv_nc_path *,
struct batadv_nc_packet *))
{
struct hlist_head *head;
struct batadv_nc_packet *nc_packet, *nc_packet_tmp;
struct batadv_nc_path *nc_path;
bool ret;
int i;
if (!hash)
return;
/* Loop hash table bins */
for (i = 0; i < hash->size; i++) {
head = &hash->table[i];
/* Loop coding paths */
rcu_read_lock();
hlist_for_each_entry_rcu(nc_path, head, hash_entry) {
/* Loop packets */
spin_lock_bh(&nc_path->packet_list_lock);
list_for_each_entry_safe(nc_packet, nc_packet_tmp,
&nc_path->packet_list, list) {
ret = process_fn(bat_priv, nc_path, nc_packet);
if (!ret)
break;
}
spin_unlock_bh(&nc_path->packet_list_lock);
}
rcu_read_unlock();
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin Hundeböll | 156 | 100.00% | 1 | 100.00% |
Total | 156 | 100.00% | 1 | 100.00% |
/**
* batadv_nc_worker - periodic task for house keeping related to network coding
* @work: kernel work struct
*/
static void batadv_nc_worker(struct work_struct *work)
{
struct delayed_work *delayed_work;
struct batadv_priv_nc *priv_nc;
struct batadv_priv *bat_priv;
unsigned long timeout;
delayed_work = to_delayed_work(work);
priv_nc = container_of(delayed_work, struct batadv_priv_nc, work);
bat_priv = container_of(priv_nc, struct batadv_priv, nc);
batadv_nc_purge_orig_hash(bat_priv);
batadv_nc_purge_paths(bat_priv, bat_priv->nc.coding_hash,
batadv_nc_to_purge_nc_path_coding);
batadv_nc_purge_paths(bat_priv, bat_priv->nc.decoding_hash,
batadv_nc_to_purge_nc_path_decoding);
timeout = bat_priv->nc.max_fwd_delay;
if (batadv_has_timed_out(bat_priv->nc.timestamp_fwd_flush, timeout)) {
batadv_nc_process_nc_paths(bat_priv, bat_priv->nc.coding_hash,
batadv_nc_fwd_flush);
bat_priv->nc.timestamp_fwd_flush = jiffies;
}
if (batadv_has_timed_out(bat_priv->nc.timestamp_sniffed_purge,
bat_priv->nc.max_buffer_time)) {
batadv_nc_process_nc_paths(bat_priv, bat_priv->nc.decoding_hash,
batadv_nc_sniffed_purge);
bat_priv->nc.timestamp_sniffed_purge = jiffies;
}
/* Schedule a new check */
batadv_nc_start_timer(bat_priv);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin Hundeböll | 181 | 99.45% | 2 | 66.67% |
Geliang Tang | 1 | 0.55% | 1 | 33.33% |
Total | 182 | 100.00% | 3 | 100.00% |
/**
* batadv_can_nc_with_orig - checks whether the given orig node is suitable for
* coding or not
* @bat_priv: the bat priv with all the soft interface information
* @orig_node: neighboring orig node which may be used as nc candidate
* @ogm_packet: incoming ogm packet also used for the checks
*
* Return: true if:
* 1) The OGM must have the most recent sequence number.
* 2) The TTL must be decremented by one and only one.
* 3) The OGM must be received from the first hop from orig_node.
* 4) The TQ value of the OGM must be above bat_priv->nc.min_tq.
*/
static bool batadv_can_nc_with_orig(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node,
struct batadv_ogm_packet *ogm_packet)
{
struct batadv_orig_ifinfo *orig_ifinfo;
u32 last_real_seqno;
u8 last_ttl;
orig_ifinfo = batadv_orig_ifinfo_get(orig_node, BATADV_IF_DEFAULT);
if (!orig_ifinfo)
return false;
last_ttl = orig_ifinfo->last_ttl;
last_real_seqno = orig_ifinfo->last_real_seqno;
batadv_orig_ifinfo_put(orig_ifinfo);
if (last_real_seqno != ntohl(ogm_packet->seqno))
return false;
if (last_ttl != ogm_packet->ttl + 1)
return false;
if (!batadv_compare_eth(ogm_packet->orig, ogm_packet->prev_sender))
return false;
if (ogm_packet->tq < bat_priv->nc.min_tq)
return false;
return true;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin Hundeböll | 84 | 65.62% | 2 | 40.00% |
Simon Wunderlich | 41 | 32.03% | 1 | 20.00% |
Sven Eckelmann | 3 | 2.34% | 2 | 40.00% |
Total | 128 | 100.00% | 5 | 100.00% |
/**
* batadv_nc_find_nc_node - search for an existing nc node and return it
* @orig_node: orig node originating the ogm packet
* @orig_neigh_node: neighboring orig node from which we received the ogm packet
* (can be equal to orig_node)
* @in_coding: traverse incoming or outgoing network coding list
*
* Return: the nc_node if found, NULL otherwise.
*/
static struct batadv_nc_node *
batadv_nc_find_nc_node(struct batadv_orig_node *orig_node,
struct batadv_orig_node *orig_neigh_node,
bool in_coding)
{
struct batadv_nc_node *nc_node, *nc_node_out = NULL;
struct list_head *list;
if (in_coding)
list = &orig_neigh_node->in_coding_list;
else
list = &orig_neigh_node->out_coding_list;
/* Traverse list of nc_nodes to orig_node */
rcu_read_lock();
list_for_each_entry_rcu(nc_node, list, list) {
if (!batadv_compare_eth(nc_node->addr, orig_node->orig))
continue;
if (!kref_get_unless_zero(&nc_node->refcount))
continue;
/* Found a match */
nc_node_out = nc_node;
break;
}
rcu_read_unlock();
return nc_node_out;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin Hundeböll | 107 | 99.07% | 1 | 50.00% |
Sven Eckelmann | 1 | 0.93% | 1 | 50.00% |
Total | 108 | 100.00% | 2 | 100.00% |
/**
* batadv_nc_get_nc_node - retrieves an nc node or creates the entry if it was
* not found
* @bat_priv: the bat priv with all the soft interface information
* @orig_node: orig node originating the ogm packet
* @orig_neigh_node: neighboring orig node from which we received the ogm packet
* (can be equal to orig_node)
* @in_coding: traverse incoming or outgoing network coding list
*
* Return: the nc_node if found or created, NULL in case of an error.
*/
static struct batadv_nc_node *
batadv_nc_get_nc_node(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node,
struct batadv_orig_node *orig_neigh_node,
bool in_coding)
{
struct batadv_nc_node *nc_node;
spinlock_t *lock; /* Used to lock list selected by "int in_coding" */
struct list_head *list;
/* Check if nc_node is already added */
nc_node = batadv_nc_find_nc_node(orig_node, orig_neigh_node, in_coding);
/* Node found */
if (nc_node)
return nc_node;
nc_node = kzalloc(sizeof(*nc_node), GFP_ATOMIC);
if (!nc_node)
return NULL;
/* Initialize nc_node */
INIT_LIST_HEAD(&nc_node->list);
kref_init(&nc_node->refcount);
ether_addr_copy(nc_node->addr, orig_node->orig);
kref_get(&orig_neigh_node->refcount);
nc_node->orig_node = orig_neigh_node;
/* Select ingoing or outgoing coding node */
if (in_coding) {
lock = &orig_neigh_node->in_coding_list_lock;
list = &orig_neigh_node->in_coding_list;
} else {
lock = &orig_neigh_node->out_coding_list_lock;
list = &orig_neigh_node->out_coding_list;
}
batadv_dbg(BATADV_DBG_NC, bat_priv, "Adding nc_node %pM -> %pM\n",
nc_node->addr, nc_node->orig_node->orig);
/* Add nc_node to orig_node */
spin_lock_bh(lock);
kref_get(&nc_node->refcount);
list_add_tail_rcu(&nc_node->list, list);
spin_unlock_bh(lock);
return nc_node;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin Hundeböll | 181 | 84.98% | 1 | 16.67% |
Sven Eckelmann | 31 | 14.55% | 4 | 66.67% |
Antonio Quartulli | 1 | 0.47% | 1 | 16.67% |
Total | 213 | 100.00% | 6 | 100.00% |
/**
* batadv_nc_update_nc_node - updates stored incoming and outgoing nc node
* structs (best called on incoming OGMs)
* @bat_priv: the bat priv with all the soft interface information
* @orig_node: orig node originating the ogm packet
* @orig_neigh_node: neighboring orig node from which we received the ogm packet
* (can be equal to orig_node)
* @ogm_packet: incoming ogm packet
* @is_single_hop_neigh: orig_node is a single hop neighbor
*/
void batadv_nc_update_nc_node(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node,
struct batadv_orig_node *orig_neigh_node,
struct batadv_ogm_packet *ogm_packet,
int is_single_hop_neigh)
{
struct batadv_nc_node *in_nc_node = NULL;
struct batadv_nc_node *out_nc_node = NULL;
/* Check if network coding is enabled */
if (!atomic_read(&bat_priv->network_coding