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