batctl; branch, master, updated. v2011.2.0-31-g6a9ccfe
by postmaster@open-mesh.org
The following commit has been merged in the master branch:
commit 6a9ccfe25e09115d04248fa22028e3f89c639d90
Author: Marek Lindner <lindner_marek(a)yahoo.de>
Date: Sun Jun 26 15:32:57 2011 +0200
batctl: tcpdump - tt_data is an unsigned int value and should be printed as such
Signed-off-by: Marek Lindner <lindner_marek(a)yahoo.de>
diff --git a/tcpdump.c b/tcpdump.c
index 5500899..0e69431 100644
--- a/tcpdump.c
+++ b/tcpdump.c
@@ -284,7 +284,7 @@ static void dump_batman_tt(unsigned char *packet_buff, ssize_t buff_len, int rea
printf("BAT %s > ",
get_name_by_macaddr((struct ether_addr *)tt_query_packet->src, read_opt));
- printf("%s: TT %s, ttvn %d, %s %d, ttl %2d, v %d, flags [%c%c], length %zu\n",
+ printf("%s: TT %s, ttvn %d, %s %u, ttl %2d, v %d, flags [%c%c], length %zu\n",
get_name_by_macaddr((struct ether_addr *)tt_query_packet->dst, read_opt),
tt_desc, tt_query_packet->ttvn, tt_data, ntohs(tt_query_packet->tt_data),
tt_query_packet->ttl, tt_query_packet->version,
--
batctl
11 years, 7 months
batctl; branch, master, updated. v2011.2.0-30-g583dc48
by postmaster@open-mesh.org
The following commit has been merged in the master branch:
commit 583dc48e206a50b38e4039270247fc33bff10114
Author: Antonio Quartulli <ordex(a)autistici.org>
Date: Mon Jun 13 22:51:40 2011 +0200
batctl: unify flags for tt_change/tt_local_entry/tt_global_entry
The tt_local_entry structure now has a 'flags' field. This helps to
unify the flags format to all the client related structures (tt_global_entry
and tt_change). The 'never_purge' field is now encoded in the 'flags' one.
Moreover 'enum tt_change_flags' is now called 'enum tt_client_flags' and the
defined values apply to the tt_local_entry, tt_global_entry and the tt_change
'flags' field.
Signed-off-by: Antonio Quartulli <ordex(a)autistici.org>
diff --git a/packet.h b/packet.h
index c5f081d..8fd2fde 100644
--- a/packet.h
+++ b/packet.h
@@ -78,10 +78,11 @@ enum tt_query_flags {
TT_FULL_TABLE = 1 << 2
};
-/* TT_CHANGE flags */
-enum tt_change_flags {
- TT_CHANGE_DEL = 0x01,
- TT_CLIENT_ROAM = 0x02
+/* TT_CLIENT flags */
+enum tt_client_flags {
+ TT_CLIENT_DEL = 0x01,
+ TT_CLIENT_ROAM = 0x02,
+ TT_CLIENT_NOPURGE = 0x04
};
struct batman_packet {
--
batctl
11 years, 7 months
batman-adv; branch, master, updated. v2011.2.0-58-g7d23eb0
by postmaster@open-mesh.org
The following commit has been merged in the master branch:
commit 7d23eb00809b118b0f1973c65b2c63b800969df5
Author: Antonio Quartulli <ordex(a)autistici.org>
Date: Sat Jun 25 19:09:12 2011 +0200
batman-adv: add_bcast_packet_to_list() takes the sending delay as parameter
In order to make possible to use the broadcast list for delayed sendings
the "delay" parameter is now provided instead of using 1 as hardcoded
value.
Signed-off-by: Antonio Quartulli <ordex(a)autistici.org>
diff --git a/routing.c b/routing.c
index 0ce090c..2cb98be 100644
--- a/routing.c
+++ b/routing.c
@@ -1677,7 +1677,7 @@ int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
spin_unlock_bh(&orig_node->bcast_seqno_lock);
/* rebroadcast packet */
- add_bcast_packet_to_list(bat_priv, skb);
+ add_bcast_packet_to_list(bat_priv, skb, 1);
/* broadcast for me */
interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size);
diff --git a/send.c b/send.c
index 7a2f082..2f62b2e 100644
--- a/send.c
+++ b/send.c
@@ -455,7 +455,7 @@ static void _add_bcast_packet_to_list(struct bat_priv *bat_priv,
* The skb is not consumed, so the caller should make sure that the
* skb is freed. */
int add_bcast_packet_to_list(struct bat_priv *bat_priv,
- const struct sk_buff *skb)
+ const struct sk_buff *skb, unsigned long delay)
{
struct hard_iface *primary_if = NULL;
struct forw_packet *forw_packet;
@@ -492,7 +492,7 @@ int add_bcast_packet_to_list(struct bat_priv *bat_priv,
/* how often did we send the bcast packet ? */
forw_packet->num_packets = 0;
- _add_bcast_packet_to_list(bat_priv, forw_packet, 1);
+ _add_bcast_packet_to_list(bat_priv, forw_packet, delay);
return NETDEV_TX_OK;
packet_free:
diff --git a/send.h b/send.h
index 633224a..1f2d1e8 100644
--- a/send.h
+++ b/send.h
@@ -31,7 +31,7 @@ void schedule_forward_packet(struct orig_node *orig_node,
int directlink,
struct hard_iface *if_outgoing);
int add_bcast_packet_to_list(struct bat_priv *bat_priv,
- const struct sk_buff *skb);
+ const struct sk_buff *skb, unsigned long delay);
void send_outstanding_bat_packet(struct work_struct *work);
void purge_outstanding_packets(struct bat_priv *bat_priv,
const struct hard_iface *hard_iface);
diff --git a/soft-interface.c b/soft-interface.c
index 2dcdbb7..3f20332 100644
--- a/soft-interface.c
+++ b/soft-interface.c
@@ -634,7 +634,7 @@ static int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
bcast_packet->seqno =
htonl(atomic_inc_return(&bat_priv->bcast_seqno));
- add_bcast_packet_to_list(bat_priv, skb);
+ add_bcast_packet_to_list(bat_priv, skb, 1);
/* a copy is stored in the bcast list, therefore removing
* the original skb. */
--
batman-adv
11 years, 7 months
batman-adv; branch, master, updated. v2011.2.0-57-g763a3c2
by postmaster@open-mesh.org
The following commit has been merged in the master branch:
commit 763a3c292fc184e34128bff51326b022556f74f0
Author: Antonio Quartulli <ordex(a)autistici.org>
Date: Fri Jun 17 16:11:27 2011 +0200
batman-adv: unify flags for tt_change/tt_local_entry/tt_global_entry
The tt_local_entry structure now has a 'flags' field. This helps to
unify the flags format to all the client related structures (tt_global_entry
and tt_change). The 'never_purge' field is now encoded in the 'flags' one.
Moreover 'enum tt_change_flags' is now called 'enum tt_client_flags' and the
defined values apply to the tt_local_entry, tt_global_entry and the tt_change
'flags' field.
Signed-off-by: Antonio Quartulli <ordex(a)autistici.org>
diff --git a/packet.h b/packet.h
index c5f081d..8fd2fde 100644
--- a/packet.h
+++ b/packet.h
@@ -78,10 +78,11 @@ enum tt_query_flags {
TT_FULL_TABLE = 1 << 2
};
-/* TT_CHANGE flags */
-enum tt_change_flags {
- TT_CHANGE_DEL = 0x01,
- TT_CLIENT_ROAM = 0x02
+/* TT_CLIENT flags */
+enum tt_client_flags {
+ TT_CLIENT_DEL = 0x01,
+ TT_CLIENT_ROAM = 0x02,
+ TT_CLIENT_NOPURGE = 0x04
};
struct batman_packet {
diff --git a/translation-table.c b/translation-table.c
index 5f1fcd5..4208dc7 100644
--- a/translation-table.c
+++ b/translation-table.c
@@ -211,13 +211,12 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr)
memcpy(tt_local_entry->addr, addr, ETH_ALEN);
tt_local_entry->last_seen = jiffies;
+ tt_local_entry->flags = NO_FLAGS;
atomic_set(&tt_local_entry->refcount, 2);
/* the batman interface mac address should never be purged */
if (compare_eth(addr, soft_iface->dev_addr))
- tt_local_entry->never_purge = 1;
- else
- tt_local_entry->never_purge = 0;
+ tt_local_entry->flags |= TT_CLIENT_NOPURGE;
hash_add(bat_priv->tt_local_hash, compare_ltt, choose_orig,
tt_local_entry, &tt_local_entry->hash_entry);
@@ -387,7 +386,7 @@ void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr,
if (!tt_local_entry)
goto out;
- tt_local_event(bat_priv, TT_CHANGE_DEL, tt_local_entry->addr, roaming);
+ tt_local_event(bat_priv, TT_CLIENT_DEL, tt_local_entry->addr, roaming);
tt_local_del(bat_priv, tt_local_entry, message);
out:
if (tt_local_entry)
@@ -410,14 +409,14 @@ static void tt_local_purge(struct bat_priv *bat_priv)
spin_lock_bh(list_lock);
hlist_for_each_entry_safe(tt_local_entry, node, node_tmp,
head, hash_entry) {
- if (tt_local_entry->never_purge)
+ if (tt_local_entry->flags & TT_CLIENT_NOPURGE)
continue;
if (!is_out_of_time(tt_local_entry->last_seen,
TT_LOCAL_TIMEOUT * 1000))
continue;
- tt_local_event(bat_priv, TT_CHANGE_DEL,
+ tt_local_event(bat_priv, TT_CLIENT_DEL,
tt_local_entry->addr, false);
atomic_dec(&bat_priv->num_local_tt);
bat_dbg(DBG_TT, bat_priv, "Deleting local "
@@ -1335,7 +1334,7 @@ static void _tt_update_changes(struct bat_priv *bat_priv,
int i;
for (i = 0; i < tt_num_changes; i++) {
- if ((tt_change + i)->flags & TT_CHANGE_DEL)
+ if ((tt_change + i)->flags & TT_CLIENT_DEL)
tt_global_del(bat_priv, orig_node,
(tt_change + i)->addr,
"tt removed by changes",
diff --git a/translation-table.h b/translation-table.h
index 1cd2d39..460e583 100644
--- a/translation-table.h
+++ b/translation-table.h
@@ -30,8 +30,7 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr);
void tt_local_remove(struct bat_priv *bat_priv,
const uint8_t *addr, const char *message, bool roaming);
int tt_local_seq_print_text(struct seq_file *seq, void *offset);
-void tt_global_add_orig(struct bat_priv *bat_priv,
- struct orig_node *orig_node,
+void tt_global_add_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
const unsigned char *tt_buff, int tt_buff_len);
int tt_global_add(struct bat_priv *bat_priv,
struct orig_node *orig_node, const unsigned char *addr,
diff --git a/types.h b/types.h
index 85cf122..582283a 100644
--- a/types.h
+++ b/types.h
@@ -224,7 +224,7 @@ struct socket_packet {
struct tt_local_entry {
uint8_t addr[ETH_ALEN];
unsigned long last_seen;
- char never_purge;
+ uint8_t flags;
atomic_t refcount;
struct rcu_head rcu;
struct hlist_node hash_entry;
--
batman-adv
11 years, 7 months
linux integration; annotated tag, v3.0-rc4, created. v3.0-rc4
by postmaster@open-mesh.org
The annotated tag, v3.0-rc4 has been created
at 4921f03412bd0a91cb242b259618b13dfae1acf6 (tag)
tagging 56299378726d5f2ba8d3c8cbbd13cb280ba45e4f (commit)
replaces v3.0-rc3
tagged by Linus Torvalds
on Mon Jun 20 20:26:00 2011 -0700
- Shortlog ------------------------------------------------------------
Linux 3.0-rc4
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
iEYEABECAAYFAk4AD0wACgkQF3YsRnbiHLswHQCeMsYuMGdmVa/y/Zup6gRH7ZLF
QT8An1U6pBqOIH3oFForu7bunoLjEcwm
=ifU/
-----END PGP SIGNATURE-----
-----------------------------------------------------------------------
--
linux integration
11 years, 7 months
linux integration; branch, merge/master, updated. v3.0-rc1-1066-gecc9b78
by postmaster@open-mesh.org
The following commit has been merged in the merge/master branch:
commit ecc9b7898e87231069fd892b496333dcd7ad46b6
Merge: 030a84f1d8c601ed2998e6ae9ba3e8a8ba4c00d9 434e765c6eee7a39ca326577e3fcc007a2a9d2db
Author: Sven Eckelmann <sven(a)narfation.org>
Date: Sun Jun 19 21:12:48 2011 +0200
Merge remote-tracking branch 'origin/standalone/next' into merge/master
Conflicts:
net/batman-adv/CHANGELOG
net/batman-adv/README
net/batman-adv/compat.c
net/batman-adv/compat.h
diff --combined net/batman-adv/Kconfig
index 6c051ad,0000000..2b68d06
mode 100644,000000..100644
--- a/net/batman-adv/Kconfig
+++ b/net/batman-adv/Kconfig
@@@ -1,25 -1,0 +1,26 @@@
+#
+# B.A.T.M.A.N meshing protocol
+#
+
+config BATMAN_ADV
+ tristate "B.A.T.M.A.N. Advanced Meshing Protocol"
+ depends on NET
++ select CRC16
+ default n
+ ---help---
+
+ B.A.T.M.A.N. (better approach to mobile ad-hoc networking) is
+ a routing protocol for multi-hop ad-hoc mesh networks. The
+ networks may be wired or wireless. See
+ http://www.open-mesh.org/ for more information and user space
+ tools.
+
+config BATMAN_ADV_DEBUG
+ bool "B.A.T.M.A.N. debugging"
+ depends on BATMAN_ADV != n
+ ---help---
+
+ This is an option for use by developers; most people should
+ say N here. This enables compilation of support for
+ outputting debugging information to the kernel log. The
+ output is controlled via the module parameter debug.
diff --combined net/batman-adv/aggregation.c
index b41f25b,c583e04..c583e04
--- a/net/batman-adv/aggregation.c
+++ b/net/batman-adv/aggregation.c
@@@ -20,17 -20,12 +20,12 @@@
*/
#include "main.h"
+ #include "translation-table.h"
#include "aggregation.h"
#include "send.h"
#include "routing.h"
#include "hard-interface.h"
- /* calculate the size of the tt information for a given packet */
- static int tt_len(const struct batman_packet *batman_packet)
- {
- return batman_packet->num_tt * ETH_ALEN;
- }
-
/* return true if new_packet can be aggregated with forw_packet */
static bool can_aggregate_with(const struct batman_packet *new_batman_packet,
int packet_len,
@@@ -151,7 -146,7 +146,7 @@@ static void new_aggregated_packet(cons
forw_packet_aggr->own = own_packet;
forw_packet_aggr->if_incoming = if_incoming;
forw_packet_aggr->num_packets = 0;
- forw_packet_aggr->direct_link_flags = 0;
+ forw_packet_aggr->direct_link_flags = NO_FLAGS;
forw_packet_aggr->send_time = send_time;
/* save packet direct link flag status */
@@@ -195,7 -190,7 +190,7 @@@ static void aggregate(struct forw_packe
void add_bat_packet_to_list(struct bat_priv *bat_priv,
unsigned char *packet_buff, int packet_len,
- struct hard_iface *if_incoming, char own_packet,
+ struct hard_iface *if_incoming, int own_packet,
unsigned long send_time)
{
/**
@@@ -264,18 -259,20 +259,20 @@@ void receive_aggr_bat_packet(const stru
batman_packet = (struct batman_packet *)packet_buff;
do {
- /* network to host order for our 32bit seqno, and the
- orig_interval. */
+ /* network to host order for our 32bit seqno and the
+ orig_interval */
batman_packet->seqno = ntohl(batman_packet->seqno);
+ batman_packet->tt_crc = ntohs(batman_packet->tt_crc);
tt_buff = packet_buff + buff_pos + BAT_PACKET_LEN;
- receive_bat_packet(ethhdr, batman_packet,
- tt_buff, tt_len(batman_packet),
- if_incoming);
- buff_pos += BAT_PACKET_LEN + tt_len(batman_packet);
+ receive_bat_packet(ethhdr, batman_packet, tt_buff, if_incoming);
+
+ buff_pos += BAT_PACKET_LEN +
+ tt_len(batman_packet->tt_num_changes);
+
batman_packet = (struct batman_packet *)
(packet_buff + buff_pos);
} while (aggregated_packet(buff_pos, packet_len,
- batman_packet->num_tt));
+ batman_packet->tt_num_changes));
}
diff --combined net/batman-adv/aggregation.h
index fedeb8d,216337b..216337b
--- a/net/batman-adv/aggregation.h
+++ b/net/batman-adv/aggregation.h
@@@ -25,9 -25,11 +25,11 @@@
#include "main.h"
/* is there another aggregated packet here? */
- static inline int aggregated_packet(int buff_pos, int packet_len, int num_tt)
+ static inline int aggregated_packet(int buff_pos, int packet_len,
+ int tt_num_changes)
{
- int next_buff_pos = buff_pos + BAT_PACKET_LEN + (num_tt * ETH_ALEN);
+ int next_buff_pos = buff_pos + BAT_PACKET_LEN + (tt_num_changes *
+ sizeof(struct tt_change));
return (next_buff_pos <= packet_len) &&
(next_buff_pos <= MAX_AGGREGATION_BYTES);
@@@ -35,7 -37,7 +37,7 @@@
void add_bat_packet_to_list(struct bat_priv *bat_priv,
unsigned char *packet_buff, int packet_len,
- struct hard_iface *if_incoming, char own_packet,
+ struct hard_iface *if_incoming, int own_packet,
unsigned long send_time);
void receive_aggr_bat_packet(const struct ethhdr *ethhdr,
unsigned char *packet_buff, int packet_len,
diff --combined net/batman-adv/bat_sysfs.c
index 6f70560,cd15deb..cd15deb
--- a/net/batman-adv/bat_sysfs.c
+++ b/net/batman-adv/bat_sysfs.c
@@@ -28,9 -28,31 +28,31 @@@
#include "gateway_client.h"
#include "vis.h"
- #define to_dev(obj) container_of(obj, struct device, kobj)
- #define kobj_to_netdev(obj) to_net_dev(to_dev(obj->parent))
- #define kobj_to_batpriv(obj) netdev_priv(kobj_to_netdev(obj))
+ static struct net_device *kobj_to_netdev(struct kobject *obj)
+ {
+ struct device *dev = container_of(obj->parent, struct device, kobj);
+ return to_net_dev(dev);
+ }
+
+ static struct bat_priv *kobj_to_batpriv(struct kobject *obj)
+ {
+ struct net_device *net_dev = kobj_to_netdev(obj);
+ return netdev_priv(net_dev);
+ }
+
+ #define UEV_TYPE_VAR "BATTYPE="
+ #define UEV_ACTION_VAR "BATACTION="
+ #define UEV_DATA_VAR "BATDATA="
+
+ static char *uev_action_str[] = {
+ "add",
+ "del",
+ "change"
+ };
+
+ static char *uev_type_str[] = {
+ "gw"
+ };
/* Use this, if you have customized show and store functions */
#define BAT_ATTR(_name, _mode, _show, _store) \
@@@ -367,7 -389,7 +389,7 @@@ BAT_ATTR_UINT(gw_sel_class, S_IRUGO | S
static BAT_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, show_gw_bwidth,
store_gw_bwidth);
#ifdef CONFIG_BATMAN_ADV_DEBUG
- BAT_ATTR_UINT(log_level, S_IRUGO | S_IWUSR, 0, 3, NULL);
+ BAT_ATTR_UINT(log_level, S_IRUGO | S_IWUSR, 0, 7, NULL);
#endif
static struct bat_attribute *mesh_attrs[] = {
@@@ -593,3 -615,60 +615,60 @@@ void sysfs_del_hardif(struct kobject **
kobject_put(*hardif_obj);
*hardif_obj = NULL;
}
+
+ int throw_uevent(struct bat_priv *bat_priv, enum uev_type type,
+ enum uev_action action, const char *data)
+ {
+ int ret = -1;
+ struct hard_iface *primary_if = NULL;
+ struct kobject *bat_kobj;
+ char *uevent_env[4] = { NULL, NULL, NULL, NULL };
+
+ primary_if = primary_if_get_selected(bat_priv);
+ if (!primary_if)
+ goto out;
+
+ bat_kobj = &primary_if->soft_iface->dev.kobj;
+
+ uevent_env[0] = kmalloc(strlen(UEV_TYPE_VAR) +
+ strlen(uev_type_str[type]) + 1,
+ GFP_ATOMIC);
+ if (!uevent_env[0])
+ goto out;
+
+ sprintf(uevent_env[0], "%s%s", UEV_TYPE_VAR, uev_type_str[type]);
+
+ uevent_env[1] = kmalloc(strlen(UEV_ACTION_VAR) +
+ strlen(uev_action_str[action]) + 1,
+ GFP_ATOMIC);
+ if (!uevent_env[1])
+ goto out;
+
+ sprintf(uevent_env[1], "%s%s", UEV_ACTION_VAR, uev_action_str[action]);
+
+ /* If the event is DEL, ignore the data field */
+ if (action != UEV_DEL) {
+ uevent_env[2] = kmalloc(strlen(UEV_DATA_VAR) +
+ strlen(data) + 1, GFP_ATOMIC);
+ if (!uevent_env[2])
+ goto out;
+
+ sprintf(uevent_env[2], "%s%s", UEV_DATA_VAR, data);
+ }
+
+ ret = kobject_uevent_env(bat_kobj, KOBJ_CHANGE, uevent_env);
+ out:
+ kfree(uevent_env[0]);
+ kfree(uevent_env[1]);
+ kfree(uevent_env[2]);
+
+ if (primary_if)
+ hardif_free_ref(primary_if);
+
+ if (ret)
+ bat_dbg(DBG_BATMAN, bat_priv, "Impossible to send "
+ "uevent for (%s,%s,%s) event (err: %d)\n",
+ uev_type_str[type], uev_action_str[action],
+ (action == UEV_DEL ? "NULL" : data), ret);
+ return ret;
+ }
diff --combined net/batman-adv/bat_sysfs.h
index 02f1fa7,a3f75a7..a3f75a7
--- a/net/batman-adv/bat_sysfs.h
+++ b/net/batman-adv/bat_sysfs.h
@@@ -38,5 -38,7 +38,7 @@@ int sysfs_add_meshif(struct net_device
void sysfs_del_meshif(struct net_device *dev);
int sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev);
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);
#endif /* _NET_BATMAN_ADV_SYSFS_H_ */
diff --combined net/batman-adv/bitarray.c
index 700ee4f,c1f4bfc..c1f4bfc
--- a/net/batman-adv/bitarray.c
+++ b/net/batman-adv/bitarray.c
@@@ -26,8 -26,8 +26,8 @@@
/* returns true if the corresponding bit in the given seq_bits indicates true
* and curr_seqno is within range of last_seqno */
- uint8_t get_bit_status(const unsigned long *seq_bits, uint32_t last_seqno,
- uint32_t curr_seqno)
+ int get_bit_status(const unsigned long *seq_bits, uint32_t last_seqno,
+ uint32_t curr_seqno)
{
int32_t diff, word_offset, word_num;
@@@ -127,8 -127,8 +127,8 @@@ static void bit_reset_window(unsigned l
* 1 if the window was moved (either new or very old)
* 0 if the window was not moved/shifted.
*/
- char bit_get_packet(void *priv, unsigned long *seq_bits,
- int32_t seq_num_diff, int8_t set_mark)
+ int bit_get_packet(void *priv, unsigned long *seq_bits,
+ int32_t seq_num_diff, int set_mark)
{
struct bat_priv *bat_priv = priv;
diff --combined net/batman-adv/bitarray.h
index e32eb2d,9c04422..9c04422
--- a/net/batman-adv/bitarray.h
+++ b/net/batman-adv/bitarray.h
@@@ -26,8 -26,8 +26,8 @@@
/* returns true if the corresponding bit in the given seq_bits indicates true
* and curr_seqno is within range of last_seqno */
- uint8_t get_bit_status(const unsigned long *seq_bits, uint32_t last_seqno,
- uint32_t curr_seqno);
+ int get_bit_status(const unsigned long *seq_bits, uint32_t last_seqno,
+ uint32_t curr_seqno);
/* turn corresponding bit on, so we can remember that we got the packet */
void bit_mark(unsigned long *seq_bits, int32_t n);
@@@ -35,8 -35,8 +35,8 @@@
/* receive and process one packet, returns 1 if received seq_num is considered
* new, 0 if old */
- char bit_get_packet(void *priv, unsigned long *seq_bits,
- int32_t seq_num_diff, int8_t set_mark);
+ int bit_get_packet(void *priv, unsigned long *seq_bits,
+ int32_t seq_num_diff, int set_mark);
/* count the hamming weight, how many good packets did we receive? */
int bit_packet_count(const unsigned long *seq_bits);
diff --combined net/batman-adv/gateway_client.c
index ab597c4,8b25b52..8b25b52
--- a/net/batman-adv/gateway_client.c
+++ b/net/batman-adv/gateway_client.c
@@@ -20,15 -20,22 +20,22 @@@
*/
#include "main.h"
+ #include "bat_sysfs.h"
#include "gateway_client.h"
#include "gateway_common.h"
#include "hard-interface.h"
#include "originator.h"
+ #include "routing.h"
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/udp.h>
#include <linux/if_vlan.h>
+ /* This is the offset of the options field in a dhcp packet starting at
+ * the beginning of the dhcp header */
+ #define DHCP_OPTIONS_OFFSET 240
+ #define DHCP_REQUEST 3
+
static void gw_node_free_ref(struct gw_node *gw_node)
{
if (atomic_dec_and_test(&gw_node->refcount))
@@@ -97,40 -104,19 +104,19 @@@ static void gw_select(struct bat_priv *
void gw_deselect(struct bat_priv *bat_priv)
{
- gw_select(bat_priv, NULL);
+ atomic_set(&bat_priv->gw_reselect, 1);
}
- void gw_election(struct bat_priv *bat_priv)
+ static struct gw_node *gw_get_best_gw_node(struct bat_priv *bat_priv)
{
- struct hlist_node *node;
- struct gw_node *gw_node, *curr_gw = NULL, *curr_gw_tmp = NULL;
struct neigh_node *router;
- uint8_t max_tq = 0;
+ struct hlist_node *node;
+ struct gw_node *gw_node, *curr_gw = NULL;
uint32_t max_gw_factor = 0, tmp_gw_factor = 0;
+ uint8_t max_tq = 0;
int down, up;
- /**
- * The batman daemon checks here if we already passed a full originator
- * cycle in order to make sure we don't choose the first gateway we
- * hear about. This check is based on the daemon's uptime which we
- * don't have.
- **/
- if (atomic_read(&bat_priv->gw_mode) != GW_MODE_CLIENT)
- return;
-
- curr_gw = gw_get_selected_gw_node(bat_priv);
- if (curr_gw)
- goto out;
-
rcu_read_lock();
- if (hlist_empty(&bat_priv->gw_list)) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "Removing selected gateway - "
- "no gateway in range\n");
- gw_deselect(bat_priv);
- goto unlock;
- }
-
hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
if (gw_node->deleted)
continue;
@@@ -139,6 -125,9 +125,9 @@@
if (!router)
continue;
+ if (!atomic_inc_not_zero(&gw_node->refcount))
+ goto next;
+
switch (atomic_read(&bat_priv->gw_sel_class)) {
case 1: /* fast connection */
gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags,
@@@ -151,8 -140,12 +140,12 @@@
if ((tmp_gw_factor > max_gw_factor) ||
((tmp_gw_factor == max_gw_factor) &&
- (router->tq_avg > max_tq)))
- curr_gw_tmp = gw_node;
+ (router->tq_avg > max_tq))) {
+ if (curr_gw)
+ gw_node_free_ref(curr_gw);
+ curr_gw = gw_node;
+ atomic_inc(&curr_gw->refcount);
+ }
break;
default: /**
@@@ -163,8 -156,12 +156,12 @@@
* soon as a better gateway appears which has
* $routing_class more tq points)
**/
- if (router->tq_avg > max_tq)
- curr_gw_tmp = gw_node;
+ if (router->tq_avg > max_tq) {
+ if (curr_gw)
+ gw_node_free_ref(curr_gw);
+ curr_gw = gw_node;
+ atomic_inc(&curr_gw->refcount);
+ }
break;
}
@@@ -174,42 -171,81 +171,81 @@@
if (tmp_gw_factor > max_gw_factor)
max_gw_factor = tmp_gw_factor;
+ gw_node_free_ref(gw_node);
+
+ next:
neigh_node_free_ref(router);
}
+ rcu_read_unlock();
- if (curr_gw != curr_gw_tmp) {
- router = orig_node_get_router(curr_gw_tmp->orig_node);
- if (!router)
- goto unlock;
+ return curr_gw;
+ }
- if ((curr_gw) && (!curr_gw_tmp))
- bat_dbg(DBG_BATMAN, bat_priv,
- "Removing selected gateway - "
- "no gateway in range\n");
- else if ((!curr_gw) && (curr_gw_tmp))
- bat_dbg(DBG_BATMAN, bat_priv,
- "Adding route to gateway %pM "
- "(gw_flags: %i, tq: %i)\n",
- curr_gw_tmp->orig_node->orig,
- curr_gw_tmp->orig_node->gw_flags,
- router->tq_avg);
- else
- bat_dbg(DBG_BATMAN, bat_priv,
- "Changing route to gateway %pM "
- "(gw_flags: %i, tq: %i)\n",
- curr_gw_tmp->orig_node->orig,
- curr_gw_tmp->orig_node->gw_flags,
- router->tq_avg);
+ void gw_election(struct bat_priv *bat_priv)
+ {
+ struct gw_node *curr_gw = NULL, *next_gw = NULL;
+ struct neigh_node *router = NULL;
+ char gw_addr[18] = { '\0' };
- neigh_node_free_ref(router);
- gw_select(bat_priv, curr_gw_tmp);
+ /**
+ * The batman daemon checks here if we already passed a full originator
+ * cycle in order to make sure we don't choose the first gateway we
+ * hear about. This check is based on the daemon's uptime which we
+ * don't have.
+ **/
+ if (atomic_read(&bat_priv->gw_mode) != GW_MODE_CLIENT)
+ goto out;
+
+ if (!atomic_dec_not_zero(&bat_priv->gw_reselect))
+ goto out;
+
+ curr_gw = gw_get_selected_gw_node(bat_priv);
+
+ next_gw = gw_get_best_gw_node(bat_priv);
+
+ if (curr_gw == next_gw)
+ goto out;
+
+ if (next_gw) {
+ sprintf(gw_addr, "%pM", next_gw->orig_node->orig);
+
+ router = orig_node_get_router(next_gw->orig_node);
+ if (!router) {
+ gw_deselect(bat_priv);
+ goto out;
+ }
}
- unlock:
- rcu_read_unlock();
+ if ((curr_gw) && (!next_gw)) {
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "Removing selected gateway - no gateway in range\n");
+ throw_uevent(bat_priv, UEV_GW, UEV_DEL, NULL);
+ } else if ((!curr_gw) && (next_gw)) {
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "Adding route to gateway %pM (gw_flags: %i, tq: %i)\n",
+ next_gw->orig_node->orig,
+ next_gw->orig_node->gw_flags,
+ router->tq_avg);
+ throw_uevent(bat_priv, UEV_GW, UEV_ADD, gw_addr);
+ } else {
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "Changing route to gateway %pM "
+ "(gw_flags: %i, tq: %i)\n",
+ next_gw->orig_node->orig,
+ next_gw->orig_node->gw_flags,
+ router->tq_avg);
+ throw_uevent(bat_priv, UEV_GW, UEV_CHANGE, gw_addr);
+ }
+
+ gw_select(bat_priv, next_gw);
+
out:
if (curr_gw)
gw_node_free_ref(curr_gw);
+ if (next_gw)
+ gw_node_free_ref(next_gw);
+ if (router)
+ neigh_node_free_ref(router);
}
void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node)
@@@ -322,7 -358,7 +358,7 @@@ void gw_node_update(struct bat_priv *ba
gw_node->deleted = 0;
- if (new_gwflags == 0) {
+ if (new_gwflags == NO_FLAGS) {
gw_node->deleted = jiffies;
bat_dbg(DBG_BATMAN, bat_priv,
"Gateway %pM removed from gateway list\n",
@@@ -335,7 -371,7 +371,7 @@@
goto unlock;
}
- if (new_gwflags == 0)
+ if (new_gwflags == NO_FLAGS)
goto unlock;
gw_node_add(bat_priv, orig_node, new_gwflags);
@@@ -352,7 -388,7 +388,7 @@@ unlock
void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node)
{
- return gw_node_update(bat_priv, orig_node, 0);
+ gw_node_update(bat_priv, orig_node, 0);
}
void gw_node_purge(struct bat_priv *bat_priv)
@@@ -360,7 -396,7 +396,7 @@@
struct gw_node *gw_node, *curr_gw;
struct hlist_node *node, *node_tmp;
unsigned long timeout = 2 * PURGE_TIMEOUT * HZ;
- char do_deselect = 0;
+ int do_deselect = 0;
curr_gw = gw_get_selected_gw_node(bat_priv);
@@@ -479,14 -515,75 +515,75 @@@ out
return ret;
}
- int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
+ static bool is_type_dhcprequest(struct sk_buff *skb, int header_len)
+ {
+ int ret = false;
+ unsigned char *p;
+ int pkt_len;
+
+ if (skb_linearize(skb) < 0)
+ goto out;
+
+ pkt_len = skb_headlen(skb);
+
+ if (pkt_len < header_len + DHCP_OPTIONS_OFFSET + 1)
+ goto out;
+
+ p = skb->data + header_len + DHCP_OPTIONS_OFFSET;
+ pkt_len -= header_len + DHCP_OPTIONS_OFFSET + 1;
+
+ /* Access the dhcp option lists. Each entry is made up by:
+ * - octect 1: option type
+ * - octect 2: option data len (only if type != 255 and 0)
+ * - octect 3: option data */
+ while (*p != 255 && !ret) {
+ /* p now points to the first octect: option type */
+ if (*p == 53) {
+ /* type 53 is the message type option.
+ * Jump the len octect and go to the data octect */
+ if (pkt_len < 2)
+ goto out;
+ p += 2;
+
+ /* check if the message type is what we need */
+ if (*p == DHCP_REQUEST)
+ ret = true;
+ break;
+ } else if (*p == 0) {
+ /* option type 0 (padding), just go forward */
+ if (pkt_len < 1)
+ goto out;
+ pkt_len--;
+ p++;
+ } else {
+ /* This is any other option. So we get the length... */
+ if (pkt_len < 1)
+ goto out;
+ pkt_len--;
+ p++;
+
+ /* ...and then we jump over the data */
+ if (pkt_len < *p)
+ goto out;
+ pkt_len -= *p;
+ p += (*p);
+ }
+ }
+ out:
+ return ret;
+ }
+
+ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb,
+ struct orig_node *old_gw)
{
struct ethhdr *ethhdr;
struct iphdr *iphdr;
struct ipv6hdr *ipv6hdr;
struct udphdr *udphdr;
struct gw_node *curr_gw;
+ struct neigh_node *neigh_curr = NULL, *neigh_old = NULL;
unsigned int header_len = 0;
+ int ret = 1;
if (atomic_read(&bat_priv->gw_mode) == GW_MODE_OFF)
return 0;
@@@ -554,7 -651,30 +651,30 @@@
if (!curr_gw)
return 0;
+ /* If old_gw != NULL then this packet is unicast.
+ * So, at this point we have to check the message type: if it is a
+ * DHCPREQUEST we have to decide whether to drop it or not */
+ if (old_gw && curr_gw->orig_node != old_gw) {
+ if (is_type_dhcprequest(skb, header_len)) {
+ /* If the dhcp packet has been sent to a different gw,
+ * we have to evaluate whether the old gw is still
+ * reliable enough */
+ neigh_curr = find_router(bat_priv, curr_gw->orig_node,
+ NULL);
+ neigh_old = find_router(bat_priv, old_gw, NULL);
+ if (!neigh_curr || !neigh_old)
+ goto free_neigh;
+ if (neigh_curr->tq_avg - neigh_old->tq_avg <
+ GW_THRESHOLD)
+ ret = -1;
+ }
+ }
+ free_neigh:
+ if (neigh_old)
+ neigh_node_free_ref(neigh_old);
+ if (neigh_curr)
+ neigh_node_free_ref(neigh_curr);
if (curr_gw)
gw_node_free_ref(curr_gw);
- return 1;
+ return ret;
}
diff --combined net/batman-adv/gateway_client.h
index 1ce8c60,b9b983c..b9b983c
--- a/net/batman-adv/gateway_client.h
+++ b/net/batman-adv/gateway_client.h
@@@ -31,6 -31,7 +31,7 @@@ void gw_node_update(struct bat_priv *ba
void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node);
void gw_node_purge(struct bat_priv *bat_priv);
int gw_client_seq_print_text(struct seq_file *seq, void *offset);
- int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb);
+ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb,
+ struct orig_node *old_gw);
#endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */
diff --combined net/batman-adv/gateway_common.c
index ed3bd36,18661af..18661af
--- a/net/batman-adv/gateway_common.c
+++ b/net/batman-adv/gateway_common.c
@@@ -61,9 -61,9 +61,9 @@@ static void kbit_to_gw_bandwidth(int do
/* returns the up and downspeeds in kbit, calculated from the class */
void gw_bandwidth_to_kbit(uint8_t gw_srv_class, int *down, int *up)
{
- char sbit = (gw_srv_class & 0x80) >> 7;
- char dpart = (gw_srv_class & 0x78) >> 3;
- char upart = (gw_srv_class & 0x07);
+ int sbit = (gw_srv_class & 0x80) >> 7;
+ int dpart = (gw_srv_class & 0x78) >> 3;
+ int upart = (gw_srv_class & 0x07);
if (!gw_srv_class) {
*down = 0;
@@@ -97,7 -97,7 +97,7 @@@ static bool parse_gw_bandwidth(struct n
*tmp_ptr = '\0';
}
- ret = strict_strtoul(buff, 10, &ldown);
+ ret = strict_strtol(buff, 10, &ldown);
if (ret) {
bat_err(net_dev,
"Download speed of gateway mode invalid: %s\n",
@@@ -122,7 -122,7 +122,7 @@@
*tmp_ptr = '\0';
}
- ret = strict_strtoul(slash_ptr + 1, 10, &lup);
+ ret = strict_strtol(slash_ptr + 1, 10, &lup);
if (ret) {
bat_err(net_dev,
"Upload speed of gateway mode invalid: "
diff --combined net/batman-adv/hard-interface.c
index a3fbfb5,db7aacf..db7aacf
--- a/net/batman-adv/hard-interface.c
+++ b/net/batman-adv/hard-interface.c
@@@ -152,12 -152,6 +152,6 @@@ static void primary_if_select(struct ba
batman_packet->ttl = TTL;
primary_if_update_addr(bat_priv);
-
- /***
- * hacky trick to make sure that we send the TT information via
- * our new primary interface
- */
- atomic_set(&bat_priv->tt_local_changed, 1);
}
static bool hardif_is_iface_up(const struct hard_iface *hard_iface)
@@@ -337,10 -331,11 +331,11 @@@ int hardif_enable_interface(struct hard
batman_packet = (struct batman_packet *)(hard_iface->packet_buff);
batman_packet->packet_type = BAT_PACKET;
batman_packet->version = COMPAT_VERSION;
- batman_packet->flags = 0;
+ batman_packet->flags = NO_FLAGS;
batman_packet->ttl = 2;
batman_packet->tq = TQ_MAX_VALUE;
- batman_packet->num_tt = 0;
+ batman_packet->tt_num_changes = 0;
+ batman_packet->ttvn = 0;
hard_iface->if_num = bat_priv->num_ifaces;
bat_priv->num_ifaces++;
@@@ -568,7 -563,7 +563,7 @@@ static int hard_if_event(struct notifie
break;
default:
break;
- };
+ }
hardif_put:
hardif_free_ref(hard_iface);
@@@ -659,6 -654,14 +654,14 @@@ static int batman_skb_recv(struct sk_bu
case BAT_VIS:
ret = recv_vis_packet(skb, hard_iface);
break;
+ /* Translation table query (request or response) */
+ case BAT_TT_QUERY:
+ ret = recv_tt_query(skb, hard_iface);
+ break;
+ /* Roaming advertisement */
+ case BAT_ROAM_ADV:
+ ret = recv_roam_adv(skb, hard_iface);
+ break;
default:
ret = NET_RX_DROP;
}
diff --combined net/batman-adv/hard-interface.h
index 79e25cb,442eacb..442eacb
--- a/net/batman-adv/hard-interface.h
+++ b/net/batman-adv/hard-interface.h
@@@ -22,12 -22,14 +22,14 @@@
#ifndef _NET_BATMAN_ADV_HARD_INTERFACE_H_
#define _NET_BATMAN_ADV_HARD_INTERFACE_H_
- #define IF_NOT_IN_USE 0
- #define IF_TO_BE_REMOVED 1
- #define IF_INACTIVE 2
- #define IF_ACTIVE 3
- #define IF_TO_BE_ACTIVATED 4
- #define IF_I_WANT_YOU 5
+ enum hard_if_state {
+ IF_NOT_IN_USE,
+ IF_TO_BE_REMOVED,
+ IF_INACTIVE,
+ IF_ACTIVE,
+ IF_TO_BE_ACTIVATED,
+ IF_I_WANT_YOU
+ };
extern struct notifier_block hard_if_notifier;
diff --combined net/batman-adv/main.c
index 2d6445e,e367e69..e367e69
--- a/net/batman-adv/main.c
+++ b/net/batman-adv/main.c
@@@ -84,8 -84,10 +84,10 @@@ int mesh_init(struct net_device *soft_i
spin_lock_init(&bat_priv->forw_bat_list_lock);
spin_lock_init(&bat_priv->forw_bcast_list_lock);
- spin_lock_init(&bat_priv->tt_lhash_lock);
- spin_lock_init(&bat_priv->tt_ghash_lock);
+ spin_lock_init(&bat_priv->tt_changes_list_lock);
+ spin_lock_init(&bat_priv->tt_req_list_lock);
+ spin_lock_init(&bat_priv->tt_roam_list_lock);
+ spin_lock_init(&bat_priv->tt_buff_lock);
spin_lock_init(&bat_priv->gw_list_lock);
spin_lock_init(&bat_priv->vis_hash_lock);
spin_lock_init(&bat_priv->vis_list_lock);
@@@ -96,14 -98,14 +98,14 @@@
INIT_HLIST_HEAD(&bat_priv->forw_bcast_list);
INIT_HLIST_HEAD(&bat_priv->gw_list);
INIT_HLIST_HEAD(&bat_priv->softif_neigh_vids);
+ INIT_LIST_HEAD(&bat_priv->tt_changes_list);
+ INIT_LIST_HEAD(&bat_priv->tt_req_list);
+ INIT_LIST_HEAD(&bat_priv->tt_roam_list);
if (originator_init(bat_priv) < 1)
goto err;
- if (tt_local_init(bat_priv) < 1)
- goto err;
-
- if (tt_global_init(bat_priv) < 1)
+ if (tt_init(bat_priv) < 1)
goto err;
tt_local_add(soft_iface, soft_iface->dev_addr);
@@@ -111,6 -113,7 +113,7 @@@
if (vis_init(bat_priv) < 1)
goto err;
+ atomic_set(&bat_priv->gw_reselect, 0);
atomic_set(&bat_priv->mesh_state, MESH_ACTIVE);
goto end;
@@@ -137,8 -140,7 +140,7 @@@ void mesh_free(struct net_device *soft_
gw_node_purge(bat_priv);
originator_free(bat_priv);
- tt_local_free(bat_priv);
- tt_global_free(bat_priv);
+ tt_free(bat_priv);
softif_neigh_purge(bat_priv);
diff --combined net/batman-adv/main.h
index 610eaf0,0000000..4f293b5
mode 100644,000000..100644
--- a/net/batman-adv/main.h
+++ b/net/batman-adv/main.h
@@@ -1,204 -1,0 +1,230 @@@
+/*
+ * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors:
+ *
+ * Marek Lindner, Simon Wunderlich
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ *
+ */
+
+#ifndef _NET_BATMAN_ADV_MAIN_H_
+#define _NET_BATMAN_ADV_MAIN_H_
+
+#define DRIVER_AUTHOR "Marek Lindner <lindner_marek(a)yahoo.de>, " \
+ "Simon Wunderlich <siwu(a)hrz.tu-chemnitz.de>"
+#define DRIVER_DESC "B.A.T.M.A.N. advanced"
+#define DRIVER_DEVICE "batman-adv"
+
+#define SOURCE_VERSION "next"
+
+
+/* B.A.T.M.A.N. parameters */
+
+#define TQ_MAX_VALUE 255
+#define JITTER 20
+
+ /* Time To Live of broadcast messages */
+#define TTL 50
+
+/* purge originators after time in seconds if no valid packet comes in
+ * -> TODO: check influence on TQ_LOCAL_WINDOW_SIZE */
+#define PURGE_TIMEOUT 200
+#define TT_LOCAL_TIMEOUT 3600 /* in seconds */
-
++#define TT_CLIENT_ROAM_TIMEOUT 600
+/* sliding packet range of received originator messages in squence numbers
+ * (should be a multiple of our word size) */
+#define TQ_LOCAL_WINDOW_SIZE 64
++#define TT_REQUEST_TIMEOUT 3 /* seconds we have to keep pending tt_req */
++
+#define TQ_GLOBAL_WINDOW_SIZE 5
+#define TQ_LOCAL_BIDRECT_SEND_MINIMUM 1
+#define TQ_LOCAL_BIDRECT_RECV_MINIMUM 1
+#define TQ_TOTAL_BIDRECT_LIMIT 1
+
++#define TT_OGM_APPEND_MAX 3 /* number of OGMs sent with the last tt diff */
++
++#define ROAMING_MAX_TIME 20 /* Time in which a client can roam at most
++ * ROAMING_MAX_COUNT times */
++#define ROAMING_MAX_COUNT 5
++
++#define NO_FLAGS 0
++
+#define NUM_WORDS (TQ_LOCAL_WINDOW_SIZE / WORD_BIT_SIZE)
+
+#define LOG_BUF_LEN 8192 /* has to be a power of 2 */
+
+#define VIS_INTERVAL 5000 /* 5 seconds */
+
+/* how much worse secondary interfaces may be to be considered as bonding
+ * candidates */
+#define BONDING_TQ_THRESHOLD 50
+
+/* should not be bigger than 512 bytes or change the size of
+ * forw_packet->direct_link_flags */
+#define MAX_AGGREGATION_BYTES 512
+#define MAX_AGGREGATION_MS 100
+
+#define SOFTIF_NEIGH_TIMEOUT 180000 /* 3 minutes */
+
+/* don't reset again within 30 seconds */
+#define RESET_PROTECTION_MS 30000
+#define EXPECTED_SEQNO_RANGE 65536
+
- #define MESH_INACTIVE 0
- #define MESH_ACTIVE 1
- #define MESH_DEACTIVATING 2
++enum mesh_state {
++ MESH_INACTIVE,
++ MESH_ACTIVE,
++ MESH_DEACTIVATING
++};
+
+#define BCAST_QUEUE_LEN 256
+#define BATMAN_QUEUE_LEN 256
+
++enum uev_action {
++ UEV_ADD = 0,
++ UEV_DEL,
++ UEV_CHANGE
++};
++
++enum uev_type {
++ UEV_GW = 0
++};
++
++#define GW_THRESHOLD 50
++
+/*
+ * Debug Messages
+ */
+#ifdef pr_fmt
+#undef pr_fmt
+#endif
+/* Append 'batman-adv: ' before kernel messages */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+/* all messages related to routing / flooding / broadcasting / etc */
- #define DBG_BATMAN 1
- /* route or tt entry added / changed / deleted */
- #define DBG_ROUTES 2
- #define DBG_ALL 3
++enum dbg_level {
++ DBG_BATMAN = 1 << 0,
++ DBG_ROUTES = 1 << 1, /* route added / changed / deleted */
++ DBG_TT = 1 << 2, /* translation table operations */
++ DBG_ALL = 7
++};
+
+
+/*
+ * Vis
+ */
+
+/*
+ * Kernel headers
+ */
+
+#include <linux/mutex.h> /* mutex */
+#include <linux/module.h> /* needed by all modules */
+#include <linux/netdevice.h> /* netdevice */
+#include <linux/etherdevice.h> /* ethernet address classifaction */
+#include <linux/if_ether.h> /* ethernet header */
+#include <linux/poll.h> /* poll_table */
+#include <linux/kthread.h> /* kernel threads */
+#include <linux/pkt_sched.h> /* schedule types */
+#include <linux/workqueue.h> /* workqueue */
+#include <linux/slab.h>
+#include <net/sock.h> /* struct sock */
+#include <linux/jiffies.h>
+#include <linux/seq_file.h>
+#include "types.h"
+
+#ifndef REVISION_VERSION
+#define REVISION_VERSION_STR ""
+#else
+#define REVISION_VERSION_STR " "REVISION_VERSION
+#endif
+
+extern struct list_head hardif_list;
+
+extern unsigned char broadcast_addr[];
+extern struct workqueue_struct *bat_event_workqueue;
+
+int mesh_init(struct net_device *soft_iface);
+void mesh_free(struct net_device *soft_iface);
+void inc_module_count(void);
+void dec_module_count(void);
+int is_my_mac(const uint8_t *addr);
+
+#ifdef CONFIG_BATMAN_ADV_DEBUG
+int debug_log(struct bat_priv *bat_priv, const char *fmt, ...) __printf(2, 3);
+
+#define bat_dbg(type, bat_priv, fmt, arg...) \
+ do { \
+ if (atomic_read(&bat_priv->log_level) & type) \
+ debug_log(bat_priv, fmt, ## arg); \
+ } \
+ while (0)
+#else /* !CONFIG_BATMAN_ADV_DEBUG */
+__printf(3, 4)
- static inline void bat_dbg(char type __always_unused,
++static inline void bat_dbg(int type __always_unused,
+ struct bat_priv *bat_priv __always_unused,
+ const char *fmt __always_unused, ...)
+{
+}
+#endif
+
+#define bat_info(net_dev, fmt, arg...) \
+ do { \
+ struct net_device *_netdev = (net_dev); \
+ struct bat_priv *_batpriv = netdev_priv(_netdev); \
+ bat_dbg(DBG_ALL, _batpriv, fmt, ## arg); \
+ pr_info("%s: " fmt, _netdev->name, ## arg); \
+ } while (0)
+#define bat_err(net_dev, fmt, arg...) \
+ do { \
+ struct net_device *_netdev = (net_dev); \
+ struct bat_priv *_batpriv = netdev_priv(_netdev); \
+ bat_dbg(DBG_ALL, _batpriv, fmt, ## arg); \
+ pr_err("%s: " fmt, _netdev->name, ## arg); \
+ } while (0)
+
+/**
+ * returns 1 if they are the same ethernet addr
+ *
+ * note: can't use compare_ether_addr() as it requires aligned memory
+ */
+
+static inline int compare_eth(const void *data1, const void *data2)
+{
+ return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
+}
+
+
+#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
+
+/* Returns the smallest signed integer in two's complement with the sizeof x */
+#define smallest_signed_int(x) (1u << (7u + 8u * (sizeof(x) - 1u)))
+
+/* Checks if a sequence number x is a predecessor/successor of y.
+ * they handle overflows/underflows and can correctly check for a
+ * predecessor/successor unless the variable sequence number has grown by
+ * more then 2**(bitwidth(x)-1)-1.
+ * This means that for a uint8_t with the maximum value 255, it would think:
+ * - when adding nothing - it is neither a predecessor nor a successor
+ * - before adding more than 127 to the starting value - it is a predecessor,
+ * - when adding 128 - it is neither a predecessor nor a successor,
+ * - after adding more than 127 to the starting value - it is a successor */
+#define seq_before(x, y) ({typeof(x) _d1 = (x); \
+ typeof(y) _d2 = (y); \
+ typeof(x) _dummy = (_d1 - _d2); \
+ (void) (&_d1 == &_d2); \
+ _dummy > smallest_signed_int(_dummy); })
+#define seq_after(x, y) seq_before(y, x)
+
+#endif /* _NET_BATMAN_ADV_MAIN_H_ */
diff --combined net/batman-adv/originator.c
index a6c35d4,338b3c5..338b3c5
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@@ -37,6 -37,14 +37,14 @@@ static void start_purge_timer(struct ba
queue_delayed_work(bat_event_workqueue, &bat_priv->orig_work, 1 * HZ);
}
+ /* returns 1 if they are the same originator */
+ static int compare_orig(const struct hlist_node *node, const void *data2)
+ {
+ const void *data1 = container_of(node, struct orig_node, hash_entry);
+
+ return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
+ }
+
int originator_init(struct bat_priv *bat_priv)
{
if (bat_priv->orig_hash)
@@@ -137,6 -145,7 +145,7 @@@ static void orig_node_free_rcu(struct r
tt_global_del_orig(orig_node->bat_priv, orig_node,
"originator timed out");
+ kfree(orig_node->tt_buff);
kfree(orig_node->bcast_own);
kfree(orig_node->bcast_own_sum);
kfree(orig_node);
@@@ -205,14 -214,18 +214,18 @@@ struct orig_node *get_orig_node(struct
spin_lock_init(&orig_node->ogm_cnt_lock);
spin_lock_init(&orig_node->bcast_seqno_lock);
spin_lock_init(&orig_node->neigh_list_lock);
+ spin_lock_init(&orig_node->tt_buff_lock);
/* extra reference for return */
atomic_set(&orig_node->refcount, 2);
+ orig_node->tt_poss_change = false;
orig_node->bat_priv = bat_priv;
memcpy(orig_node->orig, addr, ETH_ALEN);
orig_node->router = NULL;
orig_node->tt_buff = NULL;
+ orig_node->tt_buff_len = 0;
+ atomic_set(&orig_node->tt_size, 0);
orig_node->bcast_seqno_reset = jiffies - 1
- msecs_to_jiffies(RESET_PROTECTION_MS);
orig_node->batman_seqno_reset = jiffies - 1
@@@ -322,9 -335,7 +335,7 @@@ static bool purge_orig_node(struct bat_
if (purge_orig_neighbors(bat_priv, orig_node,
&best_neigh_node)) {
update_routes(bat_priv, orig_node,
- best_neigh_node,
- orig_node->tt_buff,
- orig_node->tt_buff_len);
+ best_neigh_node);
}
}
diff --combined net/batman-adv/originator.h
index 8e307af,cfc1f60..cfc1f60
--- a/net/batman-adv/originator.h
+++ b/net/batman-adv/originator.h
@@@ -40,14 -40,6 +40,6 @@@ int orig_hash_add_if(struct hard_iface
int orig_hash_del_if(struct hard_iface *hard_iface, int max_if_num);
- /* returns 1 if they are the same originator */
- static inline int compare_orig(const struct hlist_node *node, const void *data2)
- {
- const void *data1 = container_of(node, struct orig_node, hash_entry);
-
- return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
- }
-
/* hashfunction to choose an entry in a hash table of given size */
/* hash algorithm from http://en.wikipedia.org/wiki/Hash_table */
static inline int choose_orig(const void *data, int32_t size)
diff --combined net/batman-adv/packet.h
index eda9965,c5f081d..c5f081d
--- a/net/batman-adv/packet.h
+++ b/net/batman-adv/packet.h
@@@ -24,46 -24,79 +24,79 @@@
#define ETH_P_BATMAN 0x4305 /* unofficial/not registered Ethertype */
- #define BAT_PACKET 0x01
- #define BAT_ICMP 0x02
- #define BAT_UNICAST 0x03
- #define BAT_BCAST 0x04
- #define BAT_VIS 0x05
- #define BAT_UNICAST_FRAG 0x06
+ enum bat_packettype {
+ BAT_PACKET = 0x01,
+ BAT_ICMP = 0x02,
+ BAT_UNICAST = 0x03,
+ BAT_BCAST = 0x04,
+ BAT_VIS = 0x05,
+ BAT_UNICAST_FRAG = 0x06,
+ BAT_TT_QUERY = 0x07,
+ BAT_ROAM_ADV = 0x08
+ };
/* this file is included by batctl which needs these defines */
- #define COMPAT_VERSION 12
- #define DIRECTLINK 0x40
- #define VIS_SERVER 0x20
- #define PRIMARIES_FIRST_HOP 0x10
+ #define COMPAT_VERSION 14
+
+ enum batman_flags {
+ PRIMARIES_FIRST_HOP = 1 << 4,
+ VIS_SERVER = 1 << 5,
+ DIRECTLINK = 1 << 6
+ };
/* ICMP message types */
- #define ECHO_REPLY 0
- #define DESTINATION_UNREACHABLE 3
- #define ECHO_REQUEST 8
- #define TTL_EXCEEDED 11
- #define PARAMETER_PROBLEM 12
+ enum icmp_packettype {
+ ECHO_REPLY = 0,
+ DESTINATION_UNREACHABLE = 3,
+ ECHO_REQUEST = 8,
+ TTL_EXCEEDED = 11,
+ PARAMETER_PROBLEM = 12
+ };
/* vis defines */
- #define VIS_TYPE_SERVER_SYNC 0
- #define VIS_TYPE_CLIENT_UPDATE 1
+ enum vis_packettype {
+ VIS_TYPE_SERVER_SYNC = 0,
+ VIS_TYPE_CLIENT_UPDATE = 1
+ };
/* fragmentation defines */
- #define UNI_FRAG_HEAD 0x01
- #define UNI_FRAG_LARGETAIL 0x02
+ enum unicast_frag_flags {
+ UNI_FRAG_HEAD = 1 << 0,
+ UNI_FRAG_LARGETAIL = 1 << 1
+ };
+
+ /* TT_QUERY subtypes */
+ #define TT_QUERY_TYPE_MASK 0x3
+
+ enum tt_query_packettype {
+ TT_REQUEST = 0,
+ TT_RESPONSE = 1
+ };
+
+ /* TT_QUERY flags */
+ enum tt_query_flags {
+ TT_FULL_TABLE = 1 << 2
+ };
+
+ /* TT_CHANGE flags */
+ enum tt_change_flags {
+ TT_CHANGE_DEL = 0x01,
+ TT_CLIENT_ROAM = 0x02
+ };
struct batman_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
+ uint8_t ttl;
uint8_t flags; /* 0x40: DIRECTLINK flag, 0x20 VIS_SERVER flag... */
uint32_t seqno;
uint8_t orig[6];
uint8_t prev_sender[6];
- uint8_t ttl;
- uint8_t num_tt;
uint8_t gw_flags; /* flags related to gateway class */
- uint8_t align;
+ uint8_t tq;
+ uint8_t tt_num_changes;
+ uint8_t ttvn; /* translation table version number */
+ uint16_t tt_crc;
} __packed;
#define BAT_PACKET_LEN sizeof(struct batman_packet)
@@@ -71,12 -104,13 +104,13 @@@
struct icmp_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
- uint8_t msg_type; /* see ICMP message types above */
uint8_t ttl;
+ uint8_t msg_type; /* see ICMP message types above */
uint8_t dst[6];
uint8_t orig[6];
uint16_t seqno;
uint8_t uid;
+ uint8_t reserved;
} __packed;
#define BAT_RR_LEN 16
@@@ -86,8 -120,8 +120,8 @@@
struct icmp_packet_rr {
uint8_t packet_type;
uint8_t version; /* batman version field */
- uint8_t msg_type; /* see ICMP message types above */
uint8_t ttl;
+ uint8_t msg_type; /* see ICMP message types above */
uint8_t dst[6];
uint8_t orig[6];
uint16_t seqno;
@@@ -99,16 -133,19 +133,19 @@@
struct unicast_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
- uint8_t dest[6];
uint8_t ttl;
+ uint8_t ttvn; /* destination translation table version number */
+ uint8_t dest[6];
} __packed;
struct unicast_frag_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
- uint8_t dest[6];
uint8_t ttl;
+ uint8_t ttvn; /* destination translation table version number */
+ uint8_t dest[6];
uint8_t flags;
+ uint8_t align;
uint8_t orig[6];
uint16_t seqno;
} __packed;
@@@ -116,21 -153,61 +153,61 @@@
struct bcast_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
- uint8_t orig[6];
uint8_t ttl;
+ uint8_t reserved;
uint32_t seqno;
+ uint8_t orig[6];
} __packed;
struct vis_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
+ uint8_t ttl; /* TTL */
uint8_t vis_type; /* which type of vis-participant sent this? */
- uint8_t entries; /* number of entries behind this struct */
uint32_t seqno; /* sequence number */
- uint8_t ttl; /* TTL */
+ uint8_t entries; /* number of entries behind this struct */
+ uint8_t reserved;
uint8_t vis_orig[6]; /* originator that announces its neighbors */
uint8_t target_orig[6]; /* who should receive this packet */
uint8_t sender_orig[6]; /* who sent or rebroadcasted this packet */
} __packed;
+ struct tt_query_packet {
+ uint8_t packet_type;
+ uint8_t version; /* batman version field */
+ uint8_t ttl;
+ /* the flag field is a combination of:
+ * - TT_REQUEST or TT_RESPONSE
+ * - TT_FULL_TABLE */
+ uint8_t flags;
+ uint8_t dst[ETH_ALEN];
+ uint8_t src[ETH_ALEN];
+ /* the ttvn field is:
+ * if TT_REQUEST: ttvn that triggered the
+ * request
+ * if TT_RESPONSE: new ttvn for the src
+ * orig_node */
+ uint8_t ttvn;
+ /* tt_data field is:
+ * if TT_REQUEST: crc associated with the
+ * ttvn
+ * if TT_RESPONSE: table_size */
+ uint16_t tt_data;
+ } __packed;
+
+ struct roam_adv_packet {
+ uint8_t packet_type;
+ uint8_t version;
+ uint8_t ttl;
+ uint8_t reserved;
+ uint8_t dst[ETH_ALEN];
+ uint8_t src[ETH_ALEN];
+ uint8_t client[ETH_ALEN];
+ } __packed;
+
+ struct tt_change {
+ uint8_t flags;
+ uint8_t addr[ETH_ALEN];
+ } __packed;
+
#endif /* _NET_BATMAN_ADV_PACKET_H_ */
diff --combined net/batman-adv/routing.c
index 368ceeb,0ce090c..0ce090c
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@@ -64,27 -64,57 +64,57 @@@ void slide_own_bcast_window(struct hard
}
}
- static void update_TT(struct bat_priv *bat_priv, struct orig_node *orig_node,
- const unsigned char *tt_buff, int tt_buff_len)
+ static void update_transtable(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)
{
- if ((tt_buff_len != orig_node->tt_buff_len) ||
- ((tt_buff_len > 0) &&
- (orig_node->tt_buff_len > 0) &&
- (memcmp(orig_node->tt_buff, tt_buff, tt_buff_len) != 0))) {
-
- if (orig_node->tt_buff_len > 0)
- tt_global_del_orig(bat_priv, orig_node,
- "originator changed tt");
-
- if ((tt_buff_len > 0) && (tt_buff))
- tt_global_add_orig(bat_priv, orig_node,
- tt_buff, tt_buff_len);
+ uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn);
+ bool full_table = true;
+
+ /* the ttvn increased by one -> we can apply the attached changes */
+ if (ttvn - orig_ttvn == 1) {
+ /* the OGM could not contain the changes because they were too
+ * many to fit in one frame or because they have already been
+ * sent TT_OGM_APPEND_MAX times. In this case send a tt
+ * request */
+ if (!tt_num_changes) {
+ full_table = false;
+ goto request_table;
+ }
+
+ tt_update_changes(bat_priv, orig_node, tt_num_changes, ttvn,
+ (struct tt_change *)tt_buff);
+
+ /* Even if we received the crc into the OGM, we prefer
+ * to recompute it to spot any possible inconsistency
+ * in the global table */
+ orig_node->tt_crc = tt_global_crc(bat_priv, orig_node);
+ /* Roaming phase is over: tables are in sync again. I can
+ * unset the flag */
+ orig_node->tt_poss_change = false;
+ } else {
+ /* if we missed more than one change or our tables are not
+ * in sync anymore -> request fresh tt data */
+ if (ttvn != orig_ttvn || orig_node->tt_crc != tt_crc) {
+ request_table:
+ bat_dbg(DBG_TT, bat_priv, "TT inconsistency for %pM. "
+ "Need to retrieve the correct information "
+ "(ttvn: %u last_ttvn: %u crc: %u last_crc: "
+ "%u num_changes: %u)\n", orig_node->orig, ttvn,
+ orig_ttvn, tt_crc, orig_node->tt_crc,
+ tt_num_changes);
+ send_tt_request(bat_priv, orig_node, ttvn, tt_crc,
+ full_table);
+ return;
+ }
}
}
- static void update_route(struct bat_priv *bat_priv, struct orig_node *orig_node,
- struct neigh_node *neigh_node,
- const unsigned char *tt_buff, int tt_buff_len)
+ static void update_route(struct bat_priv *bat_priv,
+ struct orig_node *orig_node,
+ struct neigh_node *neigh_node)
{
struct neigh_node *curr_router;
@@@ -92,11 -122,10 +122,10 @@@
/* route deleted */
if ((curr_router) && (!neigh_node)) {
bat_dbg(DBG_ROUTES, bat_priv, "Deleting route towards: %pM\n",
orig_node->orig);
tt_global_del_orig(bat_priv, orig_node,
- "originator timed out");
+ "Deleted route towards originator");
/* route added */
} else if ((!curr_router) && (neigh_node)) {
@@@ -104,9 -133,6 +133,6 @@@
bat_dbg(DBG_ROUTES, bat_priv,
"Adding route towards: %pM (via %pM)\n",
orig_node->orig, neigh_node->addr);
- tt_global_add_orig(bat_priv, orig_node,
- tt_buff, tt_buff_len);
-
/* route changed */
} else if (neigh_node && curr_router) {
bat_dbg(DBG_ROUTES, bat_priv,
@@@ -133,8 -159,7 +159,7 @@@
}
void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node,
- struct neigh_node *neigh_node, const unsigned char *tt_buff,
- int tt_buff_len)
+ struct neigh_node *neigh_node)
{
struct neigh_node *router = NULL;
@@@ -144,11 -169,7 +169,7 @@@
router = orig_node_get_router(orig_node);
if (router != neigh_node)
- update_route(bat_priv, orig_node, neigh_node,
- tt_buff, tt_buff_len);
- /* may be just TT changed */
- else
- update_TT(bat_priv, orig_node, tt_buff, tt_buff_len);
+ update_route(bat_priv, orig_node, neigh_node);
out:
if (router)
@@@ -163,7 -184,7 +184,7 @@@ static int is_bidirectional_neigh(struc
struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
struct neigh_node *neigh_node = NULL, *tmp_neigh_node;
struct hlist_node *node;
- unsigned char total_count;
+ uint8_t total_count;
uint8_t orig_eq_count, neigh_rq_count, tq_own;
int tq_asym_penalty, ret = 0;
@@@ -360,14 -381,12 +381,12 @@@ static void update_orig(struct bat_pri
const struct ethhdr *ethhdr,
const struct batman_packet *batman_packet,
struct hard_iface *if_incoming,
- const unsigned char *tt_buff, int tt_buff_len,
- char is_duplicate)
+ const unsigned char *tt_buff, int is_duplicate)
{
struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL;
struct neigh_node *router = NULL;
struct orig_node *orig_node_tmp;
struct hlist_node *node;
- int tmp_tt_buff_len;
uint8_t bcast_own_sum_orig, bcast_own_sum_neigh;
bat_dbg(DBG_BATMAN, bat_priv, "update_originator(): "
@@@ -432,9 -451,6 +451,6 @@@
bonding_candidate_add(orig_node, neigh_node);
- tmp_tt_buff_len = (tt_buff_len > batman_packet->num_tt * ETH_ALEN ?
- batman_packet->num_tt * ETH_ALEN : tt_buff_len);
-
/* if this neighbor already is our next hop there is nothing
* to change */
router = orig_node_get_router(orig_node);
@@@ -464,15 -480,19 +480,19 @@@
goto update_tt;
}
- update_routes(bat_priv, orig_node, neigh_node,
- tt_buff, tmp_tt_buff_len);
- goto update_gw;
+ update_routes(bat_priv, orig_node, neigh_node);
update_tt:
- update_routes(bat_priv, orig_node, router,
- tt_buff, tmp_tt_buff_len);
+ /* I have to check for transtable changes only if the OGM has been
+ * sent through a primary interface */
+ if (((batman_packet->orig != ethhdr->h_source) &&
+ (batman_packet->ttl > 2)) ||
+ (batman_packet->flags & PRIMARIES_FIRST_HOP))
+ update_transtable(bat_priv, orig_node, tt_buff,
+ batman_packet->tt_num_changes,
+ batman_packet->ttvn,
+ batman_packet->tt_crc);
- update_gw:
if (orig_node->gw_flags != batman_packet->gw_flags)
gw_node_update(bat_priv, orig_node, batman_packet->gw_flags);
@@@ -528,7 -548,7 +548,7 @@@ static int window_protected(struct bat_
* -1 the packet is old and has been received while the seqno window
* was protected. Caller should drop it.
*/
- static char count_real_packets(const struct ethhdr *ethhdr,
+ static int count_real_packets(const struct ethhdr *ethhdr,
const struct batman_packet *batman_packet,
const struct hard_iface *if_incoming)
{
@@@ -536,7 -556,7 +556,7 @@@
struct orig_node *orig_node;
struct neigh_node *tmp_neigh_node;
struct hlist_node *node;
- char is_duplicate = 0;
+ int is_duplicate = 0;
int32_t seq_diff;
int need_update = 0;
int set_mark, ret = -1;
@@@ -594,7 -614,7 +614,7 @@@ out
void receive_bat_packet(const struct ethhdr *ethhdr,
struct batman_packet *batman_packet,
- const unsigned char *tt_buff, int tt_buff_len,
+ const unsigned char *tt_buff,
struct hard_iface *if_incoming)
{
struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
@@@ -602,10 -622,10 +622,10 @@@
struct orig_node *orig_neigh_node, *orig_node;
struct neigh_node *router = NULL, *router_router = NULL;
struct neigh_node *orig_neigh_router = NULL;
- char has_directlink_flag;
- char is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0;
- char is_broadcast = 0, is_bidirectional, is_single_hop_neigh;
- char is_duplicate;
+ int has_directlink_flag;
+ int is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0;
+ int is_broadcast = 0, is_bidirectional, is_single_hop_neigh;
+ int is_duplicate;
uint32_t if_incoming_seqno;
/* Silently drop when the batman packet is actually not a
@@@ -633,12 -653,14 +653,14 @@@
bat_dbg(DBG_BATMAN, bat_priv,
"Received BATMAN packet via NB: %pM, IF: %s [%pM] "
- "(from OG: %pM, via prev OG: %pM, seqno %d, tq %d, "
- "TTL %d, V %d, IDF %d)\n",
+ "(from OG: %pM, via prev OG: %pM, seqno %d, 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_packet->orig,
batman_packet->prev_sender, batman_packet->seqno,
- batman_packet->tq, batman_packet->ttl, batman_packet->version,
+ batman_packet->ttvn, batman_packet->tt_crc,
+ batman_packet->tt_num_changes, batman_packet->tq,
+ batman_packet->ttl, batman_packet->version,
has_directlink_flag);
rcu_read_lock();
@@@ -698,17 -720,16 +720,16 @@@
/* neighbor has to indicate direct link and it has to
* come via the corresponding interface */
- /* if received seqno equals last send seqno save new
- * seqno for bidirectional check */
+ /* save packet seqno for bidirectional check */
if (has_directlink_flag &&
compare_eth(if_incoming->net_dev->dev_addr,
- batman_packet->orig) &&
- (batman_packet->seqno - if_incoming_seqno + 2 == 0)) {
+ batman_packet->orig)) {
offset = if_incoming->if_num * NUM_WORDS;
spin_lock_bh(&orig_neigh_node->ogm_cnt_lock);
word = &(orig_neigh_node->bcast_own[offset]);
- bit_mark(word, 0);
+ bit_mark(word,
+ if_incoming_seqno - batman_packet->seqno - 2);
orig_neigh_node->bcast_own_sum[if_incoming->if_num] =
bit_packet_count(word);
spin_unlock_bh(&orig_neigh_node->ogm_cnt_lock);
@@@ -791,14 -812,14 +812,14 @@@
((orig_node->last_real_seqno == batman_packet->seqno) &&
(orig_node->last_ttl - 3 <= batman_packet->ttl))))
update_orig(bat_priv, orig_node, ethhdr, batman_packet,
- if_incoming, tt_buff, tt_buff_len, is_duplicate);
+ if_incoming, tt_buff, is_duplicate);
/* is single hop (direct) neighbor */
if (is_single_hop_neigh) {
/* mark direct link on incoming interface */
schedule_forward_packet(orig_node, ethhdr, batman_packet,
- 1, tt_buff_len, if_incoming);
+ 1, if_incoming);
bat_dbg(DBG_BATMAN, bat_priv, "Forwarding packet: "
"rebroadcast neighbor packet with direct link flag\n");
@@@ -821,7 -842,7 +842,7 @@@
bat_dbg(DBG_BATMAN, bat_priv,
"Forwarding packet: rebroadcast originator packet\n");
schedule_forward_packet(orig_node, ethhdr, batman_packet,
- 0, tt_buff_len, if_incoming);
+ 0, if_incoming);
out_neigh:
if ((orig_neigh_node) && (!is_single_hop_neigh))
@@@ -1168,6 -1189,118 +1189,118 @@@ static struct neigh_node *find_ifalter_
return router;
}
+ 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;
+ struct ethhdr *ethhdr;
+
+ /* drop packet if it has not necessary minimum size */
+ if (unlikely(!pskb_may_pull(skb, sizeof(struct tt_query_packet))))
+ goto out;
+
+ /* I could need to modify it */
+ if (skb_cow(skb, sizeof(struct tt_query_packet)) < 0)
+ goto out;
+
+ ethhdr = (struct ethhdr *)skb_mac_header(skb);
+
+ /* packet with unicast indication but broadcast recipient */
+ if (is_broadcast_ether_addr(ethhdr->h_dest))
+ goto out;
+
+ /* packet with broadcast sender address */
+ if (is_broadcast_ether_addr(ethhdr->h_source))
+ goto out;
+
+ 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:
+ /* If we cannot provide an answer the tt_request is
+ * forwarded */
+ if (!send_tt_response(bat_priv, tt_query)) {
+ bat_dbg(DBG_TT, bat_priv,
+ "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:
+ /* packet needs to be linearised to access the TT changes */
+ if (skb_linearize(skb) < 0)
+ goto out;
+
+ if (is_my_mac(tt_query->dst))
+ handle_tt_response(bat_priv, tt_query);
+ else {
+ bat_dbg(DBG_TT, bat_priv,
+ "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;
+ }
+
+ out:
+ /* returning NET_RX_DROP will make the caller function kfree the skb */
+ return NET_RX_DROP;
+ }
+
+ int recv_roam_adv(struct sk_buff *skb, struct hard_iface *recv_if)
+ {
+ struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
+ struct roam_adv_packet *roam_adv_packet;
+ struct orig_node *orig_node;
+ struct ethhdr *ethhdr;
+
+ /* drop packet if it has not necessary minimum size */
+ if (unlikely(!pskb_may_pull(skb, sizeof(struct roam_adv_packet))))
+ goto out;
+
+ ethhdr = (struct ethhdr *)skb_mac_header(skb);
+
+ /* packet with unicast indication but broadcast recipient */
+ if (is_broadcast_ether_addr(ethhdr->h_dest))
+ goto out;
+
+ /* packet with broadcast sender address */
+ if (is_broadcast_ether_addr(ethhdr->h_source))
+ goto out;
+
+ roam_adv_packet = (struct roam_adv_packet *)skb->data;
+
+ if (!is_my_mac(roam_adv_packet->dst))
+ return route_unicast_packet(skb, recv_if);
+
+ orig_node = orig_hash_find(bat_priv, roam_adv_packet->src);
+ if (!orig_node)
+ goto out;
+
+ bat_dbg(DBG_TT, bat_priv, "Received ROAMING_ADV from %pM "
+ "(client %pM)\n", roam_adv_packet->src,
+ roam_adv_packet->client);
+
+ tt_global_add(bat_priv, orig_node, roam_adv_packet->client,
+ atomic_read(&orig_node->last_ttvn) + 1, true);
+
+ /* Roaming phase starts: I have new information but the ttvn has not
+ * been incremented yet. This flag will make me check all the incoming
+ * packets for the correct destination. */
+ bat_priv->tt_poss_change = true;
+
+ orig_node_free_ref(orig_node);
+ out:
+ /* returning NET_RX_DROP will make the caller function kfree the skb */
+ return NET_RX_DROP;
+ }
+
/* find a suitable router for this originator, and use
* bonding if possible. increases the found neighbors
* refcount.*/
@@@ -1354,14 -1487,84 +1487,84 @@@ out
return ret;
}
+ static int check_unicast_ttvn(struct bat_priv *bat_priv,
+ struct sk_buff *skb) {
+ uint8_t curr_ttvn;
+ struct orig_node *orig_node;
+ struct ethhdr *ethhdr;
+ struct hard_iface *primary_if;
+ struct unicast_packet *unicast_packet;
+ bool tt_poss_change;
+
+ /* I could need to modify it */
+ if (skb_cow(skb, sizeof(struct unicast_packet)) < 0)
+ return 0;
+
+ unicast_packet = (struct unicast_packet *)skb->data;
+
+ if (is_my_mac(unicast_packet->dest)) {
+ tt_poss_change = bat_priv->tt_poss_change;
+ curr_ttvn = (uint8_t)atomic_read(&bat_priv->ttvn);
+ } else {
+ orig_node = orig_hash_find(bat_priv, unicast_packet->dest);
+
+ if (!orig_node)
+ return 0;
+
+ curr_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn);
+ tt_poss_change = orig_node->tt_poss_change;
+ orig_node_free_ref(orig_node);
+ }
+
+ /* Check whether I have to reroute the packet */
+ if (seq_before(unicast_packet->ttvn, curr_ttvn) || tt_poss_change) {
+ /* Linearize the skb before accessing it */
+ if (skb_linearize(skb) < 0)
+ return 0;
+
+ ethhdr = (struct ethhdr *)(skb->data +
+ sizeof(struct unicast_packet));
+ orig_node = transtable_search(bat_priv, ethhdr->h_dest);
+
+ if (!orig_node) {
+ if (!is_my_client(bat_priv, ethhdr->h_dest))
+ return 0;
+ primary_if = primary_if_get_selected(bat_priv);
+ if (!primary_if)
+ return 0;
+ memcpy(unicast_packet->dest,
+ primary_if->net_dev->dev_addr, ETH_ALEN);
+ hardif_free_ref(primary_if);
+ } else {
+ memcpy(unicast_packet->dest, orig_node->orig,
+ ETH_ALEN);
+ curr_ttvn = (uint8_t)
+ atomic_read(&orig_node->last_ttvn);
+ orig_node_free_ref(orig_node);
+ }
+
+ bat_dbg(DBG_ROUTES, bat_priv, "TTVN mismatch (old_ttvn %u "
+ "new_ttvn %u)! Rerouting unicast packet (for %pM) to "
+ "%pM\n", unicast_packet->ttvn, curr_ttvn,
+ ethhdr->h_dest, unicast_packet->dest);
+
+ unicast_packet->ttvn = curr_ttvn;
+ }
+ return 1;
+ }
+
int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
{
+ struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
struct unicast_packet *unicast_packet;
int hdr_size = sizeof(*unicast_packet);
if (check_unicast_packet(skb, hdr_size) < 0)
return NET_RX_DROP;
+ if (!check_unicast_ttvn(bat_priv, skb))
+ return NET_RX_DROP;
+
unicast_packet = (struct unicast_packet *)skb->data;
/* packet for me */
@@@ -1384,6 -1587,9 +1587,9 @@@ int recv_ucast_frag_packet(struct sk_bu
if (check_unicast_packet(skb, hdr_size) < 0)
return NET_RX_DROP;
+ if (!check_unicast_ttvn(bat_priv, skb))
+ return NET_RX_DROP;
+
unicast_packet = (struct unicast_frag_packet *)skb->data;
/* packet for me */
diff --combined net/batman-adv/routing.h
index 0ce0392,fb14e95..fb14e95
--- a/net/batman-adv/routing.h
+++ b/net/batman-adv/routing.h
@@@ -25,11 -25,10 +25,10 @@@
void slide_own_bcast_window(struct hard_iface *hard_iface);
void receive_bat_packet(const struct ethhdr *ethhdr,
struct batman_packet *batman_packet,
- const unsigned char *tt_buff, int tt_buff_len,
+ const unsigned char *tt_buff,
struct hard_iface *if_incoming);
void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node,
- struct neigh_node *neigh_node, const unsigned char *tt_buff,
- int tt_buff_len);
+ struct neigh_node *neigh_node);
int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if);
int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if);
int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if);
@@@ -37,6 -36,8 +36,8 @@@ int recv_ucast_frag_packet(struct sk_bu
int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if);
int recv_vis_packet(struct sk_buff *skb, struct hard_iface *recv_if);
int recv_bat_packet(struct sk_buff *skb, struct hard_iface *recv_if);
+ int recv_tt_query(struct sk_buff *skb, struct hard_iface *recv_if);
+ int recv_roam_adv(struct sk_buff *skb, struct hard_iface *recv_if);
struct neigh_node *find_router(struct bat_priv *bat_priv,
struct orig_node *orig_node,
const struct hard_iface *recv_if);
diff --combined net/batman-adv/send.c
index d0cfa95,7a2f082..7a2f082
--- a/net/batman-adv/send.c
+++ b/net/batman-adv/send.c
@@@ -120,7 -120,7 +120,7 @@@ static void send_packet_to_if(struct fo
/* adjust all flags and log packets */
while (aggregated_packet(buff_pos,
forw_packet->packet_len,
- batman_packet->num_tt)) {
+ batman_packet->tt_num_changes)) {
/* we might have aggregated direct link packets with an
* ordinary base packet */
@@@ -135,17 -135,17 +135,17 @@@
"Forwarding"));
bat_dbg(DBG_BATMAN, bat_priv,
"%s %spacket (originator %pM, seqno %d, TQ %d, TTL %d,"
- " IDF %s) on interface %s [%pM]\n",
+ " IDF %s, hvn %d) on interface %s [%pM]\n",
fwd_str, (packet_num > 0 ? "aggregated " : ""),
batman_packet->orig, ntohl(batman_packet->seqno),
batman_packet->tq, batman_packet->ttl,
(batman_packet->flags & DIRECTLINK ?
"on" : "off"),
- hard_iface->net_dev->name,
+ batman_packet->ttvn, hard_iface->net_dev->name,
hard_iface->net_dev->dev_addr);
buff_pos += sizeof(*batman_packet) +
- (batman_packet->num_tt * ETH_ALEN);
+ tt_len(batman_packet->tt_num_changes);
packet_num++;
batman_packet = (struct batman_packet *)
(forw_packet->skb->data + buff_pos);
@@@ -165,7 -165,7 +165,7 @@@ static void send_packet(struct forw_pac
struct bat_priv *bat_priv;
struct batman_packet *batman_packet =
(struct batman_packet *)(forw_packet->skb->data);
- unsigned char directlink = (batman_packet->flags & DIRECTLINK ? 1 : 0);
+ int directlink = (batman_packet->flags & DIRECTLINK ? 1 : 0);
if (!forw_packet->if_incoming) {
pr_err("Error - can't forward packet: incoming iface not "
@@@ -213,25 -213,18 +213,18 @@@
rcu_read_unlock();
}
- static void rebuild_batman_packet(struct bat_priv *bat_priv,
- struct hard_iface *hard_iface)
+ static void realloc_packet_buffer(struct hard_iface *hard_iface,
+ int new_len)
{
unsigned char *new_buff;
struct batman_packet *batman_packet;
- new_len = sizeof(*batman_packet) + (bat_priv->num_local_tt * ETH_ALEN);
new_buff = kmalloc(new_len, GFP_ATOMIC);
/* keep old buffer if kmalloc should fail */
if (new_buff) {
memcpy(new_buff, hard_iface->packet_buff,
sizeof(*batman_packet));
- batman_packet = (struct batman_packet *)new_buff;
-
- batman_packet->num_tt = tt_local_fill_buffer(bat_priv,
- new_buff + sizeof(*batman_packet),
- new_len - sizeof(*batman_packet));
kfree(hard_iface->packet_buff);
hard_iface->packet_buff = new_buff;
@@@ -239,6 -232,46 +232,46 @@@
}
}
+ /* when calling this function (hard_iface == primary_if) has to be true */
+ static void prepare_packet_buffer(struct bat_priv *bat_priv,
+ struct hard_iface *hard_iface)
+ {
+ int new_len;
+ struct batman_packet *batman_packet;
+
+ new_len = BAT_PACKET_LEN +
+ 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 = BAT_PACKET_LEN;
+
+ realloc_packet_buffer(hard_iface, new_len);
+ batman_packet = (struct batman_packet *)hard_iface->packet_buff;
+
+ 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);
+
+ batman_packet->tt_num_changes = tt_changes_fill_buffer(bat_priv,
+ hard_iface->packet_buff + BAT_PACKET_LEN,
+ hard_iface->packet_len - BAT_PACKET_LEN);
+
+ }
+
+ static void reset_packet_buffer(struct bat_priv *bat_priv,
+ struct hard_iface *hard_iface)
+ {
+ struct batman_packet *batman_packet;
+
+ realloc_packet_buffer(hard_iface, BAT_PACKET_LEN);
+
+ batman_packet = (struct batman_packet *)hard_iface->packet_buff;
+ batman_packet->tt_num_changes = 0;
+ }
+
void schedule_own_packet(struct hard_iface *hard_iface)
{
struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
@@@ -264,14 -297,23 +297,23 @@@
if (hard_iface->if_status == IF_TO_BE_ACTIVATED)
hard_iface->if_status = IF_ACTIVE;
- /* if local tt has changed and interface is a primary interface */
- if ((atomic_read(&bat_priv->tt_local_changed)) &&
- (hard_iface == primary_if))
- rebuild_batman_packet(bat_priv, hard_iface);
+ if (hard_iface == primary_if) {
+ /* if at least one change happened */
+ if (atomic_read(&bat_priv->tt_local_changes) > 0) {
+ prepare_packet_buffer(bat_priv, hard_iface);
+ /* Increment the TTVN only once per OGM interval */
+ atomic_inc(&bat_priv->ttvn);
+ bat_priv->tt_poss_change = false;
+ }
+
+ /* if the changes have been sent enough times */
+ if (!atomic_dec_not_zero(&bat_priv->tt_ogm_append_cnt))
+ reset_packet_buffer(bat_priv, hard_iface);
+ }
/**
* NOTE: packet_buff might just have been re-allocated in
- * rebuild_batman_packet()
+ * prepare_packet_buffer() or in reset_packet_buffer()
*/
batman_packet = (struct batman_packet *)hard_iface->packet_buff;
@@@ -279,6 -321,9 +321,9 @@@
batman_packet->seqno =
htonl((uint32_t)atomic_read(&hard_iface->seqno));
+ batman_packet->ttvn = atomic_read(&bat_priv->ttvn);
+ batman_packet->tt_crc = htons((uint16_t)atomic_read(&bat_priv->tt_crc));
+
if (vis_server == VIS_TYPE_SERVER_SYNC)
batman_packet->flags |= VIS_SERVER;
else
@@@ -289,7 -334,7 +334,7 @@@
batman_packet->gw_flags =
(uint8_t)atomic_read(&bat_priv->gw_bandwidth);
else
- batman_packet->gw_flags = 0;
+ batman_packet->gw_flags = NO_FLAGS;
atomic_inc(&hard_iface->seqno);
@@@ -307,13 -352,14 +352,14 @@@
void schedule_forward_packet(struct orig_node *orig_node,
const struct ethhdr *ethhdr,
struct batman_packet *batman_packet,
- uint8_t directlink, int tt_buff_len,
+ int directlink,
struct hard_iface *if_incoming)
{
struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
struct neigh_node *router;
- unsigned char in_tq, in_ttl, tq_avg = 0;
+ uint8_t in_tq, in_ttl, tq_avg = 0;
unsigned long send_time;
+ uint8_t tt_num_changes;
if (batman_packet->ttl <= 1) {
bat_dbg(DBG_BATMAN, bat_priv, "ttl exceeded\n");
@@@ -324,6 -370,7 +370,7 @@@
in_tq = batman_packet->tq;
in_ttl = batman_packet->ttl;
+ tt_num_changes = batman_packet->tt_num_changes;
batman_packet->ttl--;
memcpy(batman_packet->prev_sender, ethhdr->h_source, ETH_ALEN);
@@@ -356,6 -403,7 +403,7 @@@
batman_packet->ttl);
batman_packet->seqno = htonl(batman_packet->seqno);
+ batman_packet->tt_crc = htons(batman_packet->tt_crc);
/* switch of primaries first hop flag when forwarding */
batman_packet->flags &= ~PRIMARIES_FIRST_HOP;
@@@ -367,7 -415,7 +415,7 @@@
send_time = forward_send_time();
add_bat_packet_to_list(bat_priv,
(unsigned char *)batman_packet,
- sizeof(*batman_packet) + tt_buff_len,
+ sizeof(*batman_packet) + tt_len(tt_num_changes),
if_incoming, 0, send_time);
}
diff --combined net/batman-adv/send.h
index eceab87,633224a..633224a
--- a/net/batman-adv/send.h
+++ b/net/batman-adv/send.h
@@@ -28,7 -28,7 +28,7 @@@ void schedule_own_packet(struct hard_if
void schedule_forward_packet(struct orig_node *orig_node,
const struct ethhdr *ethhdr,
struct batman_packet *batman_packet,
- uint8_t directlink, int tt_buff_len,
+ int directlink,
struct hard_iface *if_outgoing);
int add_bcast_packet_to_list(struct bat_priv *bat_priv,
const struct sk_buff *skb);
diff --combined net/batman-adv/soft-interface.c
index b8d3f248,2dcdbb7..2dcdbb7
--- a/net/batman-adv/soft-interface.c
+++ b/net/batman-adv/soft-interface.c
@@@ -30,6 -30,7 +30,7 @@@
#include "gateway_common.h"
#include "gateway_client.h"
#include "bat_sysfs.h"
+ #include "originator.h"
#include <linux/slab.h>
#include <linux/ethtool.h>
#include <linux/etherdevice.h>
@@@ -380,7 -381,7 +381,7 @@@ void softif_neigh_purge(struct bat_pri
struct softif_neigh *softif_neigh, *curr_softif_neigh;
struct softif_neigh_vid *softif_neigh_vid;
struct hlist_node *node, *node_tmp, *node_tmp2;
- char do_deselect;
+ int do_deselect;
rcu_read_lock();
hlist_for_each_entry_rcu(softif_neigh_vid, node,
@@@ -534,7 -535,7 +535,7 @@@ static int interface_set_mac_addr(struc
/* only modify transtable if it has been initialised before */
if (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE) {
tt_local_remove(bat_priv, dev->dev_addr,
- "mac address changed");
+ "mac address changed", false);
tt_local_add(dev, addr->sa_data);
}
@@@ -553,7 -554,7 +554,7 @@@ static int interface_change_mtu(struct
return 0;
}
- int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
+ static int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
{
struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
struct bat_priv *bat_priv = netdev_priv(soft_iface);
@@@ -561,6 -562,7 +562,7 @@@
struct bcast_packet *bcast_packet;
struct vlan_ethhdr *vhdr;
struct softif_neigh *curr_softif_neigh = NULL;
+ struct orig_node *orig_node = NULL;
int data_len = skb->len, ret;
short vid = -1;
bool do_bcast = false;
@@@ -592,11 -594,13 +594,13 @@@
if (curr_softif_neigh)
goto dropped;
- /* TODO: check this for locks */
+ /* Register the client MAC in the transtable */
tt_local_add(soft_iface, ethhdr->h_source);
- if (is_multicast_ether_addr(ethhdr->h_dest)) {
- ret = gw_is_target(bat_priv, skb);
+ orig_node = transtable_search(bat_priv, ethhdr->h_dest);
+ if (is_multicast_ether_addr(ethhdr->h_dest) ||
+ (orig_node && orig_node->gw_flags)) {
+ ret = gw_is_target(bat_priv, skb, orig_node);
if (ret < 0)
goto dropped;
@@@ -656,6 -660,8 +660,8 @@@ end
softif_neigh_free_ref(curr_softif_neigh);
if (primary_if)
hardif_free_ref(primary_if);
+ if (orig_node)
+ orig_node_free_ref(orig_node);
return NETDEV_TX_OK;
}
@@@ -830,7 -836,13 +836,13 @@@ struct net_device *softif_create(const
atomic_set(&bat_priv->mesh_state, MESH_INACTIVE);
atomic_set(&bat_priv->bcast_seqno, 1);
- atomic_set(&bat_priv->tt_local_changed, 0);
+ atomic_set(&bat_priv->ttvn, 0);
+ atomic_set(&bat_priv->tt_local_changes, 0);
+ atomic_set(&bat_priv->tt_ogm_append_cnt, 0);
+
+ bat_priv->tt_buff = NULL;
+ bat_priv->tt_buff_len = 0;
+ bat_priv->tt_poss_change = false;
bat_priv->primary_if = NULL;
bat_priv->num_ifaces = 0;
diff --combined net/batman-adv/soft-interface.h
index c24906d,001546f..001546f
--- a/net/batman-adv/soft-interface.h
+++ b/net/batman-adv/soft-interface.h
@@@ -25,7 -25,6 +25,6 @@@
int my_skb_head_push(struct sk_buff *skb, unsigned int len);
int softif_neigh_seq_print_text(struct seq_file *seq, void *offset);
void softif_neigh_purge(struct bat_priv *bat_priv);
- int interface_tx(struct sk_buff *skb, struct net_device *soft_iface);
void interface_rx(struct net_device *soft_iface,
struct sk_buff *skb, struct hard_iface *recv_if,
int hdr_size);
diff --combined net/batman-adv/translation-table.c
index 561f769,5f1fcd5..5f1fcd5
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@@ -23,13 -23,17 +23,17 @@@
#include "translation-table.h"
#include "soft-interface.h"
#include "hard-interface.h"
+ #include "send.h"
#include "hash.h"
#include "originator.h"
+ #include "routing.h"
- static void tt_local_purge(struct work_struct *work);
- static void _tt_global_del_orig(struct bat_priv *bat_priv,
- struct tt_global_entry *tt_global_entry,
- const char *message);
+ #include <linux/crc16.h>
+
+ static void _tt_global_del(struct bat_priv *bat_priv,
+ struct tt_global_entry *tt_global_entry,
+ const char *message);
+ static void tt_purge(struct work_struct *work);
/* returns 1 if they are the same mac addr */
static int compare_ltt(const struct hlist_node *node, const void *data2)
@@@ -49,10 -53,11 +53,11 @@@ static int compare_gtt(const struct hli
return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
}
- static void tt_local_start_timer(struct bat_priv *bat_priv)
+ static void tt_start_timer(struct bat_priv *bat_priv)
{
- INIT_DELAYED_WORK(&bat_priv->tt_work, tt_local_purge);
- queue_delayed_work(bat_event_workqueue, &bat_priv->tt_work, 10 * HZ);
+ INIT_DELAYED_WORK(&bat_priv->tt_work, tt_purge);
+ queue_delayed_work(bat_event_workqueue, &bat_priv->tt_work,
+ msecs_to_jiffies(5000));
}
static struct tt_local_entry *tt_local_hash_find(struct bat_priv *bat_priv,
@@@ -75,6 -80,9 +80,9 @@@
if (!compare_eth(tt_local_entry, data))
continue;
+ if (!atomic_inc_not_zero(&tt_local_entry->refcount))
+ continue;
+
tt_local_entry_tmp = tt_local_entry;
break;
}
@@@ -104,6 -112,9 +112,9 @@@ static struct tt_global_entry *tt_globa
if (!compare_eth(tt_global_entry, data))
continue;
+ if (!atomic_inc_not_zero(&tt_global_entry->refcount))
+ continue;
+
tt_global_entry_tmp = tt_global_entry;
break;
}
@@@ -112,7 -123,57 +123,57 @@@
return tt_global_entry_tmp;
}
- int tt_local_init(struct bat_priv *bat_priv)
+ static bool is_out_of_time(unsigned long starting_time, unsigned long timeout)
+ {
+ unsigned long deadline;
+ deadline = starting_time + msecs_to_jiffies(timeout);
+
+ return time_after(jiffies, deadline);
+ }
+
+ static void tt_local_entry_free_ref(struct tt_local_entry *tt_local_entry)
+ {
+ if (atomic_dec_and_test(&tt_local_entry->refcount))
+ kfree_rcu(tt_local_entry, rcu);
+ }
+
+ static void tt_global_entry_free_ref(struct tt_global_entry *tt_global_entry)
+ {
+ if (atomic_dec_and_test(&tt_global_entry->refcount))
+ kfree_rcu(tt_global_entry, rcu);
+ }
+
+ static void tt_local_event(struct bat_priv *bat_priv, uint8_t op,
+ const uint8_t *addr, bool roaming)
+ {
+ struct tt_change_node *tt_change_node;
+
+ tt_change_node = kmalloc(sizeof(*tt_change_node), GFP_ATOMIC);
+
+ if (!tt_change_node)
+ return;
+
+ tt_change_node->change.flags = op;
+ if (roaming)
+ tt_change_node->change.flags |= TT_CLIENT_ROAM;
+
+ memcpy(tt_change_node->change.addr, addr, ETH_ALEN);
+
+ spin_lock_bh(&bat_priv->tt_changes_list_lock);
+ /* track the change in the OGMinterval list */
+ list_add_tail(&tt_change_node->list, &bat_priv->tt_changes_list);
+ atomic_inc(&bat_priv->tt_local_changes);
+ spin_unlock_bh(&bat_priv->tt_changes_list_lock);
+
+ atomic_set(&bat_priv->tt_ogm_append_cnt, 0);
+ }
+
+ int tt_len(int changes_num)
+ {
+ return changes_num * sizeof(struct tt_change);
+ }
+
+ static int tt_local_init(struct bat_priv *bat_priv)
{
if (bat_priv->tt_local_hash)
return 1;
@@@ -122,54 -183,35 +183,35 @@@
if (!bat_priv->tt_local_hash)
return 0;
- atomic_set(&bat_priv->tt_local_changed, 0);
- tt_local_start_timer(bat_priv);
-
return 1;
}
void tt_local_add(struct net_device *soft_iface, const uint8_t *addr)
{
struct bat_priv *bat_priv = netdev_priv(soft_iface);
- struct tt_local_entry *tt_local_entry;
- struct tt_global_entry *tt_global_entry;
- int required_bytes;
+ struct tt_local_entry *tt_local_entry = NULL;
+ struct tt_global_entry *tt_global_entry = NULL;
- spin_lock_bh(&bat_priv->tt_lhash_lock);
tt_local_entry = tt_local_hash_find(bat_priv, addr);
if (tt_local_entry) {
tt_local_entry->last_seen = jiffies;
- return;
- }
-
- /* only announce as many hosts as possible in the batman-packet and
- space in batman_packet->num_tt That also should give a limit to
- MAC-flooding. */
- required_bytes = (bat_priv->num_local_tt + 1) * ETH_ALEN;
- required_bytes += BAT_PACKET_LEN;
-
- if ((required_bytes > ETH_DATA_LEN) ||
- (atomic_read(&bat_priv->aggregated_ogms) &&
- required_bytes > MAX_AGGREGATION_BYTES) ||
- (bat_priv->num_local_tt + 1 > 255)) {
- bat_dbg(DBG_ROUTES, bat_priv,
- "Can't add new local tt entry (%pM): "
- "number of local tt entries exceeds packet size\n",
- addr);
- return;
+ goto out;
}
- bat_dbg(DBG_ROUTES, bat_priv,
- "Creating new local tt entry: %pM\n", addr);
-
tt_local_entry = kmalloc(sizeof(*tt_local_entry), GFP_ATOMIC);
if (!tt_local_entry)
- return;
+ goto out;
+
+ tt_local_event(bat_priv, NO_FLAGS, addr, false);
+
+ bat_dbg(DBG_TT, bat_priv,
+ "Creating new local tt entry: %pM (ttvn: %d)\n", addr,
+ (uint8_t)atomic_read(&bat_priv->ttvn));
memcpy(tt_local_entry->addr, addr, ETH_ALEN);
tt_local_entry->last_seen = jiffies;
+ atomic_set(&tt_local_entry->refcount, 2);
/* the batman interface mac address should never be purged */
if (compare_eth(addr, soft_iface->dev_addr))
@@@ -177,61 -219,75 +219,75 @@@
else
tt_local_entry->never_purge = 0;
- spin_lock_bh(&bat_priv->tt_lhash_lock);
-
hash_add(bat_priv->tt_local_hash, compare_ltt, choose_orig,
tt_local_entry, &tt_local_entry->hash_entry);
- bat_priv->num_local_tt++;
- atomic_set(&bat_priv->tt_local_changed, 1);
- spin_unlock_bh(&bat_priv->tt_lhash_lock);
+ atomic_inc(&bat_priv->num_local_tt);
/* remove address from global hash if present */
- spin_lock_bh(&bat_priv->tt_ghash_lock);
-
tt_global_entry = tt_global_hash_find(bat_priv, addr);
+ /* Check whether it is a roaming! */
+ if (tt_global_entry) {
+ /* This node is probably going to update its tt table */
+ tt_global_entry->orig_node->tt_poss_change = true;
+ _tt_global_del(bat_priv, tt_global_entry,
+ "local tt received");
+ send_roam_adv(bat_priv, tt_global_entry->addr,
+ tt_global_entry->orig_node);
+ }
+ out:
+ if (tt_local_entry)
+ tt_local_entry_free_ref(tt_local_entry);
if (tt_global_entry)
- _tt_global_del_orig(bat_priv, tt_global_entry,
- "local tt received");
-
- spin_unlock_bh(&bat_priv->tt_ghash_lock);
+ tt_global_entry_free_ref(tt_global_entry);
}
- int tt_local_fill_buffer(struct bat_priv *bat_priv,
- unsigned char *buff, int buff_len)
+ int tt_changes_fill_buffer(struct bat_priv *bat_priv,
+ unsigned char *buff, int buff_len)
{
- struct hashtable_t *hash = bat_priv->tt_local_hash;
- struct tt_local_entry *tt_local_entry;
- struct hlist_node *node;
- struct hlist_head *head;
- int i, count = 0;
+ int count = 0, tot_changes = 0;
+ struct tt_change_node *entry, *safe;
- spin_lock_bh(&bat_priv->tt_lhash_lock);
+ if (buff_len > 0)
+ tot_changes = buff_len / tt_len(1);
- for (i = 0; i < hash->size; i++) {
- head = &hash->table[i];
-
- rcu_read_lock();
- hlist_for_each_entry_rcu(tt_local_entry, node,
- head, hash_entry) {
- if (buff_len < (count + 1) * ETH_ALEN)
- break;
-
- memcpy(buff + (count * ETH_ALEN), tt_local_entry->addr,
- ETH_ALEN);
+ spin_lock_bh(&bat_priv->tt_changes_list_lock);
+ atomic_set(&bat_priv->tt_local_changes, 0);
+ list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list,
+ list) {
+ if (count < tot_changes) {
+ memcpy(buff + tt_len(count),
+ &entry->change, sizeof(struct tt_change));
count++;
}
- rcu_read_unlock();
+ list_del(&entry->list);
+ kfree(entry);
}
+ spin_unlock_bh(&bat_priv->tt_changes_list_lock);
+
+ /* Keep the buffer for possible tt_request */
+ spin_lock_bh(&bat_priv->tt_buff_lock);
+ 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
+ * instead of providing the diff
+ */
+ bat_priv->tt_buff = kmalloc(buff_len, GFP_ATOMIC);
+ if (bat_priv->tt_buff) {
+ memcpy(bat_priv->tt_buff, buff, buff_len);
+ bat_priv->tt_buff_len = buff_len;
+ }
+ }
+ spin_unlock_bh(&bat_priv->tt_buff_lock);
- /* if we did not get all new local tts see you next time ;-) */
- if (count == bat_priv->num_local_tt)
- atomic_set(&bat_priv->tt_local_changed, 0);
-
- spin_unlock_bh(&bat_priv->tt_lhash_lock);
- return count;
+ return tot_changes;
}
int tt_local_seq_print_text(struct seq_file *seq, void *offset)
@@@ -263,10 -319,8 +319,8 @@@
}
seq_printf(seq, "Locally retrieved addresses (from %s) "
- "announced via TT:\n",
- net_dev->name);
-
- spin_lock_bh(&bat_priv->tt_lhash_lock);
+ "announced via TT (TTVN: %u):\n",
+ net_dev->name, (uint8_t)atomic_read(&bat_priv->ttvn));
buf_size = 1;
/* Estimate length for: " * xx:xx:xx:xx:xx:xx\n" */
@@@ -281,7 -335,6 +335,6 @@@
buff = kmalloc(buf_size, GFP_ATOMIC);
if (!buff) {
- spin_unlock_bh(&bat_priv->tt_lhash_lock);
ret = -ENOMEM;
goto out;
}
@@@ -301,8 -354,6 +354,6 @@@
rcu_read_unlock();
}
- spin_unlock_bh(&bat_priv->tt_lhash_lock);
-
seq_printf(seq, "%s", buff);
kfree(buff);
out:
@@@ -311,92 -362,108 +362,108 @@@
return ret;
}
- static void _tt_local_del(struct hlist_node *node, void *arg)
- {
- struct bat_priv *bat_priv = arg;
- void *data = container_of(node, struct tt_local_entry, hash_entry);
-
- kfree(data);
- bat_priv->num_local_tt--;
- atomic_set(&bat_priv->tt_local_changed, 1);
- }
-
static void tt_local_del(struct bat_priv *bat_priv,
struct tt_local_entry *tt_local_entry,
const char *message)
{
- bat_dbg(DBG_ROUTES, bat_priv, "Deleting local tt entry (%pM): %s\n",
+ bat_dbg(DBG_TT, bat_priv, "Deleting local tt entry (%pM): %s\n",
tt_local_entry->addr, message);
+ atomic_dec(&bat_priv->num_local_tt);
+
hash_remove(bat_priv->tt_local_hash, compare_ltt, choose_orig,
tt_local_entry->addr);
- _tt_local_del(&tt_local_entry->hash_entry, bat_priv);
+
+ tt_local_entry_free_ref(tt_local_entry);
}
- void tt_local_remove(struct bat_priv *bat_priv,
- const uint8_t *addr, const char *message)
+ void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr,
+ const char *message, bool roaming)
{
- struct tt_local_entry *tt_local_entry;
-
- spin_lock_bh(&bat_priv->tt_lhash_lock);
+ struct tt_local_entry *tt_local_entry = NULL;
tt_local_entry = tt_local_hash_find(bat_priv, addr);
- if (tt_local_entry)
- tt_local_del(bat_priv, tt_local_entry, message);
+ if (!tt_local_entry)
+ goto out;
- spin_unlock_bh(&bat_priv->tt_lhash_lock);
+ tt_local_event(bat_priv, TT_CHANGE_DEL, tt_local_entry->addr, roaming);
+ tt_local_del(bat_priv, tt_local_entry, message);
+ out:
+ if (tt_local_entry)
+ tt_local_entry_free_ref(tt_local_entry);
}
- static void tt_local_purge(struct work_struct *work)
+ static void tt_local_purge(struct bat_priv *bat_priv)
{
- struct delayed_work *delayed_work =
- container_of(work, struct delayed_work, work);
- struct bat_priv *bat_priv =
- container_of(delayed_work, struct bat_priv, tt_work);
struct hashtable_t *hash = bat_priv->tt_local_hash;
struct tt_local_entry *tt_local_entry;
struct hlist_node *node, *node_tmp;
struct hlist_head *head;
- unsigned long timeout;
+ spinlock_t *list_lock; /* protects write access to the hash lists */
int i;
- spin_lock_bh(&bat_priv->tt_lhash_lock);
-
for (i = 0; i < hash->size; i++) {
head = &hash->table[i];
+ list_lock = &hash->list_locks[i];
+ spin_lock_bh(list_lock);
hlist_for_each_entry_safe(tt_local_entry, node, node_tmp,
head, hash_entry) {
if (tt_local_entry->never_purge)
continue;
- timeout = tt_local_entry->last_seen;
- timeout += TT_LOCAL_TIMEOUT * HZ;
-
- if (time_before(jiffies, timeout))
+ if (!is_out_of_time(tt_local_entry->last_seen,
+ TT_LOCAL_TIMEOUT * 1000))
continue;
- tt_local_del(bat_priv, tt_local_entry,
- "address timed out");
+ tt_local_event(bat_priv, TT_CHANGE_DEL,
+ tt_local_entry->addr, false);
+ atomic_dec(&bat_priv->num_local_tt);
+ bat_dbg(DBG_TT, bat_priv, "Deleting local "
+ "tt entry (%pM): timed out\n",
+ tt_local_entry->addr);
+ hlist_del_rcu(node);
+ tt_local_entry_free_ref(tt_local_entry);
}
+ spin_unlock_bh(list_lock);
}
- spin_unlock_bh(&bat_priv->tt_lhash_lock);
- tt_local_start_timer(bat_priv);
}
- void tt_local_free(struct bat_priv *bat_priv)
+ static void tt_local_table_free(struct bat_priv *bat_priv)
{
+ struct hashtable_t *hash;
+ spinlock_t *list_lock; /* protects write access to the hash lists */
+ struct tt_local_entry *tt_local_entry;
+ struct hlist_node *node, *node_tmp;
+ struct hlist_head *head;
+ int i;
+
if (!bat_priv->tt_local_hash)
return;
- cancel_delayed_work_sync(&bat_priv->tt_work);
- hash_delete(bat_priv->tt_local_hash, _tt_local_del, bat_priv);
+ hash = bat_priv->tt_local_hash;
+
+ for (i = 0; i < hash->size; i++) {
+ head = &hash->table[i];
+ list_lock = &hash->list_locks[i];
+
+ spin_lock_bh(list_lock);
+ hlist_for_each_entry_safe(tt_local_entry, node, node_tmp,
+ head, hash_entry) {
+ hlist_del_rcu(node);
+ tt_local_entry_free_ref(tt_local_entry);
+ }
+ spin_unlock_bh(list_lock);
+ }
+
+ hash_destroy(hash);
+
bat_priv->tt_local_hash = NULL;
}
- 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)
return 1;
@@@ -409,73 -476,78 +476,78 @@@
return 1;
}
- void tt_global_add_orig(struct bat_priv *bat_priv,
- struct orig_node *orig_node,
- const unsigned char *tt_buff, int tt_buff_len)
+ static void tt_changes_list_free(struct bat_priv *bat_priv)
{
- struct tt_global_entry *tt_global_entry;
- struct tt_local_entry *tt_local_entry;
- int tt_buff_count = 0;
- const unsigned char *tt_ptr;
-
- while ((tt_buff_count + 1) * ETH_ALEN <= tt_buff_len) {
- spin_lock_bh(&bat_priv->tt_ghash_lock);
-
- tt_ptr = tt_buff + (tt_buff_count * ETH_ALEN);
- tt_global_entry = tt_global_hash_find(bat_priv, tt_ptr);
-
- if (!tt_global_entry) {
- spin_unlock_bh(&bat_priv->tt_ghash_lock);
+ struct tt_change_node *entry, *safe;
- tt_global_entry = kmalloc(sizeof(*tt_global_entry),
- GFP_ATOMIC);
+ spin_lock_bh(&bat_priv->tt_changes_list_lock);
- if (!tt_global_entry)
- break;
+ list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list,
+ list) {
+ list_del(&entry->list);
+ kfree(entry);
+ }
- memcpy(tt_global_entry->addr, tt_ptr, ETH_ALEN);
+ atomic_set(&bat_priv->tt_local_changes, 0);
+ spin_unlock_bh(&bat_priv->tt_changes_list_lock);
+ }
- bat_dbg(DBG_ROUTES, bat_priv,
- "Creating new global tt entry: "
- "%pM (via %pM)\n",
- tt_global_entry->addr, orig_node->orig);
+ /* caller must hold orig_node refcount */
+ int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
+ const unsigned char *tt_addr, uint8_t ttvn, bool roaming)
+ {
+ struct tt_global_entry *tt_global_entry;
+ struct orig_node *orig_node_tmp;
+ int ret = 0;
- spin_lock_bh(&bat_priv->tt_ghash_lock);
- hash_add(bat_priv->tt_global_hash, compare_gtt,
- choose_orig, tt_global_entry,
- &tt_global_entry->hash_entry);
+ tt_global_entry = tt_global_hash_find(bat_priv, tt_addr);
- }
+ if (!tt_global_entry) {
+ tt_global_entry =
+ kmalloc(sizeof(*tt_global_entry),
+ GFP_ATOMIC);
+ if (!tt_global_entry)
+ goto out;
+ memcpy(tt_global_entry->addr, tt_addr, ETH_ALEN);
+ /* Assign the new orig_node */
+ atomic_inc(&orig_node->refcount);
tt_global_entry->orig_node = orig_node;
- spin_unlock_bh(&bat_priv->tt_ghash_lock);
-
- /* remove address from local hash if present */
- spin_lock_bh(&bat_priv->tt_lhash_lock);
-
- tt_ptr = tt_buff + (tt_buff_count * ETH_ALEN);
- tt_local_entry = tt_local_hash_find(bat_priv, tt_ptr);
-
- if (tt_local_entry)
- tt_local_del(bat_priv, tt_local_entry,
- "global tt received");
-
- spin_unlock_bh(&bat_priv->tt_lhash_lock);
-
- tt_buff_count++;
+ tt_global_entry->ttvn = ttvn;
+ tt_global_entry->flags = NO_FLAGS;
+ tt_global_entry->roam_at = 0;
+ atomic_set(&tt_global_entry->refcount, 2);
+
+ hash_add(bat_priv->tt_global_hash, compare_gtt,
+ choose_orig, tt_global_entry,
+ &tt_global_entry->hash_entry);
+ atomic_inc(&orig_node->tt_size);
+ } else {
+ if (tt_global_entry->orig_node != orig_node) {
+ atomic_dec(&tt_global_entry->orig_node->tt_size);
+ orig_node_tmp = tt_global_entry->orig_node;
+ atomic_inc(&orig_node->refcount);
+ tt_global_entry->orig_node = orig_node;
+ orig_node_free_ref(orig_node_tmp);
+ atomic_inc(&orig_node->tt_size);
+ }
+ tt_global_entry->ttvn = ttvn;
+ tt_global_entry->flags = NO_FLAGS;
+ tt_global_entry->roam_at = 0;
}
- /* initialize, and overwrite if malloc succeeds */
- orig_node->tt_buff = NULL;
- orig_node->tt_buff_len = 0;
+ bat_dbg(DBG_TT, bat_priv,
+ "Creating new global tt entry: %pM (via %pM)\n",
+ tt_global_entry->addr, orig_node->orig);
- if (tt_buff_len > 0) {
- orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC);
- if (orig_node->tt_buff) {
- memcpy(orig_node->tt_buff, tt_buff, tt_buff_len);
- orig_node->tt_buff_len = tt_buff_len;
- }
- }
+ /* remove address from local hash if present */
+ tt_local_remove(bat_priv, tt_global_entry->addr,
+ "global tt received", roaming);
+ ret = 1;
+ out:
+ if (tt_global_entry)
+ tt_global_entry_free_ref(tt_global_entry);
+ return ret;
}
int tt_global_seq_print_text(struct seq_file *seq, void *offset)
@@@ -509,26 -581,27 +581,27 @@@
seq_printf(seq,
"Globally announced TT entries received via the mesh %s\n",
net_dev->name);
-
- spin_lock_bh(&bat_priv->tt_ghash_lock);
+ seq_printf(seq, " %-13s %s %-15s %s\n",
+ "Client", "(TTVN)", "Originator", "(Curr TTVN)");
buf_size = 1;
- /* Estimate length for: " * xx:xx:xx:xx:xx:xx via xx:xx:xx:xx:xx:xx\n"*/
+ /* Estimate length for: " * xx:xx:xx:xx:xx:xx (ttvn) via
+ * xx:xx:xx:xx:xx:xx (cur_ttvn)\n"*/
for (i = 0; i < hash->size; i++) {
head = &hash->table[i];
rcu_read_lock();
__hlist_for_each_rcu(node, head)
- buf_size += 43;
+ buf_size += 59;
rcu_read_unlock();
}
buff = kmalloc(buf_size, GFP_ATOMIC);
if (!buff) {
ret = -ENOMEM;
goto out;
}
+
buff[0] = '\0';
pos = 0;
@@@ -538,16 -611,18 +611,18 @@@
rcu_read_lock();
hlist_for_each_entry_rcu(tt_global_entry, node,
head, hash_entry) {
- pos += snprintf(buff + pos, 44,
- " * %pM via %pM\n",
+ pos += snprintf(buff + pos, 61,
+ " * %pM (%3u) via %pM (%3u)\n",
tt_global_entry->addr,
- tt_global_entry->orig_node->orig);
+ tt_global_entry->ttvn,
+ tt_global_entry->orig_node->orig,
+ (uint8_t) atomic_read(
+ &tt_global_entry->orig_node->
+ last_ttvn));
}
rcu_read_unlock();
}
- spin_unlock_bh(&bat_priv->tt_ghash_lock);
-
seq_printf(seq, "%s", buff);
kfree(buff);
out:
@@@ -556,64 -631,145 +631,145 @@@
return ret;
}
- static void _tt_global_del_orig(struct bat_priv *bat_priv,
- struct tt_global_entry *tt_global_entry,
- const char *message)
+ static void _tt_global_del(struct bat_priv *bat_priv,
+ struct tt_global_entry *tt_global_entry,
+ const char *message)
{
- bat_dbg(DBG_ROUTES, bat_priv,
+ if (!tt_global_entry)
+ goto out;
+
+ bat_dbg(DBG_TT, bat_priv,
"Deleting global tt entry %pM (via %pM): %s\n",
tt_global_entry->addr, tt_global_entry->orig_node->orig,
message);
+ atomic_dec(&tt_global_entry->orig_node->tt_size);
+
hash_remove(bat_priv->tt_global_hash, compare_gtt, choose_orig,
tt_global_entry->addr);
- kfree(tt_global_entry);
+ out:
+ if (tt_global_entry)
+ tt_global_entry_free_ref(tt_global_entry);
}
- void tt_global_del_orig(struct bat_priv *bat_priv,
- struct orig_node *orig_node, const char *message)
+ void tt_global_del(struct bat_priv *bat_priv,
+ struct orig_node *orig_node, const unsigned char *addr,
+ const char *message, bool roaming)
{
- struct tt_global_entry *tt_global_entry;
- int tt_buff_count = 0;
- unsigned char *tt_ptr;
+ struct tt_global_entry *tt_global_entry = NULL;
- if (orig_node->tt_buff_len == 0)
- return;
+ tt_global_entry = tt_global_hash_find(bat_priv, addr);
+ if (!tt_global_entry)
+ goto out;
- spin_lock_bh(&bat_priv->tt_ghash_lock);
+ if (tt_global_entry->orig_node == orig_node) {
+ if (roaming) {
+ tt_global_entry->flags |= TT_CLIENT_ROAM;
+ tt_global_entry->roam_at = jiffies;
+ goto out;
+ }
+ _tt_global_del(bat_priv, tt_global_entry, message);
+ }
+ out:
+ if (tt_global_entry)
+ tt_global_entry_free_ref(tt_global_entry);
+ }
- while ((tt_buff_count + 1) * ETH_ALEN <= orig_node->tt_buff_len) {
- tt_ptr = orig_node->tt_buff + (tt_buff_count * ETH_ALEN);
- tt_global_entry = tt_global_hash_find(bat_priv, tt_ptr);
+ void tt_global_del_orig(struct bat_priv *bat_priv,
+ struct orig_node *orig_node, const char *message)
+ {
+ struct tt_global_entry *tt_global_entry;
+ int i;
+ struct hashtable_t *hash = bat_priv->tt_global_hash;
+ struct hlist_node *node, *safe;
+ struct hlist_head *head;
+ spinlock_t *list_lock; /* protects write access to the hash lists */
- if ((tt_global_entry) &&
- (tt_global_entry->orig_node == orig_node))
- _tt_global_del_orig(bat_priv, tt_global_entry,
- message);
+ for (i = 0; i < hash->size; i++) {
+ head = &hash->table[i];
+ list_lock = &hash->list_locks[i];
- tt_buff_count++;
+ spin_lock_bh(list_lock);
+ hlist_for_each_entry_safe(tt_global_entry, node, safe,
+ head, hash_entry) {
+ if (tt_global_entry->orig_node == orig_node) {
+ bat_dbg(DBG_TT, bat_priv,
+ "Deleting global tt entry %pM "
+ "(via %pM): originator time out\n",
+ tt_global_entry->addr,
+ tt_global_entry->orig_node->orig);
+ hlist_del_rcu(node);
+ tt_global_entry_free_ref(tt_global_entry);
+ }
+ }
+ spin_unlock_bh(list_lock);
}
-
- spin_unlock_bh(&bat_priv->tt_ghash_lock);
-
- orig_node->tt_buff_len = 0;
- kfree(orig_node->tt_buff);
- orig_node->tt_buff = NULL;
+ atomic_set(&orig_node->tt_size, 0);
}
- static void tt_global_del(struct hlist_node *node, void *arg)
+ static void tt_global_roam_purge(struct bat_priv *bat_priv)
{
- void *data = container_of(node, struct tt_global_entry, hash_entry);
+ struct hashtable_t *hash = bat_priv->tt_global_hash;
+ struct tt_global_entry *tt_global_entry;
+ struct hlist_node *node, *node_tmp;
+ struct hlist_head *head;
+ spinlock_t *list_lock; /* protects write access to the hash lists */
+ int i;
+
+ for (i = 0; i < hash->size; i++) {
+ head = &hash->table[i];
+ list_lock = &hash->list_locks[i];
+
+ spin_lock_bh(list_lock);
+ hlist_for_each_entry_safe(tt_global_entry, node, node_tmp,
+ head, hash_entry) {
+ if (!(tt_global_entry->flags & TT_CLIENT_ROAM))
+ continue;
+ if (!is_out_of_time(tt_global_entry->roam_at,
+ TT_CLIENT_ROAM_TIMEOUT * 1000))
+ continue;
+
+ bat_dbg(DBG_TT, bat_priv, "Deleting global "
+ "tt entry (%pM): Roaming timeout\n",
+ tt_global_entry->addr);
+ atomic_dec(&tt_global_entry->orig_node->tt_size);
+ hlist_del_rcu(node);
+ tt_global_entry_free_ref(tt_global_entry);
+ }
+ spin_unlock_bh(list_lock);
+ }
- kfree(data);
}
- void tt_global_free(struct bat_priv *bat_priv)
+ static void tt_global_table_free(struct bat_priv *bat_priv)
{
+ struct hashtable_t *hash;
+ spinlock_t *list_lock; /* protects write access to the hash lists */
+ struct tt_global_entry *tt_global_entry;
+ struct hlist_node *node, *node_tmp;
+ struct hlist_head *head;
+ int i;
+
if (!bat_priv->tt_global_hash)
return;
- hash_delete(bat_priv->tt_global_hash, tt_global_del, NULL);
+ hash = bat_priv->tt_global_hash;
+
+ for (i = 0; i < hash->size; i++) {
+ head = &hash->table[i];
+ list_lock = &hash->list_locks[i];
+
+ spin_lock_bh(list_lock);
+ hlist_for_each_entry_safe(tt_global_entry, node, node_tmp,
+ head, hash_entry) {
+ hlist_del_rcu(node);
+ tt_global_entry_free_ref(tt_global_entry);
+ }
+ spin_unlock_bh(list_lock);
+ }
+
+ hash_destroy(hash);
+
bat_priv->tt_global_hash = NULL;
}
@@@ -623,18 -779,846 +779,846 @@@ struct orig_node *transtable_search(str
struct tt_global_entry *tt_global_entry;
struct orig_node *orig_node = NULL;
- spin_lock_bh(&bat_priv->tt_ghash_lock);
tt_global_entry = tt_global_hash_find(bat_priv, addr);
if (!tt_global_entry)
goto out;
if (!atomic_inc_not_zero(&tt_global_entry->orig_node->refcount))
- goto out;
+ goto free_tt;
orig_node = tt_global_entry->orig_node;
+ free_tt:
+ tt_global_entry_free_ref(tt_global_entry);
out:
- spin_unlock_bh(&bat_priv->tt_ghash_lock);
return orig_node;
}
+
+ /* Calculates the checksum of the local table of a given orig_node */
+ uint16_t tt_global_crc(struct bat_priv *bat_priv, struct orig_node *orig_node)
+ {
+ uint16_t total = 0, total_one;
+ struct hashtable_t *hash = bat_priv->tt_global_hash;
+ struct tt_global_entry *tt_global_entry;
+ struct hlist_node *node;
+ struct hlist_head *head;
+ int i, j;
+
+ for (i = 0; i < hash->size; i++) {
+ head = &hash->table[i];
+
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(tt_global_entry, node,
+ head, hash_entry) {
+ if (compare_eth(tt_global_entry->orig_node,
+ orig_node)) {
+ /* Roaming clients are in the global table for
+ * consistency only. They don't have to be
+ * taken into account while computing the
+ * global crc */
+ if (tt_global_entry->flags & TT_CLIENT_ROAM)
+ continue;
+ total_one = 0;
+ for (j = 0; j < ETH_ALEN; j++)
+ total_one = crc16_byte(total_one,
+ tt_global_entry->addr[j]);
+ total ^= total_one;
+ }
+ }
+ rcu_read_unlock();
+ }
+
+ return total;
+ }
+
+ /* Calculates the checksum of the local table */
+ uint16_t tt_local_crc(struct bat_priv *bat_priv)
+ {
+ uint16_t total = 0, total_one;
+ struct hashtable_t *hash = bat_priv->tt_local_hash;
+ struct tt_local_entry *tt_local_entry;
+ struct hlist_node *node;
+ struct hlist_head *head;
+ int i, j;
+
+ for (i = 0; i < hash->size; i++) {
+ head = &hash->table[i];
+
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(tt_local_entry, node,
+ head, hash_entry) {
+ total_one = 0;
+ for (j = 0; j < ETH_ALEN; j++)
+ total_one = crc16_byte(total_one,
+ tt_local_entry->addr[j]);
+ total ^= total_one;
+ }
+ rcu_read_unlock();
+ }
+
+ return total;
+ }
+
+ static void tt_req_list_free(struct bat_priv *bat_priv)
+ {
+ struct tt_req_node *node, *safe;
+
+ spin_lock_bh(&bat_priv->tt_req_list_lock);
+
+ list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
+ list_del(&node->list);
+ kfree(node);
+ }
+
+ spin_unlock_bh(&bat_priv->tt_req_list_lock);
+ }
+
+ void tt_save_orig_buffer(struct bat_priv *bat_priv, struct orig_node *orig_node,
+ const unsigned char *tt_buff, uint8_t tt_num_changes)
+ {
+ uint16_t tt_buff_len = tt_len(tt_num_changes);
+
+ /* Replace the old buffer only if I received something in the
+ * last OGM (the OGM could carry no changes) */
+ spin_lock_bh(&orig_node->tt_buff_lock);
+ if (tt_buff_len > 0) {
+ kfree(orig_node->tt_buff);
+ orig_node->tt_buff_len = 0;
+ orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC);
+ if (orig_node->tt_buff) {
+ memcpy(orig_node->tt_buff, tt_buff, tt_buff_len);
+ orig_node->tt_buff_len = tt_buff_len;
+ }
+ }
+ spin_unlock_bh(&orig_node->tt_buff_lock);
+ }
+
+ static void tt_req_purge(struct bat_priv *bat_priv)
+ {
+ struct tt_req_node *node, *safe;
+
+ spin_lock_bh(&bat_priv->tt_req_list_lock);
+ list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
+ if (is_out_of_time(node->issued_at,
+ TT_REQUEST_TIMEOUT * 1000)) {
+ list_del(&node->list);
+ kfree(node);
+ }
+ }
+ spin_unlock_bh(&bat_priv->tt_req_list_lock);
+ }
+
+ /* returns the pointer to the new tt_req_node struct if no request
+ * has already been issued for this orig_node, NULL otherwise */
+ static struct tt_req_node *new_tt_req_node(struct bat_priv *bat_priv,
+ struct orig_node *orig_node)
+ {
+ struct tt_req_node *tt_req_node_tmp, *tt_req_node = NULL;
+
+ spin_lock_bh(&bat_priv->tt_req_list_lock);
+ list_for_each_entry(tt_req_node_tmp, &bat_priv->tt_req_list, list) {
+ if (compare_eth(tt_req_node_tmp, orig_node) &&
+ !is_out_of_time(tt_req_node_tmp->issued_at,
+ TT_REQUEST_TIMEOUT * 1000))
+ goto unlock;
+ }
+
+ tt_req_node = kmalloc(sizeof(*tt_req_node), GFP_ATOMIC);
+ if (!tt_req_node)
+ goto unlock;
+
+ memcpy(tt_req_node->addr, orig_node->orig, ETH_ALEN);
+ tt_req_node->issued_at = jiffies;
+
+ list_add(&tt_req_node->list, &bat_priv->tt_req_list);
+ unlock:
+ spin_unlock_bh(&bat_priv->tt_req_list_lock);
+ return tt_req_node;
+ }
+
+ static int tt_global_valid_entry(const void *entry_ptr, const void *data_ptr)
+ {
+ const struct tt_global_entry *tt_global_entry = entry_ptr;
+ const struct orig_node *orig_node = data_ptr;
+
+ if (tt_global_entry->flags & TT_CLIENT_ROAM)
+ return 0;
+
+ return (tt_global_entry->orig_node == orig_node);
+ }
+
+ static struct sk_buff *tt_response_fill_table(uint16_t tt_len, uint8_t ttvn,
+ struct hashtable_t *hash,
+ struct hard_iface *primary_if,
+ int (*valid_cb)(const void *,
+ const void *),
+ void *cb_data)
+ {
+ struct tt_local_entry *tt_local_entry;
+ struct tt_query_packet *tt_response;
+ struct tt_change *tt_change;
+ struct hlist_node *node;
+ struct hlist_head *head;
+ struct sk_buff *skb = NULL;
+ uint16_t tt_tot, tt_count;
+ ssize_t tt_query_size = sizeof(struct tt_query_packet);
+ int i;
+
+ if (tt_query_size + tt_len > primary_if->soft_iface->mtu) {
+ tt_len = primary_if->soft_iface->mtu - tt_query_size;
+ tt_len -= tt_len % sizeof(struct tt_change);
+ }
+ tt_tot = tt_len / sizeof(struct tt_change);
+
+ skb = dev_alloc_skb(tt_query_size + tt_len + ETH_HLEN);
+ if (!skb)
+ goto out;
+
+ skb_reserve(skb, ETH_HLEN);
+ tt_response = (struct tt_query_packet *)skb_put(skb,
+ tt_query_size + tt_len);
+ tt_response->ttvn = ttvn;
+ tt_response->tt_data = htons(tt_tot);
+
+ tt_change = (struct tt_change *)(skb->data + tt_query_size);
+ tt_count = 0;
+
+ rcu_read_lock();
+ for (i = 0; i < hash->size; i++) {
+ head = &hash->table[i];
+
+ hlist_for_each_entry_rcu(tt_local_entry, node,
+ head, hash_entry) {
+ if (tt_count == tt_tot)
+ break;
+
+ if ((valid_cb) && (!valid_cb(tt_local_entry, cb_data)))
+ continue;
+
+ memcpy(tt_change->addr, tt_local_entry->addr, ETH_ALEN);
+ tt_change->flags = NO_FLAGS;
+
+ tt_count++;
+ tt_change++;
+ }
+ }
+ rcu_read_unlock();
+
+ out:
+ return skb;
+ }
+
+ int send_tt_request(struct bat_priv *bat_priv, struct orig_node *dst_orig_node,
+ uint8_t ttvn, uint16_t tt_crc, bool full_table)
+ {
+ struct sk_buff *skb = NULL;
+ struct tt_query_packet *tt_request;
+ struct neigh_node *neigh_node = NULL;
+ struct hard_iface *primary_if;
+ struct tt_req_node *tt_req_node = NULL;
+ int ret = 1;
+
+ primary_if = primary_if_get_selected(bat_priv);
+ if (!primary_if)
+ goto out;
+
+ /* The new tt_req will be issued only if I'm not waiting for a
+ * reply from the same orig_node yet */
+ tt_req_node = new_tt_req_node(bat_priv, dst_orig_node);
+ if (!tt_req_node)
+ goto out;
+
+ skb = dev_alloc_skb(sizeof(struct tt_query_packet) + ETH_HLEN);
+ if (!skb)
+ goto out;
+
+ skb_reserve(skb, ETH_HLEN);
+
+ tt_request = (struct tt_query_packet *)skb_put(skb,
+ sizeof(struct tt_query_packet));
+
+ tt_request->packet_type = BAT_TT_QUERY;
+ tt_request->version = COMPAT_VERSION;
+ memcpy(tt_request->src, primary_if->net_dev->dev_addr, ETH_ALEN);
+ memcpy(tt_request->dst, dst_orig_node->orig, ETH_ALEN);
+ tt_request->ttl = TTL;
+ tt_request->ttvn = ttvn;
+ tt_request->tt_data = tt_crc;
+ tt_request->flags = TT_REQUEST;
+
+ if (full_table)
+ tt_request->flags |= TT_FULL_TABLE;
+
+ neigh_node = orig_node_get_router(dst_orig_node);
+ if (!neigh_node)
+ goto out;
+
+ bat_dbg(DBG_TT, bat_priv, "Sending TT_REQUEST to %pM via %pM "
+ "[%c]\n", dst_orig_node->orig, neigh_node->addr,
+ (full_table ? 'F' : '.'));
+
+ send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
+ ret = 0;
+
+ out:
+ if (neigh_node)
+ neigh_node_free_ref(neigh_node);
+ if (primary_if)
+ hardif_free_ref(primary_if);
+ if (ret)
+ kfree_skb(skb);
+ if (ret && tt_req_node) {
+ spin_lock_bh(&bat_priv->tt_req_list_lock);
+ list_del(&tt_req_node->list);
+ spin_unlock_bh(&bat_priv->tt_req_list_lock);
+ kfree(tt_req_node);
+ }
+ return ret;
+ }
+
+ static bool send_other_tt_response(struct bat_priv *bat_priv,
+ struct tt_query_packet *tt_request)
+ {
+ struct orig_node *req_dst_orig_node = NULL, *res_dst_orig_node = NULL;
+ struct neigh_node *neigh_node = NULL;
+ struct hard_iface *primary_if = NULL;
+ uint8_t orig_ttvn, req_ttvn, ttvn;
+ int ret = false;
+ unsigned char *tt_buff;
+ bool full_table;
+ uint16_t tt_len, tt_tot;
+ struct sk_buff *skb = NULL;
+ struct tt_query_packet *tt_response;
+
+ bat_dbg(DBG_TT, bat_priv,
+ "Received TT_REQUEST from %pM for "
+ "ttvn: %u (%pM) [%c]\n", tt_request->src,
+ tt_request->ttvn, tt_request->dst,
+ (tt_request->flags & TT_FULL_TABLE ? 'F' : '.'));
+
+ /* Let's get the orig node of the REAL destination */
+ req_dst_orig_node = get_orig_node(bat_priv, tt_request->dst);
+ if (!req_dst_orig_node)
+ goto out;
+
+ res_dst_orig_node = get_orig_node(bat_priv, tt_request->src);
+ if (!res_dst_orig_node)
+ goto out;
+
+ neigh_node = orig_node_get_router(res_dst_orig_node);
+ if (!neigh_node)
+ goto out;
+
+ primary_if = primary_if_get_selected(bat_priv);
+ if (!primary_if)
+ goto out;
+
+ orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn);
+ req_ttvn = tt_request->ttvn;
+
+ /* I have not the requested data */
+ if (orig_ttvn != req_ttvn ||
+ tt_request->tt_data != req_dst_orig_node->tt_crc)
+ goto out;
+
+ /* If it has explicitly been requested the full table */
+ if (tt_request->flags & TT_FULL_TABLE ||
+ !req_dst_orig_node->tt_buff)
+ full_table = true;
+ else
+ full_table = false;
+
+ /* In this version, fragmentation is not implemented, then
+ * I'll send only one packet with as much TT entries as I can */
+ if (!full_table) {
+ spin_lock_bh(&req_dst_orig_node->tt_buff_lock);
+ tt_len = req_dst_orig_node->tt_buff_len;
+ tt_tot = tt_len / sizeof(struct tt_change);
+
+ skb = dev_alloc_skb(sizeof(struct tt_query_packet) +
+ tt_len + ETH_HLEN);
+ if (!skb)
+ goto unlock;
+
+ skb_reserve(skb, ETH_HLEN);
+ tt_response = (struct tt_query_packet *)skb_put(skb,
+ sizeof(struct tt_query_packet) + tt_len);
+ tt_response->ttvn = req_ttvn;
+ tt_response->tt_data = htons(tt_tot);
+
+ tt_buff = skb->data + sizeof(struct tt_query_packet);
+ /* Copy the last orig_node's OGM buffer */
+ memcpy(tt_buff, req_dst_orig_node->tt_buff,
+ req_dst_orig_node->tt_buff_len);
+
+ spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
+ } else {
+ tt_len = (uint16_t)atomic_read(&req_dst_orig_node->tt_size) *
+ sizeof(struct tt_change);
+ ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn);
+
+ skb = tt_response_fill_table(tt_len, ttvn,
+ bat_priv->tt_global_hash,
+ primary_if, tt_global_valid_entry,
+ req_dst_orig_node);
+ if (!skb)
+ goto out;
+
+ tt_response = (struct tt_query_packet *)skb->data;
+ }
+
+ tt_response->packet_type = BAT_TT_QUERY;
+ tt_response->version = COMPAT_VERSION;
+ tt_response->ttl = TTL;
+ memcpy(tt_response->src, req_dst_orig_node->orig, ETH_ALEN);
+ memcpy(tt_response->dst, tt_request->src, ETH_ALEN);
+ tt_response->flags = TT_RESPONSE;
+
+ if (full_table)
+ tt_response->flags |= TT_FULL_TABLE;
+
+ bat_dbg(DBG_TT, bat_priv,
+ "Sending TT_RESPONSE %pM via %pM for %pM (ttvn: %u)\n",
+ res_dst_orig_node->orig, neigh_node->addr,
+ req_dst_orig_node->orig, req_ttvn);
+
+ send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
+ ret = true;
+ goto out;
+
+ unlock:
+ spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
+
+ out:
+ if (res_dst_orig_node)
+ orig_node_free_ref(res_dst_orig_node);
+ if (req_dst_orig_node)
+ orig_node_free_ref(req_dst_orig_node);
+ if (neigh_node)
+ neigh_node_free_ref(neigh_node);
+ if (primary_if)
+ hardif_free_ref(primary_if);
+ if (!ret)
+ kfree_skb(skb);
+ return ret;
+
+ }
+ static bool send_my_tt_response(struct bat_priv *bat_priv,
+ struct tt_query_packet *tt_request)
+ {
+ struct orig_node *orig_node = NULL;
+ struct neigh_node *neigh_node = NULL;
+ struct hard_iface *primary_if = NULL;
+ uint8_t my_ttvn, req_ttvn, ttvn;
+ int ret = false;
+ unsigned char *tt_buff;
+ bool full_table;
+ uint16_t tt_len, tt_tot;
+ struct sk_buff *skb = NULL;
+ struct tt_query_packet *tt_response;
+
+ bat_dbg(DBG_TT, bat_priv,
+ "Received TT_REQUEST from %pM for "
+ "ttvn: %u (me) [%c]\n", tt_request->src,
+ tt_request->ttvn,
+ (tt_request->flags & TT_FULL_TABLE ? 'F' : '.'));
+
+
+ my_ttvn = (uint8_t)atomic_read(&bat_priv->ttvn);
+ req_ttvn = tt_request->ttvn;
+
+ orig_node = get_orig_node(bat_priv, tt_request->src);
+ if (!orig_node)
+ goto out;
+
+ neigh_node = orig_node_get_router(orig_node);
+ if (!neigh_node)
+ goto out;
+
+ primary_if = primary_if_get_selected(bat_priv);
+ if (!primary_if)
+ goto out;
+
+ /* If the full table has been explicitly requested or the gap
+ * is too big send the whole local translation table */
+ if (tt_request->flags & TT_FULL_TABLE || my_ttvn != req_ttvn ||
+ !bat_priv->tt_buff)
+ full_table = true;
+ else
+ full_table = false;
+
+ /* In this version, fragmentation is not implemented, then
+ * I'll send only one packet with as much TT entries as I can */
+ if (!full_table) {
+ spin_lock_bh(&bat_priv->tt_buff_lock);
+ tt_len = bat_priv->tt_buff_len;
+ tt_tot = tt_len / sizeof(struct tt_change);
+
+ skb = dev_alloc_skb(sizeof(struct tt_query_packet) +
+ tt_len + ETH_HLEN);
+ if (!skb)
+ goto unlock;
+
+ skb_reserve(skb, ETH_HLEN);
+ tt_response = (struct tt_query_packet *)skb_put(skb,
+ sizeof(struct tt_query_packet) + tt_len);
+ tt_response->ttvn = req_ttvn;
+ tt_response->tt_data = htons(tt_tot);
+
+ tt_buff = skb->data + sizeof(struct tt_query_packet);
+ memcpy(tt_buff, bat_priv->tt_buff,
+ bat_priv->tt_buff_len);
+ spin_unlock_bh(&bat_priv->tt_buff_lock);
+ } else {
+ tt_len = (uint16_t)atomic_read(&bat_priv->num_local_tt) *
+ sizeof(struct tt_change);
+ ttvn = (uint8_t)atomic_read(&bat_priv->ttvn);
+
+ skb = tt_response_fill_table(tt_len, ttvn,
+ bat_priv->tt_local_hash,
+ primary_if, NULL, NULL);
+ if (!skb)
+ goto out;
+
+ tt_response = (struct tt_query_packet *)skb->data;
+ }
+
+ tt_response->packet_type = BAT_TT_QUERY;
+ tt_response->version = COMPAT_VERSION;
+ tt_response->ttl = TTL;
+ memcpy(tt_response->src, primary_if->net_dev->dev_addr, ETH_ALEN);
+ memcpy(tt_response->dst, tt_request->src, ETH_ALEN);
+ tt_response->flags = TT_RESPONSE;
+
+ if (full_table)
+ tt_response->flags |= TT_FULL_TABLE;
+
+ bat_dbg(DBG_TT, bat_priv,
+ "Sending TT_RESPONSE to %pM via %pM [%c]\n",
+ orig_node->orig, neigh_node->addr,
+ (tt_response->flags & TT_FULL_TABLE ? 'F' : '.'));
+
+ send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
+ ret = true;
+ goto out;
+
+ unlock:
+ spin_unlock_bh(&bat_priv->tt_buff_lock);
+ out:
+ if (orig_node)
+ orig_node_free_ref(orig_node);
+ if (neigh_node)
+ neigh_node_free_ref(neigh_node);
+ if (primary_if)
+ hardif_free_ref(primary_if);
+ if (!ret)
+ kfree_skb(skb);
+ /* This packet was for me, so it doesn't need to be re-routed */
+ return true;
+ }
+
+ bool send_tt_response(struct bat_priv *bat_priv,
+ struct tt_query_packet *tt_request)
+ {
+ if (is_my_mac(tt_request->dst))
+ return send_my_tt_response(bat_priv, tt_request);
+ else
+ return send_other_tt_response(bat_priv, tt_request);
+ }
+
+ static void _tt_update_changes(struct bat_priv *bat_priv,
+ struct orig_node *orig_node,
+ struct tt_change *tt_change,
+ uint16_t tt_num_changes, uint8_t ttvn)
+ {
+ int i;
+
+ for (i = 0; i < tt_num_changes; i++) {
+ if ((tt_change + i)->flags & TT_CHANGE_DEL)
+ tt_global_del(bat_priv, orig_node,
+ (tt_change + i)->addr,
+ "tt removed by changes",
+ (tt_change + i)->flags & TT_CLIENT_ROAM);
+ else
+ if (!tt_global_add(bat_priv, orig_node,
+ (tt_change + i)->addr, ttvn, false))
+ /* In case of problem while storing a
+ * global_entry, we stop the updating
+ * procedure without committing the
+ * ttvn change. This will avoid to send
+ * corrupted data on tt_request
+ */
+ return;
+ }
+ }
+
+ static void tt_fill_gtable(struct bat_priv *bat_priv,
+ struct tt_query_packet *tt_response)
+ {
+ struct orig_node *orig_node = NULL;
+
+ orig_node = orig_hash_find(bat_priv, tt_response->src);
+ if (!orig_node)
+ goto out;
+
+ /* Purge the old table first.. */
+ tt_global_del_orig(bat_priv, orig_node, "Received full table");
+
+ _tt_update_changes(bat_priv, orig_node,
+ (struct tt_change *)(tt_response + 1),
+ tt_response->tt_data, tt_response->ttvn);
+
+ spin_lock_bh(&orig_node->tt_buff_lock);
+ kfree(orig_node->tt_buff);
+ orig_node->tt_buff_len = 0;
+ orig_node->tt_buff = NULL;
+ spin_unlock_bh(&orig_node->tt_buff_lock);
+
+ atomic_set(&orig_node->last_ttvn, tt_response->ttvn);
+
+ out:
+ if (orig_node)
+ orig_node_free_ref(orig_node);
+ }
+
+ void tt_update_changes(struct bat_priv *bat_priv, struct orig_node *orig_node,
+ uint16_t tt_num_changes, uint8_t ttvn,
+ struct tt_change *tt_change)
+ {
+ _tt_update_changes(bat_priv, orig_node, tt_change, tt_num_changes,
+ ttvn);
+
+ tt_save_orig_buffer(bat_priv, orig_node, (unsigned char *)tt_change,
+ tt_num_changes);
+ atomic_set(&orig_node->last_ttvn, ttvn);
+ }
+
+ bool is_my_client(struct bat_priv *bat_priv, const uint8_t *addr)
+ {
+ struct tt_local_entry *tt_local_entry = NULL;
+ bool ret = false;
+
+ tt_local_entry = tt_local_hash_find(bat_priv, addr);
+ if (!tt_local_entry)
+ goto out;
+ ret = true;
+ out:
+ if (tt_local_entry)
+ tt_local_entry_free_ref(tt_local_entry);
+ return ret;
+ }
+
+ void handle_tt_response(struct bat_priv *bat_priv,
+ struct tt_query_packet *tt_response)
+ {
+ struct tt_req_node *node, *safe;
+ struct orig_node *orig_node = NULL;
+
+ 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->flags & TT_FULL_TABLE ? 'F' : '.'));
+
+ orig_node = orig_hash_find(bat_priv, tt_response->src);
+ if (!orig_node)
+ goto out;
+
+ 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_response->ttvn,
+ (struct tt_change *)(tt_response + 1));
+
+ /* Delete the tt_req_node from pending tt_requests list */
+ spin_lock_bh(&bat_priv->tt_req_list_lock);
+ list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
+ if (!compare_eth(node->addr, tt_response->src))
+ continue;
+ list_del(&node->list);
+ kfree(node);
+ }
+ spin_unlock_bh(&bat_priv->tt_req_list_lock);
+
+ /* Recalculate the CRC for this orig_node and store it */
+ orig_node->tt_crc = tt_global_crc(bat_priv, orig_node);
+ /* Roaming phase is over: tables are in sync again. I can
+ * unset the flag */
+ orig_node->tt_poss_change = false;
+ out:
+ if (orig_node)
+ orig_node_free_ref(orig_node);
+ }
+
+ int tt_init(struct bat_priv *bat_priv)
+ {
+ if (!tt_local_init(bat_priv))
+ return 0;
+
+ if (!tt_global_init(bat_priv))
+ return 0;
+
+ tt_start_timer(bat_priv);
+
+ return 1;
+ }
+
+ static void tt_roam_list_free(struct bat_priv *bat_priv)
+ {
+ struct tt_roam_node *node, *safe;
+
+ spin_lock_bh(&bat_priv->tt_roam_list_lock);
+
+ list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) {
+ list_del(&node->list);
+ kfree(node);
+ }
+
+ spin_unlock_bh(&bat_priv->tt_roam_list_lock);
+ }
+
+ static void tt_roam_purge(struct bat_priv *bat_priv)
+ {
+ struct tt_roam_node *node, *safe;
+
+ spin_lock_bh(&bat_priv->tt_roam_list_lock);
+ list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) {
+ if (!is_out_of_time(node->first_time,
+ ROAMING_MAX_TIME * 1000))
+ continue;
+
+ list_del(&node->list);
+ kfree(node);
+ }
+ spin_unlock_bh(&bat_priv->tt_roam_list_lock);
+ }
+
+ /* This function checks whether the client already reached the
+ * maximum number of possible roaming phases. In this case the ROAMING_ADV
+ * will not be sent.
+ *
+ * returns true if the ROAMING_ADV can be sent, false otherwise */
+ static bool tt_check_roam_count(struct bat_priv *bat_priv,
+ uint8_t *client)
+ {
+ struct tt_roam_node *tt_roam_node;
+ bool ret = false;
+
+ spin_lock_bh(&bat_priv->tt_roam_list_lock);
+ /* The new tt_req will be issued only if I'm not waiting for a
+ * reply from the same orig_node yet */
+ list_for_each_entry(tt_roam_node, &bat_priv->tt_roam_list, list) {
+ if (!compare_eth(tt_roam_node->addr, client))
+ continue;
+
+ if (is_out_of_time(tt_roam_node->first_time,
+ ROAMING_MAX_TIME * 1000))
+ continue;
+
+ if (!atomic_dec_not_zero(&tt_roam_node->counter))
+ /* Sorry, you roamed too many times! */
+ goto unlock;
+ ret = true;
+ break;
+ }
+
+ if (!ret) {
+ tt_roam_node = kmalloc(sizeof(*tt_roam_node), GFP_ATOMIC);
+ if (!tt_roam_node)
+ goto unlock;
+
+ tt_roam_node->first_time = jiffies;
+ atomic_set(&tt_roam_node->counter, ROAMING_MAX_COUNT - 1);
+ memcpy(tt_roam_node->addr, client, ETH_ALEN);
+
+ list_add(&tt_roam_node->list, &bat_priv->tt_roam_list);
+ ret = true;
+ }
+
+ unlock:
+ spin_unlock_bh(&bat_priv->tt_roam_list_lock);
+ return ret;
+ }
+
+ void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
+ struct orig_node *orig_node)
+ {
+ struct neigh_node *neigh_node = NULL;
+ struct sk_buff *skb = NULL;
+ struct roam_adv_packet *roam_adv_packet;
+ int ret = 1;
+ struct hard_iface *primary_if;
+
+ /* before going on we have to check whether the client has
+ * already roamed to us too many times */
+ if (!tt_check_roam_count(bat_priv, client))
+ goto out;
+
+ skb = dev_alloc_skb(sizeof(struct roam_adv_packet) + ETH_HLEN);
+ if (!skb)
+ goto out;
+
+ skb_reserve(skb, ETH_HLEN);
+
+ roam_adv_packet = (struct roam_adv_packet *)skb_put(skb,
+ sizeof(struct roam_adv_packet));
+
+ roam_adv_packet->packet_type = BAT_ROAM_ADV;
+ roam_adv_packet->version = COMPAT_VERSION;
+ roam_adv_packet->ttl = TTL;
+ primary_if = primary_if_get_selected(bat_priv);
+ if (!primary_if)
+ goto out;
+ memcpy(roam_adv_packet->src, primary_if->net_dev->dev_addr, ETH_ALEN);
+ hardif_free_ref(primary_if);
+ memcpy(roam_adv_packet->dst, orig_node->orig, ETH_ALEN);
+ memcpy(roam_adv_packet->client, client, ETH_ALEN);
+
+ neigh_node = orig_node_get_router(orig_node);
+ if (!neigh_node)
+ goto out;
+
+ bat_dbg(DBG_TT, bat_priv,
+ "Sending ROAMING_ADV to %pM (client %pM) via %pM\n",
+ orig_node->orig, client, neigh_node->addr);
+
+ send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
+ ret = 0;
+
+ out:
+ if (neigh_node)
+ neigh_node_free_ref(neigh_node);
+ if (ret)
+ kfree_skb(skb);
+ return;
+ }
+
+ static void tt_purge(struct work_struct *work)
+ {
+ struct delayed_work *delayed_work =
+ container_of(work, struct delayed_work, work);
+ struct bat_priv *bat_priv =
+ container_of(delayed_work, struct bat_priv, tt_work);
+
+ tt_local_purge(bat_priv);
+ tt_global_roam_purge(bat_priv);
+ tt_req_purge(bat_priv);
+ tt_roam_purge(bat_priv);
+
+ tt_start_timer(bat_priv);
+ }
+
+ void tt_free(struct bat_priv *bat_priv)
+ {
+ cancel_delayed_work_sync(&bat_priv->tt_work);
+
+ tt_local_table_free(bat_priv);
+ tt_global_table_free(bat_priv);
+ tt_req_list_free(bat_priv);
+ tt_changes_list_free(bat_priv);
+ tt_roam_list_free(bat_priv);
+
+ kfree(bat_priv->tt_buff);
+ }
diff --combined net/batman-adv/translation-table.h
index 0f2b990,1cd2d39..1cd2d39
--- a/net/batman-adv/translation-table.h
+++ b/net/batman-adv/translation-table.h
@@@ -22,23 -22,45 +22,45 @@@
#ifndef _NET_BATMAN_ADV_TRANSLATION_TABLE_H_
#define _NET_BATMAN_ADV_TRANSLATION_TABLE_H_
- int tt_local_init(struct bat_priv *bat_priv);
+ 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);
void tt_local_remove(struct bat_priv *bat_priv,
- const uint8_t *addr, const char *message);
- int tt_local_fill_buffer(struct bat_priv *bat_priv,
- unsigned char *buff, int buff_len);
+ const uint8_t *addr, const char *message, bool roaming);
int tt_local_seq_print_text(struct seq_file *seq, void *offset);
void tt_global_add_orig(struct bat_priv *bat_priv,
struct orig_node *orig_node,
const unsigned char *tt_buff, int tt_buff_len);
+ int tt_global_add(struct bat_priv *bat_priv,
+ struct orig_node *orig_node, const unsigned char *addr,
+ uint8_t ttvn, bool roaming);
int tt_global_seq_print_text(struct seq_file *seq, void *offset);
void tt_global_del_orig(struct bat_priv *bat_priv,
- struct orig_node *orig_node, const char *message);
- void tt_global_free(struct bat_priv *bat_priv);
+ struct orig_node *orig_node, const char *message);
+ void tt_global_del(struct bat_priv *bat_priv,
+ struct orig_node *orig_node, const unsigned char *addr,
+ const char *message, bool roaming);
struct orig_node *transtable_search(struct bat_priv *bat_priv,
const uint8_t *addr);
+ void tt_save_orig_buffer(struct bat_priv *bat_priv, struct orig_node *orig_node,
+ const unsigned char *tt_buff, uint8_t tt_num_changes);
+ uint16_t tt_local_crc(struct bat_priv *bat_priv);
+ uint16_t tt_global_crc(struct bat_priv *bat_priv, struct orig_node *orig_node);
+ void tt_free(struct bat_priv *bat_priv);
+ int send_tt_request(struct bat_priv *bat_priv,
+ struct orig_node *dst_orig_node, uint8_t hvn,
+ uint16_t tt_crc, bool full_table);
+ bool send_tt_response(struct bat_priv *bat_priv,
+ struct tt_query_packet *tt_request);
+ void tt_update_changes(struct bat_priv *bat_priv, struct orig_node *orig_node,
+ uint16_t tt_num_changes, uint8_t ttvn,
+ struct tt_change *tt_change);
+ 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 send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
+ struct orig_node *orig_node);
#endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */
diff --combined net/batman-adv/types.h
index 65b3222,85cf122..85cf122
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@@ -75,8 -75,18 +75,18 @@@ struct orig_node
unsigned long batman_seqno_reset;
uint8_t gw_flags;
uint8_t flags;
+ atomic_t last_ttvn; /* last seen translation table version number */
+ uint16_t tt_crc;
unsigned char *tt_buff;
int16_t tt_buff_len;
+ spinlock_t tt_buff_lock; /* protects tt_buff */
+ atomic_t tt_size;
+ /* The tt_poss_change flag is used to detect an ongoing roaming phase.
+ * If true, then I sent a Roaming_adv to this orig_node and I have to
+ * inspect every packet directed to it to check whether it is still
+ * the true destination or not. This flag will be reset to false as
+ * soon as I receive a new TTVN from this orig_node */
+ bool tt_poss_change;
uint32_t last_real_seqno;
uint8_t last_ttl;
unsigned long bcast_bits[NUM_WORDS];
@@@ -94,6 -104,7 +104,7 @@@
spinlock_t ogm_cnt_lock;
/* bcast_seqno_lock protects bcast_bits, last_bcast_seqno */
spinlock_t bcast_seqno_lock;
+ spinlock_t tt_list_lock; /* protects tt_list */
atomic_t bond_candidates;
struct list_head bond_list;
};
@@@ -145,6 -156,15 +156,15 @@@ struct bat_priv
atomic_t bcast_seqno;
atomic_t bcast_queue_left;
atomic_t batman_queue_left;
+ atomic_t ttvn; /* tranlation table version number */
+ atomic_t tt_ogm_append_cnt;
+ atomic_t tt_local_changes; /* changes registered in a OGM interval */
+ /* The tt_poss_change flag is used to detect an ongoing roaming phase.
+ * If true, then I received a Roaming_adv and I have to inspect every
+ * packet directed to me to check whether I am still the true
+ * destination or not. This flag will be reset to false as soon as I
+ * increase my TTVN */
+ bool tt_poss_change;
char num_ifaces;
struct debug_log *debug_log;
struct kobject *mesh_obj;
@@@ -153,26 -173,35 +173,35 @@@
struct hlist_head forw_bcast_list;
struct hlist_head gw_list;
struct hlist_head softif_neigh_vids;
+ struct list_head tt_changes_list; /* tracks changes in a OGM int */
struct list_head vis_send_list;
struct hashtable_t *orig_hash;
struct hashtable_t *tt_local_hash;
struct hashtable_t *tt_global_hash;
+ struct list_head tt_req_list; /* list of pending tt_requests */
+ struct list_head tt_roam_list;
struct hashtable_t *vis_hash;
spinlock_t forw_bat_list_lock; /* protects forw_bat_list */
spinlock_t forw_bcast_list_lock; /* protects */
- spinlock_t tt_lhash_lock; /* protects tt_local_hash */
- spinlock_t tt_ghash_lock; /* protects tt_global_hash */
+ spinlock_t tt_changes_list_lock; /* protects tt_changes */
+ spinlock_t tt_req_list_lock; /* protects tt_req_list */
+ spinlock_t tt_roam_list_lock; /* protects tt_roam_list */
spinlock_t gw_list_lock; /* protects gw_list and curr_gw */
spinlock_t vis_hash_lock; /* protects vis_hash */
spinlock_t vis_list_lock; /* protects vis_info::recv_list */
spinlock_t softif_neigh_lock; /* protects soft-interface neigh list */
spinlock_t softif_neigh_vid_lock; /* protects soft-interface vid list */
- int16_t num_local_tt;
- atomic_t tt_local_changed;
+ atomic_t num_local_tt;
+ /* Checksum of the local table, recomputed before sending a new OGM */
+ atomic_t tt_crc;
+ unsigned char *tt_buff;
+ int16_t tt_buff_len;
+ spinlock_t tt_buff_lock; /* protects tt_buff */
struct delayed_work tt_work;
struct delayed_work orig_work;
struct delayed_work vis_work;
struct gw_node __rcu *curr_gw; /* rcu protected pointer */
+ atomic_t gw_reselect;
struct hard_iface __rcu *primary_if; /* rcu protected pointer */
struct vis_info *my_vis_info;
};
@@@ -196,13 -225,38 +225,38 @@@ struct tt_local_entry
uint8_t addr[ETH_ALEN];
unsigned long last_seen;
char never_purge;
+ atomic_t refcount;
+ struct rcu_head rcu;
struct hlist_node hash_entry;
};
struct tt_global_entry {
uint8_t addr[ETH_ALEN];
struct orig_node *orig_node;
- struct hlist_node hash_entry;
+ uint8_t ttvn;
+ uint8_t flags; /* only TT_GLOBAL_ROAM is used */
+ unsigned long roam_at; /* time at which TT_GLOBAL_ROAM was set */
+ atomic_t refcount;
+ struct rcu_head rcu;
+ struct hlist_node hash_entry; /* entry in the global table */
+ };
+
+ struct tt_change_node {
+ struct list_head list;
+ struct tt_change change;
+ };
+
+ struct tt_req_node {
+ uint8_t addr[ETH_ALEN];
+ unsigned long issued_at;
+ struct list_head list;
+ };
+
+ struct tt_roam_node {
+ uint8_t addr[ETH_ALEN];
+ atomic_t counter;
+ unsigned long first_time;
+ struct list_head list;
};
/**
diff --combined net/batman-adv/unicast.c
index 6eabf42,32b125f..32b125f
--- a/net/batman-adv/unicast.c
+++ b/net/batman-adv/unicast.c
@@@ -325,6 -325,9 +325,9 @@@ find_router
unicast_packet->ttl = TTL;
/* copy the destination for faster routing */
memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN);
+ /* set the destination tt version number */
+ unicast_packet->ttvn =
+ (uint8_t)atomic_read(&orig_node->last_ttvn);
if (atomic_read(&bat_priv->fragmentation) &&
data_len + sizeof(*unicast_packet) >
diff --combined net/batman-adv/vis.c
index 355c6e5,8a1b985..8a1b985
--- a/net/batman-adv/vis.c
+++ b/net/batman-adv/vis.c
@@@ -665,11 -665,12 +665,12 @@@ next
hash = bat_priv->tt_local_hash;
for (i = 0; i < hash->size; i++) {
head = &hash->table[i];
- hlist_for_each_entry(tt_local_entry, node, head, hash_entry) {
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(tt_local_entry, node, head,
+ hash_entry) {
entry = (struct vis_info_entry *)
skb_put(info->skb_packet,
sizeof(*entry));
@@@ -678,14 -679,12 +679,12 @@@
entry->quality = 0; /* 0 means TT */
packet->entries++;
- if (vis_packet_full(info)) {
- spin_unlock_bh(&bat_priv->tt_lhash_lock);
- return 0;
- }
+ if (vis_packet_full(info))
+ goto unlock;
}
+ rcu_read_unlock();
}
- spin_unlock_bh(&bat_priv->tt_lhash_lock);
return 0;
unlock:
--
linux integration
11 years, 7 months
batctl; branch, next, updated. v2011.2.0-30-g3a64829
by postmaster@open-mesh.org
The following commit has been merged in the next branch:
commit 3a648297ecddd861d43a1e447c37e5d6abfa2f3c
Author: Sven Eckelmann <sven(a)narfation.org>
Date: Sun Jun 19 20:32:30 2011 +0200
batctl: Start new development cycle
Signed-off-by: Sven Eckelmann <sven(a)narfation.org>
diff --git a/main.h b/main.h
index 2f4841a..a9102b1 100644
--- a/main.h
+++ b/main.h
@@ -21,7 +21,7 @@
-#define SOURCE_VERSION "devel"
+#define SOURCE_VERSION "next"
#define SOCKET_PATH_FMT "%s/batman_adv/%s/socket"
--
batctl
11 years, 7 months
batman-adv; branch, next, updated. v2011.2.0-57-g434e765
by postmaster@open-mesh.org
The following commit has been merged in the next branch:
commit 434e765c6eee7a39ca326577e3fcc007a2a9d2db
Author: Sven Eckelmann <sven(a)narfation.org>
Date: Sun Jun 19 20:31:53 2011 +0200
batman-adv: Start new development cycle
Signed-off-by: Sven Eckelmann <sven(a)narfation.org>
diff --git a/main.h b/main.h
index f3fe9f4..175c9c9 100644
--- a/main.h
+++ b/main.h
@@ -27,7 +27,7 @@
#define DRIVER_DESC "B.A.T.M.A.N. advanced"
#define DRIVER_DEVICE "batman-adv"
-#define SOURCE_VERSION "devel"
+#define SOURCE_VERSION "next"
/* B.A.T.M.A.N. parameters */
--
batman-adv
11 years, 7 months
batctl; branch, master, updated. v2011.2.0-29-g27b695b
by postmaster@open-mesh.org
The following commit has been merged in the master branch:
commit 27b695b97cf0d6813e3e9951538186e15ad62068
Merge: 5e42d990f203fdb11e7409cb04b6be4fd9d64a09 b929422071da1bcea5c7b3185b376c664d19ad58
Author: Sven Eckelmann <sven(a)narfation.org>
Date: Sun Jun 19 20:26:57 2011 +0200
Merge commit 'v2011.2.0'
--
batctl
11 years, 7 months
batman-adv; branch, master, updated. v2011.2.0-56-g8c1fb2c
by postmaster@open-mesh.org
The following commit has been merged in the master branch:
commit 8c1fb2c2aa1ed1f5fa67a7d3459a9b6428aa337f
Merge: 74db0801dd491805b1cfcbf3b0f35aaf8c3ada38 885c663956e419e7a72419681766d339262bb50c
Author: Sven Eckelmann <sven(a)narfation.org>
Date: Sun Jun 19 20:25:59 2011 +0200
Merge commit 'v2011.2.0'
Conflicts:
main.h
--
batman-adv
11 years, 7 months