Commit f032537f authored by David S. Miller's avatar David S. Miller

Merge tag 'batman-adv-for-davem' of git://git.open-mesh.org/linux-merge

Included changes:

* major skb->data pointer usage fix
* interval version update
* added get_ethtool_stats() support
* endianess clean up
* routing protocol API improvement wrt TT commit code
* fix locking in hash table code
* minor cleanups and fixes
parents 6fac2625 dafe94b2
......@@ -211,6 +211,11 @@ The debug output can be changed at runtime using the file
will enable debug messages for when routes change.
Counters for different types of packets entering and leaving the
batman-adv module are available through ethtool:
# ethtool --statistics bat0
BATCTL
------
......
......@@ -195,13 +195,13 @@ static int debug_log_setup(struct bat_priv *bat_priv)
d = debugfs_create_file("log", S_IFREG | S_IRUSR,
bat_priv->debug_dir, bat_priv, &log_fops);
if (d)
if (!d)
goto err;
return 0;
err:
return 1;
return -ENOMEM;
}
static void debug_log_cleanup(struct bat_priv *bat_priv)
......@@ -348,8 +348,11 @@ int debugfs_add_meshif(struct net_device *dev)
if (!bat_priv->debug_dir)
goto out;
bat_socket_setup(bat_priv);
debug_log_setup(bat_priv);
if (bat_socket_setup(bat_priv) < 0)
goto rem_attr;
if (debug_log_setup(bat_priv) < 0)
goto rem_attr;
for (bat_debug = mesh_debuginfos; *bat_debug; ++bat_debug) {
file = debugfs_create_file(((*bat_debug)->attr).name,
......
......@@ -34,11 +34,12 @@ static struct neigh_node *bat_iv_ogm_neigh_new(struct hard_iface *hard_iface,
const uint8_t *neigh_addr,
struct orig_node *orig_node,
struct orig_node *orig_neigh,
uint32_t seqno)
__be32 seqno)
{
struct neigh_node *neigh_node;
neigh_node = batadv_neigh_node_new(hard_iface, neigh_addr, seqno);
neigh_node = batadv_neigh_node_new(hard_iface, neigh_addr,
ntohl(seqno));
if (!neigh_node)
goto out;
......@@ -59,7 +60,7 @@ static int bat_iv_ogm_iface_enable(struct hard_iface *hard_iface)
{
struct batman_ogm_packet *batman_ogm_packet;
uint32_t random_seqno;
int res = -1;
int res = -ENOMEM;
/* randomize initial seqno to avoid collision */
get_random_bytes(&random_seqno, sizeof(random_seqno));
......@@ -196,8 +197,12 @@ static void bat_iv_ogm_send_to_if(struct forw_packet *forw_packet,
/* create clone because function is called more than once */
skb = skb_clone(forw_packet->skb, GFP_ATOMIC);
if (skb)
if (skb) {
batadv_inc_counter(bat_priv, BAT_CNT_MGMT_TX);
batadv_add_counter(bat_priv, BAT_CNT_MGMT_TX_BYTES,
skb->len + ETH_HLEN);
send_skb_packet(skb, hard_iface, broadcast_addr);
}
}
/* send a batman ogm packet */
......@@ -542,9 +547,6 @@ static void bat_iv_ogm_forward(struct orig_node *orig_node,
"Forwarding packet: tq: %i, ttl: %i\n",
batman_ogm_packet->tq, batman_ogm_packet->header.ttl);
batman_ogm_packet->seqno = htonl(batman_ogm_packet->seqno);
batman_ogm_packet->tt_crc = htons(batman_ogm_packet->tt_crc);
/* switch of primaries first hop flag when forwarding */
batman_ogm_packet->flags &= ~PRIMARIES_FIRST_HOP;
if (is_single_hop_neigh)
......@@ -557,26 +559,31 @@ static void bat_iv_ogm_forward(struct orig_node *orig_node,
if_incoming, 0, bat_iv_ogm_fwd_send_time());
}
static void bat_iv_ogm_schedule(struct hard_iface *hard_iface,
int tt_num_changes)
static void bat_iv_ogm_schedule(struct hard_iface *hard_iface)
{
struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
struct batman_ogm_packet *batman_ogm_packet;
struct hard_iface *primary_if;
int vis_server;
int vis_server, tt_num_changes = 0;
vis_server = atomic_read(&bat_priv->vis_mode);
primary_if = primary_if_get_selected(bat_priv);
if (hard_iface == primary_if)
tt_num_changes = batadv_tt_append_diff(bat_priv,
&hard_iface->packet_buff,
&hard_iface->packet_len,
BATMAN_OGM_HLEN);
batman_ogm_packet = (struct batman_ogm_packet *)hard_iface->packet_buff;
/* change sequence number to network order */
batman_ogm_packet->seqno =
htonl((uint32_t)atomic_read(&hard_iface->seqno));
atomic_inc(&hard_iface->seqno);
batman_ogm_packet->ttvn = atomic_read(&bat_priv->ttvn);
batman_ogm_packet->tt_crc = htons((uint16_t)
atomic_read(&bat_priv->tt_crc));
batman_ogm_packet->tt_crc = htons(bat_priv->tt_crc);
if (tt_num_changes >= 0)
batman_ogm_packet->tt_num_changes = tt_num_changes;
......@@ -592,8 +599,6 @@ static void bat_iv_ogm_schedule(struct hard_iface *hard_iface,
else
batman_ogm_packet->gw_flags = NO_FLAGS;
atomic_inc(&hard_iface->seqno);
slide_own_bcast_window(hard_iface);
bat_iv_ogm_queue_add(bat_priv, hard_iface->packet_buff,
hard_iface->packet_len, hard_iface, 1,
......@@ -721,7 +726,7 @@ static void bat_iv_ogm_orig_update(struct bat_priv *bat_priv,
tt_update_orig(bat_priv, orig_node, tt_buff,
batman_ogm_packet->tt_num_changes,
batman_ogm_packet->ttvn,
batman_ogm_packet->tt_crc);
ntohs(batman_ogm_packet->tt_crc));
if (orig_node->gw_flags != batman_ogm_packet->gw_flags)
gw_node_update(bat_priv, orig_node,
......@@ -868,13 +873,14 @@ static int bat_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
int32_t seq_diff;
int need_update = 0;
int set_mark, ret = -1;
uint32_t seqno = ntohl(batman_ogm_packet->seqno);
orig_node = get_orig_node(bat_priv, batman_ogm_packet->orig);
if (!orig_node)
return 0;
spin_lock_bh(&orig_node->ogm_cnt_lock);
seq_diff = batman_ogm_packet->seqno - orig_node->last_real_seqno;
seq_diff = seqno - orig_node->last_real_seqno;
/* signalize caller that the packet is to be dropped. */
if (!hlist_empty(&orig_node->neigh_list) &&
......@@ -888,7 +894,7 @@ static int bat_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
is_duplicate |= bat_test_bit(tmp_neigh_node->real_bits,
orig_node->last_real_seqno,
batman_ogm_packet->seqno);
seqno);
if (compare_eth(tmp_neigh_node->addr, ethhdr->h_source) &&
(tmp_neigh_node->if_incoming == if_incoming))
......@@ -910,8 +916,8 @@ static int bat_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
if (need_update) {
bat_dbg(DBG_BATMAN, bat_priv,
"updating last_seqno: old %u, new %u\n",
orig_node->last_real_seqno, batman_ogm_packet->seqno);
orig_node->last_real_seqno = batman_ogm_packet->seqno;
orig_node->last_real_seqno, seqno);
orig_node->last_real_seqno = seqno;
}
ret = is_duplicate;
......@@ -967,8 +973,8 @@ static void bat_iv_ogm_process(const struct ethhdr *ethhdr,
"Received BATMAN packet via NB: %pM, IF: %s [%pM] (from OG: %pM, via prev OG: %pM, seqno %u, ttvn %u, crc %u, changes %u, td %d, TTL %d, V %d, IDF %d)\n",
ethhdr->h_source, if_incoming->net_dev->name,
if_incoming->net_dev->dev_addr, batman_ogm_packet->orig,
batman_ogm_packet->prev_sender, batman_ogm_packet->seqno,
batman_ogm_packet->ttvn, batman_ogm_packet->tt_crc,
batman_ogm_packet->prev_sender, ntohl(batman_ogm_packet->seqno),
batman_ogm_packet->ttvn, ntohs(batman_ogm_packet->tt_crc),
batman_ogm_packet->tt_num_changes, batman_ogm_packet->tq,
batman_ogm_packet->header.ttl,
batman_ogm_packet->header.version, has_directlink_flag);
......@@ -1039,7 +1045,7 @@ static void bat_iv_ogm_process(const struct ethhdr *ethhdr,
word = &(orig_neigh_node->bcast_own[offset]);
bat_set_bit(word,
if_incoming_seqno -
batman_ogm_packet->seqno - 2);
ntohl(batman_ogm_packet->seqno) - 2);
orig_neigh_node->bcast_own_sum[if_incoming->if_num] =
bitmap_weight(word, TQ_LOCAL_WINDOW_SIZE);
spin_unlock_bh(&orig_neigh_node->ogm_cnt_lock);
......@@ -1132,7 +1138,7 @@ static void bat_iv_ogm_process(const struct ethhdr *ethhdr,
* seqno and similar ttl as the non-duplicate */
if (is_bidirectional &&
(!is_duplicate ||
((orig_node->last_real_seqno == batman_ogm_packet->seqno) &&
((orig_node->last_real_seqno == ntohl(batman_ogm_packet->seqno)) &&
(orig_node->last_ttl - 3 <= batman_ogm_packet->header.ttl))))
bat_iv_ogm_orig_update(bat_priv, orig_node, ethhdr,
batman_ogm_packet, if_incoming,
......@@ -1204,6 +1210,10 @@ static int bat_iv_ogm_receive(struct sk_buff *skb,
if (bat_priv->bat_algo_ops->bat_ogm_emit != bat_iv_ogm_emit)
return NET_RX_DROP;
batadv_inc_counter(bat_priv, BAT_CNT_MGMT_RX);
batadv_add_counter(bat_priv, BAT_CNT_MGMT_RX_BYTES,
skb->len + ETH_HLEN);
packet_len = skb_headlen(skb);
ethhdr = (struct ethhdr *)skb_mac_header(skb);
packet_buff = skb->data;
......@@ -1211,11 +1221,6 @@ static int bat_iv_ogm_receive(struct sk_buff *skb,
/* unpack the aggregated packets and process them one by one */
do {
/* network to host order for our 32bit seqno and the
orig_interval */
batman_ogm_packet->seqno = ntohl(batman_ogm_packet->seqno);
batman_ogm_packet->tt_crc = ntohs(batman_ogm_packet->tt_crc);
tt_buff = packet_buff + buff_pos + BATMAN_OGM_HLEN;
bat_iv_ogm_process(ethhdr, batman_ogm_packet,
......@@ -1234,7 +1239,7 @@ static int bat_iv_ogm_receive(struct sk_buff *skb,
}
static struct bat_algo_ops batman_iv __read_mostly = {
.name = "BATMAN IV",
.name = "BATMAN_IV",
.bat_iface_enable = bat_iv_ogm_iface_enable,
.bat_iface_disable = bat_iv_ogm_iface_disable,
.bat_iface_update_mac = bat_iv_ogm_iface_update_mac,
......
......@@ -445,7 +445,7 @@ BAT_ATTR_SIF_UINT(gw_sel_class, S_IRUGO | S_IWUSR, 1, TQ_MAX_VALUE,
static BAT_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, show_gw_bwidth,
store_gw_bwidth);
#ifdef CONFIG_BATMAN_ADV_DEBUG
BAT_ATTR_SIF_UINT(log_level, S_IRUGO | S_IWUSR, 0, 15, NULL);
BAT_ATTR_SIF_UINT(log_level, S_IRUGO | S_IWUSR, 0, DBG_ALL, NULL);
#endif
static struct bat_attribute *mesh_attrs[] = {
......@@ -680,7 +680,7 @@ void sysfs_del_hardif(struct kobject **hardif_obj)
int throw_uevent(struct bat_priv *bat_priv, enum uev_type type,
enum uev_action action, const char *data)
{
int ret = -1;
int ret = -ENOMEM;
struct hard_iface *primary_if = NULL;
struct kobject *bat_kobj;
char *uevent_env[4] = { NULL, NULL, NULL, NULL };
......
......@@ -258,7 +258,7 @@ static void bla_send_claim(struct bat_priv *bat_priv, uint8_t *mac,
struct net_device *soft_iface;
uint8_t *hw_src;
struct bla_claim_dst local_claim_dest;
uint32_t zeroip = 0;
__be32 zeroip = 0;
primary_if = primary_if_get_selected(bat_priv);
if (!primary_if)
......@@ -506,11 +506,11 @@ static void bla_send_announce(struct bat_priv *bat_priv,
struct backbone_gw *backbone_gw)
{
uint8_t mac[ETH_ALEN];
uint16_t crc;
__be16 crc;
memcpy(mac, announce_mac, 4);
crc = htons(backbone_gw->crc);
memcpy(&mac[4], (uint8_t *)&crc, 2);
memcpy(&mac[4], &crc, 2);
bla_send_claim(bat_priv, mac, backbone_gw->vid, CLAIM_TYPE_ANNOUNCE);
......@@ -627,7 +627,7 @@ static int handle_announce(struct bat_priv *bat_priv,
/* handle as ANNOUNCE frame */
backbone_gw->lasttime = jiffies;
crc = ntohs(*((uint16_t *)(&an_addr[4])));
crc = ntohs(*((__be16 *)(&an_addr[4])));
bat_dbg(DBG_BLA, bat_priv,
"handle_announce(): ANNOUNCE vid %d (sent by %pM)... CRC = %04x\n",
......@@ -1127,6 +1127,14 @@ static void bla_periodic_work(struct work_struct *work)
bla_start_timer(bat_priv);
}
/* The hash for claim and backbone hash receive the same key because they
* are getting initialized by hash_new with the same key. Reinitializing
* them with to different keys to allow nested locking without generating
* lockdep warnings
*/
static struct lock_class_key claim_hash_lock_class_key;
static struct lock_class_key backbone_hash_lock_class_key;
/* initialize all bla structures */
int bla_init(struct bat_priv *bat_priv)
{
......@@ -1156,18 +1164,23 @@ int bla_init(struct bat_priv *bat_priv)
bat_priv->bcast_duplist_curr = 0;
if (bat_priv->claim_hash)
return 1;
return 0;
bat_priv->claim_hash = hash_new(128);
bat_priv->backbone_hash = hash_new(32);
if (!bat_priv->claim_hash || !bat_priv->backbone_hash)
return -1;
return -ENOMEM;
batadv_hash_set_lock_class(bat_priv->claim_hash,
&claim_hash_lock_class_key);
batadv_hash_set_lock_class(bat_priv->backbone_hash,
&backbone_hash_lock_class_key);
bat_dbg(DBG_BLA, bat_priv, "bla hashes initialized\n");
bla_start_timer(bat_priv);
return 1;
return 0;
}
/**
......
......@@ -162,6 +162,9 @@ ssize_t gw_bandwidth_set(struct net_device *net_dev, char *buff, size_t count)
**/
gw_bandwidth_to_kbit((uint8_t)gw_bandwidth_tmp, &down, &up);
if (atomic_read(&bat_priv->gw_bandwidth) == gw_bandwidth_tmp)
return count;
gw_deselect(bat_priv);
bat_info(net_dev,
"Changing gateway bandwidth from: '%i' to: '%ld' (propagating: %d%s/%d%s)\n",
......
......@@ -306,10 +306,8 @@ int hardif_enable_interface(struct hard_iface *hard_iface,
bat_priv = netdev_priv(hard_iface->soft_iface);
ret = bat_priv->bat_algo_ops->bat_iface_enable(hard_iface);
if (ret < 0) {
ret = -ENOMEM;
if (ret < 0)
goto err_dev;
}
hard_iface->if_num = bat_priv->num_ifaces;
bat_priv->num_ifaces++;
......
......@@ -69,3 +69,12 @@ struct hashtable_t *hash_new(uint32_t size)
kfree(hash);
return NULL;
}
void batadv_hash_set_lock_class(struct hashtable_t *hash,
struct lock_class_key *key)
{
uint32_t i;
for (i = 0; i < hash->size; i++)
lockdep_set_class(&hash->list_locks[i], key);
}
......@@ -45,6 +45,10 @@ struct hashtable_t {
/* allocates and clears the hash */
struct hashtable_t *hash_new(uint32_t size);
/* set class key for all locks */
void batadv_hash_set_lock_class(struct hashtable_t *hash,
struct lock_class_key *key);
/* free only the hashtable and the hash itself. */
void hash_destroy(struct hashtable_t *hash);
......@@ -106,26 +110,23 @@ static inline int hash_add(struct hashtable_t *hash,
head = &hash->table[index];
list_lock = &hash->list_locks[index];
rcu_read_lock();
__hlist_for_each_rcu(node, head) {
spin_lock_bh(list_lock);
hlist_for_each(node, head) {
if (!compare(node, data))
continue;
ret = 1;
goto err_unlock;
goto unlock;
}
rcu_read_unlock();
/* no duplicate found in list, add new element */
spin_lock_bh(list_lock);
hlist_add_head_rcu(data_node, head);
spin_unlock_bh(list_lock);
ret = 0;
goto out;
err_unlock:
rcu_read_unlock();
unlock:
spin_unlock_bh(list_lock);
out:
return ret;
}
......
......@@ -285,13 +285,13 @@ int bat_socket_setup(struct bat_priv *bat_priv)
d = debugfs_create_file(ICMP_SOCKET, S_IFREG | S_IWUSR | S_IRUSR,
bat_priv->debug_dir, bat_priv, &fops);
if (d)
if (!d)
goto err;
return 0;
err:
return 1;
return -ENOMEM;
}
static void bat_socket_add_packet(struct socket_client *socket_client,
......
......@@ -40,7 +40,7 @@
* list traversals just rcu-locked */
struct list_head hardif_list;
static int (*recv_packet_handler[256])(struct sk_buff *, struct hard_iface *);
char bat_routing_algo[20] = "BATMAN IV";
char bat_routing_algo[20] = "BATMAN_IV";
static struct hlist_head bat_algo_list;
unsigned char broadcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
......@@ -92,6 +92,7 @@ static void __exit batman_exit(void)
int mesh_init(struct net_device *soft_iface)
{
struct bat_priv *bat_priv = netdev_priv(soft_iface);
int ret;
spin_lock_init(&bat_priv->forw_bat_list_lock);
spin_lock_init(&bat_priv->forw_bcast_list_lock);
......@@ -110,30 +111,32 @@ int mesh_init(struct net_device *soft_iface)
INIT_LIST_HEAD(&bat_priv->tt_req_list);
INIT_LIST_HEAD(&bat_priv->tt_roam_list);
if (originator_init(bat_priv) < 1)
ret = originator_init(bat_priv);
if (ret < 0)
goto err;
if (tt_init(bat_priv) < 1)
ret = tt_init(bat_priv);
if (ret < 0)
goto err;
tt_local_add(soft_iface, soft_iface->dev_addr, NULL_IFINDEX);
if (vis_init(bat_priv) < 1)
ret = vis_init(bat_priv);
if (ret < 0)
goto err;
if (bla_init(bat_priv) < 1)
ret = bla_init(bat_priv);
if (ret < 0)
goto err;
atomic_set(&bat_priv->gw_reselect, 0);
atomic_set(&bat_priv->mesh_state, MESH_ACTIVE);
goto end;
return 0;
err:
mesh_free(soft_iface);
return -1;
end:
return 0;
return ret;
}
void mesh_free(struct net_device *soft_iface)
......@@ -153,6 +156,8 @@ void mesh_free(struct net_device *soft_iface)
bla_free(bat_priv);
free_percpu(bat_priv->bat_counters);
atomic_set(&bat_priv->mesh_state, MESH_INACTIVE);
}
......@@ -317,12 +322,13 @@ static struct bat_algo_ops *bat_algo_get(char *name)
int bat_algo_register(struct bat_algo_ops *bat_algo_ops)
{
struct bat_algo_ops *bat_algo_ops_tmp;
int ret = -1;
int ret;
bat_algo_ops_tmp = bat_algo_get(bat_algo_ops->name);
if (bat_algo_ops_tmp) {
pr_info("Trying to register already registered routing algorithm: %s\n",
bat_algo_ops->name);
ret = -EEXIST;
goto out;
}
......@@ -335,6 +341,7 @@ int bat_algo_register(struct bat_algo_ops *bat_algo_ops)
!bat_algo_ops->bat_ogm_emit) {
pr_info("Routing algo '%s' does not implement required ops\n",
bat_algo_ops->name);
ret = -EINVAL;
goto out;
}
......@@ -349,7 +356,7 @@ int bat_algo_register(struct bat_algo_ops *bat_algo_ops)
int bat_algo_select(struct bat_priv *bat_priv, char *name)
{
struct bat_algo_ops *bat_algo_ops;
int ret = -1;
int ret = -EINVAL;
bat_algo_ops = bat_algo_get(name);
if (!bat_algo_ops)
......@@ -379,14 +386,19 @@ int bat_algo_seq_print_text(struct seq_file *seq, void *offset)
static int param_set_ra(const char *val, const struct kernel_param *kp)
{
struct bat_algo_ops *bat_algo_ops;
char *algo_name = (char *)val;
size_t name_len = strlen(algo_name);
if (algo_name[name_len - 1] == '\n')
algo_name[name_len - 1] = '\0';
bat_algo_ops = bat_algo_get((char *)val);
bat_algo_ops = bat_algo_get(algo_name);
if (!bat_algo_ops) {
pr_err("Routing algorithm '%s' is not supported\n", val);
pr_err("Routing algorithm '%s' is not supported\n", algo_name);
return -EINVAL;
}
return param_set_copystring(val, kp);
return param_set_copystring(algo_name, kp);
}
static const struct kernel_param_ops param_ops_ra = {
......
......@@ -28,7 +28,7 @@
#define DRIVER_DEVICE "batman-adv"
#ifndef SOURCE_VERSION
#define SOURCE_VERSION "2012.2.0"
#define SOURCE_VERSION "2012.3.0"
#endif
/* B.A.T.M.A.N. parameters */
......@@ -138,6 +138,7 @@ enum dbg_level {
#include <linux/kthread.h> /* kernel threads */
#include <linux/pkt_sched.h> /* schedule types */
#include <linux/workqueue.h> /* workqueue */
#include <linux/percpu.h>
#include <linux/slab.h>
#include <net/sock.h> /* struct sock */
#include <linux/jiffies.h>
......@@ -242,4 +243,30 @@ static inline bool has_timed_out(unsigned long timestamp, unsigned int timeout)
_dummy > smallest_signed_int(_dummy); })
#define seq_after(x, y) seq_before(y, x)
/* Stop preemption on local cpu while incrementing the counter */
static inline void batadv_add_counter(struct bat_priv *bat_priv, size_t idx,
size_t count)
{
int cpu = get_cpu();
per_cpu_ptr(bat_priv->bat_counters, cpu)[idx] += count;
put_cpu();
}
#define batadv_inc_counter(b, i) batadv_add_counter(b, i, 1)
/* Sum and return the cpu-local counters for index 'idx' */
static inline uint64_t batadv_sum_counter(struct bat_priv *bat_priv, size_t idx)
{
uint64_t *counters;
int cpu;
int sum = 0;
for_each_possible_cpu(cpu) {
counters = per_cpu_ptr(bat_priv->bat_counters, cpu);
sum += counters[idx];
}
return sum;
}
#endif /* _NET_BATMAN_ADV_MAIN_H_ */
......@@ -50,7 +50,7 @@ static int compare_orig(const struct hlist_node *node, const void *data2)
int originator_init(struct bat_priv *bat_priv)
{
if (bat_priv->orig_hash)
return 1;
return 0;
bat_priv->orig_hash = hash_new(1024);
......@@ -58,10 +58,10 @@ int originator_init(struct bat_priv *bat_priv)
goto err;
start_purge_timer(bat_priv);
return 1;
return 0;
err:
return 0;
return -ENOMEM;
}
void neigh_node_free_ref(struct neigh_node *neigh_node)
......@@ -488,7 +488,7 @@ static int orig_node_add_if(struct orig_node *orig_node, int max_if_num)
data_ptr = kmalloc(max_if_num * sizeof(unsigned long) * NUM_WORDS,
GFP_ATOMIC);
if (!data_ptr)
return -1;
return -ENOMEM;
memcpy(data_ptr, orig_node->bcast_own,
(max_if_num - 1) * sizeof(unsigned long) * NUM_WORDS);
......@@ -497,7 +497,7 @@ static int orig_node_add_if(struct orig_node *orig_node, int max_if_num)
data_ptr = kmalloc(max_if_num * sizeof(uint8_t), GFP_ATOMIC);
if (!data_ptr)
return -1;
return -ENOMEM;
memcpy(data_ptr, orig_node->bcast_own_sum,
(max_if_num - 1) * sizeof(uint8_t));
......@@ -528,7 +528,7 @@ int orig_hash_add_if(struct hard_iface *hard_iface, int max_if_num)
ret = orig_node_add_if(orig_node, max_if_num);
spin_unlock_bh(&orig_node->ogm_cnt_lock);
if (ret == -1)
if (ret == -ENOMEM)
goto err;
}
rcu_read_unlock();
......@@ -554,7 +554,7 @@ static int orig_node_del_if(struct orig_node *orig_node,
chunk_size = sizeof(unsigned long) * NUM_WORDS;
data_ptr = kmalloc(max_if_num * chunk_size, GFP_ATOMIC);
if (!data_ptr)
return -1;
return -ENOMEM;
/* copy first part */
memcpy(data_ptr, orig_node->bcast_own, del_if_num * chunk_size);
......@@ -573,7 +573,7 @@ static int orig_node_del_if(struct orig_node *orig_node,
data_ptr = kmalloc(max_if_num * sizeof(uint8_t), GFP_ATOMIC);
if (!data_ptr)
return -1;
return -ENOMEM;
memcpy(data_ptr, orig_node->bcast_own_sum,
del_if_num * sizeof(uint8_t));
......@@ -612,7 +612,7 @@ int orig_hash_del_if(struct hard_iface *hard_iface, int max_if_num)
hard_iface->if_num);
spin_unlock_bh(&orig_node->ogm_cnt_lock);
if (ret == -1)
if (ret == -ENOMEM)
goto err;
}
rcu_read_unlock();
......
......@@ -105,7 +105,7 @@ enum bla_claimframe {
struct bla_claim_dst {
uint8_t magic[3]; /* FF:43:05 */
uint8_t type; /* bla_claimframe */
uint16_t group; /* group id */
__be16 group; /* group id */
} __packed;
struct batman_header {
......@@ -117,14 +117,14 @@ struct batman_header {
struct batman_ogm_packet {
struct batman_header header;
uint8_t flags; /* 0x40: DIRECTLINK flag, 0x20 VIS_SERVER flag... */
uint32_t seqno;
__be32 seqno;
uint8_t orig[ETH_ALEN];
uint8_t prev_sender[ETH_ALEN];
uint8_t gw_flags; /* flags related to gateway class */
uint8_t tq;
uint8_t tt_num_changes;
uint8_t ttvn; /* translation table version number */
uint16_t tt_crc;
__be16 tt_crc;
} __packed;
#define BATMAN_OGM_HLEN sizeof(struct batman_ogm_packet)
......@@ -134,7 +134,7 @@ struct icmp_packet {
uint8_t msg_type; /* see ICMP message types above */
uint8_t dst[ETH_ALEN];
uint8_t orig[ETH_ALEN];
uint16_t seqno;
__be16 seqno;
uint8_t uid;
uint8_t reserved;
} __packed;
......@@ -148,7 +148,7 @@ struct icmp_packet_rr {
uint8_t msg_type; /* see ICMP message types above */
uint8_t dst[ETH_ALEN];
uint8_t orig[ETH_ALEN];
uint16_t seqno;
__be16 seqno;
uint8_t uid;
uint8_t rr_cur;
uint8_t rr[BAT_RR_LEN][ETH_ALEN];
......@@ -167,20 +167,20 @@ struct unicast_frag_packet {
uint8_t flags;
uint8_t align;
uint8_t orig[ETH_ALEN];
uint16_t seqno;
__be16 seqno;
} __packed;
struct bcast_packet {
struct batman_header header;
uint8_t reserved;
uint32_t seqno;
__be32 seqno;
uint8_t orig[ETH_ALEN];
} __packed;
struct vis_packet {
struct batman_header header;
uint8_t vis_type; /* which type of vis-participant sent this? */
uint32_t seqno; /* sequence number */
__be32 seqno; /* sequence number */
uint8_t entries; /* number of entries behind this struct */
uint8_t reserved;
uint8_t vis_orig[ETH_ALEN]; /* originator reporting its neighbors */
......@@ -206,7 +206,7 @@ struct tt_query_packet {
* if TT_REQUEST: crc associated with the
* ttvn
* if TT_RESPONSE: table_size */
uint16_t tt_data;
__be16 tt_data;
} __packed;
struct roam_adv_packet {
......
......@@ -573,7 +573,7 @@ int recv_tt_query(struct sk_buff *skb, struct hard_iface *recv_if)
{
struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
struct tt_query_packet *tt_query;
uint16_t tt_len;
uint16_t tt_size;
struct ethhdr *ethhdr;
/* drop packet if it has not necessary minimum size */
......@@ -596,10 +596,10 @@ int recv_tt_query(struct sk_buff *skb, struct hard_iface *recv_if)
tt_query = (struct tt_query_packet *)skb->data;
tt_query->tt_data = ntohs(tt_query->tt_data);
switch (tt_query->flags & TT_QUERY_TYPE_MASK) {
case TT_REQUEST:
batadv_inc_counter(bat_priv, BAT_CNT_TT_REQUEST_RX);
/* If we cannot provide an answer the tt_request is
* forwarded */
if (!send_tt_response(bat_priv, tt_query)) {
......@@ -607,22 +607,25 @@ int recv_tt_query(struct sk_buff *skb, struct hard_iface *recv_if)
"Routing TT_REQUEST to %pM [%c]\n",
tt_query->dst,
(tt_query->flags & TT_FULL_TABLE ? 'F' : '.'));
tt_query->tt_data = htons(tt_query->tt_data);
return route_unicast_packet(skb, recv_if);
}
break;
case TT_RESPONSE:
batadv_inc_counter(bat_priv, BAT_CNT_TT_RESPONSE_RX);
if (is_my_mac(tt_query->dst)) {
/* packet needs to be linearized to access the TT
* changes */
if (skb_linearize(skb) < 0)
goto out;
/* skb_linearize() possibly changed skb->data */
tt_query = (struct tt_query_packet *)skb->data;
tt_len = tt_query->tt_data * sizeof(struct tt_change);
tt_size = tt_len(ntohs(tt_query->tt_data));
/* Ensure we have all the claimed data */
if (unlikely(skb_headlen(skb) <
sizeof(struct tt_query_packet) + tt_len))
sizeof(struct tt_query_packet) + tt_size))
goto out;
handle_tt_response(bat_priv, tt_query);
......@@ -631,7 +634,6 @@ int recv_tt_query(struct sk_buff *skb, struct hard_iface *recv_if)
"Routing TT_RESPONSE to %pM [%c]\n",
tt_query->dst,
(tt_query->flags & TT_FULL_TABLE ? 'F' : '.'));
tt_query->tt_data = htons(tt_query->tt_data);
return route_unicast_packet(skb, recv_if);
}
break;
......@@ -663,6 +665,8 @@ int recv_roam_adv(struct sk_buff *skb, struct hard_iface *recv_if)
if (is_broadcast_ether_addr(ethhdr->h_source))
goto out;
batadv_inc_counter(bat_priv, BAT_CNT_TT_ROAM_ADV_RX);
roam_adv_packet = (struct roam_adv_packet *)skb->data;
if (!is_my_mac(roam_adv_packet->dst))
......@@ -870,6 +874,11 @@ static int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
/* decrement ttl */
unicast_packet->header.ttl--;
/* Update stats counter */
batadv_inc_counter(bat_priv, BAT_CNT_FORWARD);
batadv_add_counter(bat_priv, BAT_CNT_FORWARD_BYTES,
skb->len + ETH_HLEN);
/* route it */
send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
ret = NET_RX_SUCCESS;
......
......@@ -77,62 +77,9 @@ int send_skb_packet(struct sk_buff *skb, struct hard_iface *hard_iface,
return NET_XMIT_DROP;
}
static void realloc_packet_buffer(struct hard_iface *hard_iface,
int new_len)
{
unsigned char *new_buff;
new_buff = kmalloc(new_len, GFP_ATOMIC);
/* keep old buffer if kmalloc should fail */
if (new_buff) {
memcpy(new_buff, hard_iface->packet_buff,
BATMAN_OGM_HLEN);
kfree(hard_iface->packet_buff);
hard_iface->packet_buff = new_buff;
hard_iface->packet_len = new_len;
}
}
/* when calling this function (hard_iface == primary_if) has to be true */
static int prepare_packet_buffer(struct bat_priv *bat_priv,
struct hard_iface *hard_iface)
{
int new_len;
new_len = BATMAN_OGM_HLEN +
tt_len((uint8_t)atomic_read(&bat_priv->tt_local_changes));
/* if we have too many changes for one packet don't send any
* and wait for the tt table request which will be fragmented */
if (new_len > hard_iface->soft_iface->mtu)
new_len = BATMAN_OGM_HLEN;
realloc_packet_buffer(hard_iface, new_len);
atomic_set(&bat_priv->tt_crc, tt_local_crc(bat_priv));
/* reset the sending counter */
atomic_set(&bat_priv->tt_ogm_append_cnt, TT_OGM_APPEND_MAX);
return tt_changes_fill_buffer(bat_priv,
hard_iface->packet_buff + BATMAN_OGM_HLEN,
hard_iface->packet_len - BATMAN_OGM_HLEN);
}
static int reset_packet_buffer(struct bat_priv *bat_priv,
struct hard_iface *hard_iface)
{
realloc_packet_buffer(hard_iface, BATMAN_OGM_HLEN);
return 0;
}
void schedule_bat_ogm(struct hard_iface *hard_iface)
{
struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
struct hard_iface *primary_if;
int tt_num_changes = -1;
if ((hard_iface->if_status == IF_NOT_IN_USE) ||
(hard_iface->if_status == IF_TO_BE_REMOVED))
......@@ -148,26 +95,7 @@ void schedule_bat_ogm(struct hard_iface *hard_iface)
if (hard_iface->if_status == IF_TO_BE_ACTIVATED)
hard_iface->if_status = IF_ACTIVE;
primary_if = primary_if_get_selected(bat_priv);
if (hard_iface == primary_if) {
/* if at least one change happened */
if (atomic_read(&bat_priv->tt_local_changes) > 0) {
tt_commit_changes(bat_priv);
tt_num_changes = prepare_packet_buffer(bat_priv,
hard_iface);
}
/* if the changes have been sent often enough */
if (!atomic_dec_not_zero(&bat_priv->tt_ogm_append_cnt))
tt_num_changes = reset_packet_buffer(bat_priv,
hard_iface);
}
if (primary_if)
hardif_free_ref(primary_if);
bat_priv->bat_algo_ops->bat_ogm_schedule(hard_iface, tt_num_changes);
bat_priv->bat_algo_ops->bat_ogm_schedule(hard_iface);
}
static void forw_packet_free(struct forw_packet *forw_packet)
......
......@@ -45,6 +45,10 @@ static void bat_get_drvinfo(struct net_device *dev,
static u32 bat_get_msglevel(struct net_device *dev);
static void bat_set_msglevel(struct net_device *dev, u32 value);
static u32 bat_get_link(struct net_device *dev);
static void batadv_get_strings(struct net_device *dev, u32 stringset, u8 *data);
static void batadv_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *stats, u64 *data);
static int batadv_get_sset_count(struct net_device *dev, int stringset);
static const struct ethtool_ops bat_ethtool_ops = {
.get_settings = bat_get_settings,
......@@ -52,6 +56,9 @@ static const struct ethtool_ops bat_ethtool_ops = {
.get_msglevel = bat_get_msglevel,
.set_msglevel = bat_set_msglevel,
.get_link = bat_get_link,
.get_strings = batadv_get_strings,
.get_ethtool_stats = batadv_get_ethtool_stats,
.get_sset_count = batadv_get_sset_count,
};
int my_skb_head_push(struct sk_buff *skb, unsigned int len)
......@@ -399,13 +406,18 @@ struct net_device *softif_create(const char *name)
bat_priv->primary_if = NULL;
bat_priv->num_ifaces = 0;
bat_priv->bat_counters = __alloc_percpu(sizeof(uint64_t) * BAT_CNT_NUM,
__alignof__(uint64_t));
if (!bat_priv->bat_counters)
goto unreg_soft_iface;
ret = bat_algo_select(bat_priv, bat_routing_algo);
if (ret < 0)
goto unreg_soft_iface;
goto free_bat_counters;
ret = sysfs_add_meshif(soft_iface);
if (ret < 0)
goto unreg_soft_iface;
goto free_bat_counters;
ret = debugfs_add_meshif(soft_iface);
if (ret < 0)
......@@ -421,6 +433,8 @@ struct net_device *softif_create(const char *name)
debugfs_del_meshif(soft_iface);
unreg_sysfs:
sysfs_del_meshif(soft_iface);
free_bat_counters:
free_percpu(bat_priv->bat_counters);
unreg_soft_iface:
unregister_netdevice(soft_iface);
return NULL;
......@@ -486,3 +500,51 @@ static u32 bat_get_link(struct net_device *dev)
{
return 1;
}
/* Inspired by drivers/net/ethernet/dlink/sundance.c:1702
* Declare each description string in struct.name[] to get fixed sized buffer
* and compile time checking for strings longer than ETH_GSTRING_LEN.
*/
static const struct {
const char name[ETH_GSTRING_LEN];
} bat_counters_strings[] = {
{ "forward" },
{ "forward_bytes" },
{ "mgmt_tx" },
{ "mgmt_tx_bytes" },
{ "mgmt_rx" },
{ "mgmt_rx_bytes" },
{ "tt_request_tx" },
{ "tt_request_rx" },
{ "tt_response_tx" },
{ "tt_response_rx" },
{ "tt_roam_adv_tx" },
{ "tt_roam_adv_rx" },
};
static void batadv_get_strings(struct net_device *dev, uint32_t stringset,
uint8_t *data)
{
if (stringset == ETH_SS_STATS)
memcpy(data, bat_counters_strings,
sizeof(bat_counters_strings));
}
static void batadv_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *stats,
uint64_t *data)
{
struct bat_priv *bat_priv = netdev_priv(dev);
int i;
for (i = 0; i < BAT_CNT_NUM; i++)
data[i] = batadv_sum_counter(bat_priv, i);
}
static int batadv_get_sset_count(struct net_device *dev, int stringset)
{
if (stringset == ETH_SS_STATS)
return BAT_CNT_NUM;
return -EOPNOTSUPP;
}
......@@ -181,14 +181,14 @@ int tt_len(int changes_num)
static int tt_local_init(struct bat_priv *bat_priv)
{
if (bat_priv->tt_local_hash)
return 1;
return 0;
bat_priv->tt_local_hash = hash_new(1024);
if (!bat_priv->tt_local_hash)
return 0;
return -ENOMEM;
return 1;
return 0;
}
void tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
......@@ -275,14 +275,64 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
tt_global_entry_free_ref(tt_global_entry);
}
int tt_changes_fill_buffer(struct bat_priv *bat_priv,
unsigned char *buff, int buff_len)
static void tt_realloc_packet_buff(unsigned char **packet_buff,
int *packet_buff_len, int min_packet_len,
int new_packet_len)
{
unsigned char *new_buff;
new_buff = kmalloc(new_packet_len, GFP_ATOMIC);
/* keep old buffer if kmalloc should fail */
if (new_buff) {
memcpy(new_buff, *packet_buff, min_packet_len);
kfree(*packet_buff);
*packet_buff = new_buff;
*packet_buff_len = new_packet_len;
}
}
static void tt_prepare_packet_buff(struct bat_priv *bat_priv,
unsigned char **packet_buff,
int *packet_buff_len, int min_packet_len)
{
struct hard_iface *primary_if;
int req_len;
primary_if = primary_if_get_selected(bat_priv);
req_len = min_packet_len;
req_len += tt_len(atomic_read(&bat_priv->tt_local_changes));
/* if we have too many changes for one packet don't send any
* and wait for the tt table request which will be fragmented
*/
if ((!primary_if) || (req_len > primary_if->soft_iface->mtu))
req_len = min_packet_len;
tt_realloc_packet_buff(packet_buff, packet_buff_len,
min_packet_len, req_len);
if (primary_if)
hardif_free_ref(primary_if);
}
static int tt_changes_fill_buff(struct bat_priv *bat_priv,
unsigned char **packet_buff,
int *packet_buff_len, int min_packet_len)
{
int count = 0, tot_changes = 0;
struct tt_change_node *entry, *safe;
int count = 0, tot_changes = 0, new_len;
unsigned char *tt_buff;
tt_prepare_packet_buff(bat_priv, packet_buff,
packet_buff_len, min_packet_len);
new_len = *packet_buff_len - min_packet_len;
tt_buff = *packet_buff + min_packet_len;
if (buff_len > 0)
tot_changes = buff_len / tt_len(1);
if (new_len > 0)
tot_changes = new_len / tt_len(1);
spin_lock_bh(&bat_priv->tt_changes_list_lock);
atomic_set(&bat_priv->tt_local_changes, 0);
......@@ -290,7 +340,7 @@ int tt_changes_fill_buffer(struct bat_priv *bat_priv,
list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list,
list) {
if (count < tot_changes) {
memcpy(buff + tt_len(count),
memcpy(tt_buff + tt_len(count),
&entry->change, sizeof(struct tt_change));
count++;
}
......@@ -304,22 +354,20 @@ int tt_changes_fill_buffer(struct bat_priv *bat_priv,
kfree(bat_priv->tt_buff);
bat_priv->tt_buff_len = 0;
bat_priv->tt_buff = NULL;
/* We check whether this new OGM has no changes due to size
* problems */
if (buff_len > 0) {
/**
* if kmalloc() fails we will reply with the full table
/* check whether this new OGM has no changes due to size problems */
if (new_len > 0) {
/* if kmalloc() fails we will reply with the full table
* instead of providing the diff
*/
bat_priv->tt_buff = kmalloc(buff_len, GFP_ATOMIC);
bat_priv->tt_buff = kmalloc(new_len, GFP_ATOMIC);
if (bat_priv->tt_buff) {
memcpy(bat_priv->tt_buff, buff, buff_len);
bat_priv->tt_buff_len = buff_len;
memcpy(bat_priv->tt_buff, tt_buff, new_len);
bat_priv->tt_buff_len = new_len;
}
}
spin_unlock_bh(&bat_priv->tt_buff_lock);
return tot_changes;
return count;
}
int tt_local_seq_print_text(struct seq_file *seq, void *offset)
......@@ -491,14 +539,14 @@ static void tt_local_table_free(struct bat_priv *bat_priv)
static int tt_global_init(struct bat_priv *bat_priv)
{
if (bat_priv->tt_global_hash)
return 1;
return 0;
bat_priv->tt_global_hash = hash_new(1024);
if (!bat_priv->tt_global_hash)
return 0;
return -ENOMEM;
return 1;
return 0;
}
static void tt_changes_list_free(struct bat_priv *bat_priv)
......@@ -1105,7 +1153,7 @@ static uint16_t tt_global_crc(struct bat_priv *bat_priv,
}
/* Calculates the checksum of the local table */
uint16_t tt_local_crc(struct bat_priv *bat_priv)
static uint16_t batadv_tt_local_crc(struct bat_priv *bat_priv)
{
uint16_t total = 0, total_one;
struct hashtable_t *hash = bat_priv->tt_local_hash;
......@@ -1356,6 +1404,8 @@ static int send_tt_request(struct bat_priv *bat_priv,
dst_orig_node->orig, neigh_node->addr,
(full_table ? 'F' : '.'));
batadv_inc_counter(bat_priv, BAT_CNT_TT_REQUEST_TX);
send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
ret = 0;
......@@ -1416,7 +1466,7 @@ static bool send_other_tt_response(struct bat_priv *bat_priv,
/* I don't have the requested data */
if (orig_ttvn != req_ttvn ||
tt_request->tt_data != req_dst_orig_node->tt_crc)
tt_request->tt_data != htons(req_dst_orig_node->tt_crc))
goto out;
/* If the full table has been explicitly requested */
......@@ -1480,6 +1530,8 @@ static bool send_other_tt_response(struct bat_priv *bat_priv,
res_dst_orig_node->orig, neigh_node->addr,
req_dst_orig_node->orig, req_ttvn);
batadv_inc_counter(bat_priv, BAT_CNT_TT_RESPONSE_TX);
send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
ret = true;
goto out;
......@@ -1596,6 +1648,8 @@ static bool send_my_tt_response(struct bat_priv *bat_priv,
orig_node->orig, neigh_node->addr,
(tt_response->flags & TT_FULL_TABLE ? 'F' : '.'));
batadv_inc_counter(bat_priv, BAT_CNT_TT_RESPONSE_TX);
send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
ret = true;
goto out;
......@@ -1672,7 +1726,7 @@ static void tt_fill_gtable(struct bat_priv *bat_priv,
_tt_update_changes(bat_priv, orig_node,
(struct tt_change *)(tt_response + 1),
tt_response->tt_data, tt_response->ttvn);
ntohs(tt_response->tt_data), tt_response->ttvn);
spin_lock_bh(&orig_node->tt_buff_lock);
kfree(orig_node->tt_buff);
......@@ -1727,7 +1781,8 @@ void handle_tt_response(struct bat_priv *bat_priv,
bat_dbg(DBG_TT, bat_priv,
"Received TT_RESPONSE from %pM for ttvn %d t_size: %d [%c]\n",
tt_response->src, tt_response->ttvn, tt_response->tt_data,
tt_response->src, tt_response->ttvn,
ntohs(tt_response->tt_data),
(tt_response->flags & TT_FULL_TABLE ? 'F' : '.'));
/* we should have never asked a backbone gw */
......@@ -1741,7 +1796,8 @@ void handle_tt_response(struct bat_priv *bat_priv,
if (tt_response->flags & TT_FULL_TABLE)
tt_fill_gtable(bat_priv, tt_response);
else
tt_update_changes(bat_priv, orig_node, tt_response->tt_data,
tt_update_changes(bat_priv, orig_node,
ntohs(tt_response->tt_data),
tt_response->ttvn,
(struct tt_change *)(tt_response + 1));
......@@ -1767,11 +1823,15 @@ void handle_tt_response(struct bat_priv *bat_priv,
int tt_init(struct bat_priv *bat_priv)
{
if (!tt_local_init(bat_priv))
return 0;
int ret;
if (!tt_global_init(bat_priv))
return 0;
ret = tt_local_init(bat_priv);
if (ret < 0)
return ret;
ret = tt_global_init(bat_priv);
if (ret < 0)
return ret;
tt_start_timer(bat_priv);
......@@ -1895,6 +1955,8 @@ static void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
"Sending ROAMING_ADV to %pM (client %pM) via %pM\n",
orig_node->orig, client, neigh_node->addr);
batadv_inc_counter(bat_priv, BAT_CNT_TT_ROAM_ADV_TX);
send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
ret = 0;
......@@ -2011,20 +2073,56 @@ static void tt_local_purge_pending_clients(struct bat_priv *bat_priv)
}
void tt_commit_changes(struct bat_priv *bat_priv)
static int tt_commit_changes(struct bat_priv *bat_priv,
unsigned char **packet_buff, int *packet_buff_len,
int packet_min_len)
{
uint16_t changed_num = tt_set_flags(bat_priv->tt_local_hash,
uint16_t changed_num = 0;
if (atomic_read(&bat_priv->tt_local_changes) < 1)
return -ENOENT;
changed_num = tt_set_flags(bat_priv->tt_local_hash,
TT_CLIENT_NEW, false);
/* all the reset entries have now to be effectively counted as local
* entries */
/* all reset entries have to be counted as local entries */
atomic_add(changed_num, &bat_priv->num_local_tt);
tt_local_purge_pending_clients(bat_priv);
bat_priv->tt_crc = batadv_tt_local_crc(bat_priv);
/* Increment the TTVN only once per OGM interval */
atomic_inc(&bat_priv->ttvn);
bat_dbg(DBG_TT, bat_priv, "Local changes committed, updating to ttvn %u\n",
(uint8_t)atomic_read(&bat_priv->ttvn));
bat_priv->tt_poss_change = false;
/* reset the sending counter */
atomic_set(&bat_priv->tt_ogm_append_cnt, TT_OGM_APPEND_MAX);
return tt_changes_fill_buff(bat_priv, packet_buff,
packet_buff_len, packet_min_len);
}
/* when calling this function (hard_iface == primary_if) has to be true */
int batadv_tt_append_diff(struct bat_priv *bat_priv,
unsigned char **packet_buff, int *packet_buff_len,
int packet_min_len)
{
int tt_num_changes;
/* if at least one change happened */
tt_num_changes = tt_commit_changes(bat_priv, packet_buff,
packet_buff_len, packet_min_len);
/* if the changes have been sent often enough */
if ((tt_num_changes < 0) &&
(!atomic_dec_not_zero(&bat_priv->tt_ogm_append_cnt))) {
tt_realloc_packet_buff(packet_buff, packet_buff_len,
packet_min_len, packet_min_len);
tt_num_changes = 0;
}
return tt_num_changes;
}
bool is_ap_isolated(struct bat_priv *bat_priv, uint8_t *src, uint8_t *dst)
......
......@@ -23,8 +23,6 @@
#define _NET_BATMAN_ADV_TRANSLATION_TABLE_H_
int tt_len(int changes_num);
int tt_changes_fill_buffer(struct bat_priv *bat_priv,
unsigned char *buff, int buff_len);
int tt_init(struct bat_priv *bat_priv);
void tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
int ifindex);
......@@ -41,18 +39,19 @@ void tt_global_del_orig(struct bat_priv *bat_priv,
struct orig_node *orig_node, const char *message);
struct orig_node *transtable_search(struct bat_priv *bat_priv,
const uint8_t *src, const uint8_t *addr);
uint16_t tt_local_crc(struct bat_priv *bat_priv);
void tt_free(struct bat_priv *bat_priv);
bool send_tt_response(struct bat_priv *bat_priv,
struct tt_query_packet *tt_request);
bool is_my_client(struct bat_priv *bat_priv, const uint8_t *addr);
void handle_tt_response(struct bat_priv *bat_priv,
struct tt_query_packet *tt_response);
void tt_commit_changes(struct bat_priv *bat_priv);
bool is_ap_isolated(struct bat_priv *bat_priv, uint8_t *src, uint8_t *dst);
void tt_update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
const unsigned char *tt_buff, uint8_t tt_num_changes,
uint8_t ttvn, uint16_t tt_crc);
int batadv_tt_append_diff(struct bat_priv *bat_priv,
unsigned char **packet_buff, int *packet_buff_len,
int packet_min_len);
bool tt_global_client_is_roaming(struct bat_priv *bat_priv, uint8_t *addr);
......
......@@ -148,9 +148,26 @@ struct bcast_duplist_entry {
};
#endif
enum bat_counters {
BAT_CNT_FORWARD,
BAT_CNT_FORWARD_BYTES,
BAT_CNT_MGMT_TX,
BAT_CNT_MGMT_TX_BYTES,
BAT_CNT_MGMT_RX,
BAT_CNT_MGMT_RX_BYTES,
BAT_CNT_TT_REQUEST_TX,
BAT_CNT_TT_REQUEST_RX,
BAT_CNT_TT_RESPONSE_TX,
BAT_CNT_TT_RESPONSE_RX,
BAT_CNT_TT_ROAM_ADV_TX,
BAT_CNT_TT_ROAM_ADV_RX,
BAT_CNT_NUM,
};
struct bat_priv {
atomic_t mesh_state;
struct net_device_stats stats;
uint64_t __percpu *bat_counters; /* Per cpu counters */
atomic_t aggregated_ogms; /* boolean */
atomic_t bonding; /* boolean */
atomic_t fragmentation; /* boolean */
......@@ -210,7 +227,7 @@ struct bat_priv {
spinlock_t vis_list_lock; /* protects vis_info::recv_list */
atomic_t num_local_tt;
/* Checksum of the local table, recomputed before sending a new OGM */
atomic_t tt_crc;
uint16_t tt_crc;
unsigned char *tt_buff;
int16_t tt_buff_len;
spinlock_t tt_buff_lock; /* protects tt_buff */
......@@ -388,8 +405,7 @@ struct bat_algo_ops {
/* called when primary interface is selected / changed */
void (*bat_primary_iface_set)(struct hard_iface *hard_iface);
/* prepare a new outgoing OGM for the send queue */
void (*bat_ogm_schedule)(struct hard_iface *hard_iface,
int tt_num_changes);
void (*bat_ogm_schedule)(struct hard_iface *hard_iface);
/* send scheduled OGM */
void (*bat_ogm_emit)(struct forw_packet *forw_packet);
};
......
......@@ -207,7 +207,6 @@ int vis_seq_print_text(struct seq_file *seq, void *offset)
int vis_server = atomic_read(&bat_priv->vis_mode);
size_t buff_pos, buf_size;
char *buff;
int compare;
primary_if = primary_if_get_selected(bat_priv);
if (!primary_if)
......@@ -228,14 +227,18 @@ int vis_seq_print_text(struct seq_file *seq, void *offset)
entries = (struct vis_info_entry *)
((char *)packet + sizeof(*packet));
vis_data_insert_interface(packet->vis_orig,
&vis_if_list, true);
for (j = 0; j < packet->entries; j++) {
if (entries[j].quality == 0)
continue;
compare =
compare_eth(entries[j].src, packet->vis_orig);
if (compare_eth(entries[j].src,
packet->vis_orig))
continue;
vis_data_insert_interface(entries[j].src,
&vis_if_list,
compare);
false);
}
hlist_for_each_entry(entry, pos, &vis_if_list, list) {
......@@ -276,14 +279,18 @@ int vis_seq_print_text(struct seq_file *seq, void *offset)
entries = (struct vis_info_entry *)
((char *)packet + sizeof(*packet));
vis_data_insert_interface(packet->vis_orig,
&vis_if_list, true);
for (j = 0; j < packet->entries; j++) {
if (entries[j].quality == 0)
continue;
compare =
compare_eth(entries[j].src, packet->vis_orig);
if (compare_eth(entries[j].src,
packet->vis_orig))
continue;
vis_data_insert_interface(entries[j].src,
&vis_if_list,
compare);
false);
}
hlist_for_each_entry(entry, pos, &vis_if_list, list) {
......@@ -626,7 +633,7 @@ static int generate_vis_packet(struct bat_priv *bat_priv)
best_tq = find_best_vis_server(bat_priv, info);
if (best_tq < 0)
return -1;
return best_tq;
}
for (i = 0; i < hash->size; i++) {
......@@ -878,7 +885,7 @@ int vis_init(struct bat_priv *bat_priv)
int hash_added;
if (bat_priv->vis_hash)
return 1;
return 0;
spin_lock_bh(&bat_priv->vis_hash_lock);
......@@ -929,7 +936,7 @@ int vis_init(struct bat_priv *bat_priv)
spin_unlock_bh(&bat_priv->vis_hash_lock);
start_vis_timer(bat_priv);
return 1;
return 0;
free_info:
kfree(bat_priv->my_vis_info);
......@@ -937,7 +944,7 @@ int vis_init(struct bat_priv *bat_priv)
err:
spin_unlock_bh(&bat_priv->vis_hash_lock);
vis_quit(bat_priv);
return 0;
return -ENOMEM;
}
/* Decrease the reference count on a hash item info */
......
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