aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--net/batman-adv/Kconfig1
-rw-r--r--net/batman-adv/aggregation.c23
-rw-r--r--net/batman-adv/aggregation.h6
-rw-r--r--net/batman-adv/bat_sysfs.c2
-rw-r--r--net/batman-adv/hard-interface.c13
-rw-r--r--net/batman-adv/main.c13
-rw-r--r--net/batman-adv/main.h7
-rw-r--r--net/batman-adv/originator.c8
-rw-r--r--net/batman-adv/packet.h59
-rw-r--r--net/batman-adv/routing.c252
-rw-r--r--net/batman-adv/routing.h6
-rw-r--r--net/batman-adv/send.c87
-rw-r--r--net/batman-adv/send.h2
-rw-r--r--net/batman-adv/soft-interface.c11
-rw-r--r--net/batman-adv/translation-table.c1126
-rw-r--r--net/batman-adv/translation-table.h34
-rw-r--r--net/batman-adv/types.h33
-rw-r--r--net/batman-adv/unicast.c3
18 files changed, 1381 insertions, 305 deletions
diff --git a/net/batman-adv/Kconfig b/net/batman-adv/Kconfig
index 6c051ad833e..2b68d068eaf 100644
--- a/net/batman-adv/Kconfig
+++ b/net/batman-adv/Kconfig
@@ -5,6 +5,7 @@
config BATMAN_ADV
tristate "B.A.T.M.A.N. Advanced Meshing Protocol"
depends on NET
+ select CRC16
default n
---help---
diff --git a/net/batman-adv/aggregation.c b/net/batman-adv/aggregation.c
index 29c67405347..c583e049f42 100644
--- a/net/batman-adv/aggregation.c
+++ b/net/batman-adv/aggregation.c
@@ -20,17 +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,
@@ -264,18 +259,20 @@ void receive_aggr_bat_packet(const struct ethhdr *ethhdr,
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 --git a/net/batman-adv/aggregation.h b/net/batman-adv/aggregation.h
index 0547fd8ea3b..216337bb841 100644
--- a/net/batman-adv/aggregation.h
+++ b/net/batman-adv/aggregation.h
@@ -25,9 +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);
diff --git a/net/batman-adv/bat_sysfs.c b/net/batman-adv/bat_sysfs.c
index 924d5773da2..63738ec1051 100644
--- a/net/batman-adv/bat_sysfs.c
+++ b/net/batman-adv/bat_sysfs.c
@@ -375,7 +375,7 @@ BAT_ATTR_UINT(gw_sel_class, S_IRUGO | S_IWUSR, 1, TQ_MAX_VALUE,
static BAT_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, show_gw_bwidth,
store_gw_bwidth);
#ifdef CONFIG_BATMAN_ADV_DEBUG
-BAT_ATTR_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[] = {
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c
index b55e8616fc1..d40426cc5e2 100644
--- a/net/batman-adv/hard-interface.c
+++ b/net/batman-adv/hard-interface.c
@@ -152,12 +152,6 @@ static void primary_if_select(struct bat_priv *bat_priv,
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)
@@ -340,7 +334,8 @@ int hardif_enable_interface(struct hard_iface *hard_iface,
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++;
@@ -659,6 +654,10 @@ static int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
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;
default:
ret = NET_RX_DROP;
}
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c
index 2d6445e171d..49a5e64b2d4 100644
--- a/net/batman-adv/main.c
+++ b/net/batman-adv/main.c
@@ -86,6 +86,9 @@ int mesh_init(struct net_device *soft_iface)
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_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 +99,13 @@ int mesh_init(struct net_device *soft_iface)
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);
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);
@@ -137,8 +139,7 @@ void mesh_free(struct net_device *soft_iface)
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 --git a/net/batman-adv/main.h b/net/batman-adv/main.h
index 714a2414d91..6f53a1de778 100644
--- a/net/batman-adv/main.h
+++ b/net/batman-adv/main.h
@@ -46,11 +46,15 @@
/* 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 NO_FLAGS 0
#define NUM_WORDS (TQ_LOCAL_WINDOW_SIZE / WORD_BIT_SIZE)
@@ -96,7 +100,8 @@ enum mesh_state {
enum dbg_level {
DBG_BATMAN = 1 << 0,
DBG_ROUTES = 1 << 1, /* route added / changed / deleted */
- DBG_ALL = 3
+ DBG_TT = 1 << 2, /* translation table operations */
+ DBG_ALL = 7
};
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c
index 991a6e72a9d..25e7e50eef2 100644
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@ -145,6 +145,7 @@ static void orig_node_free_rcu(struct rcu_head *rcu)
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);
@@ -213,6 +214,7 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, const uint8_t *addr)
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);
@@ -221,6 +223,8 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, const uint8_t *addr)
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
@@ -330,9 +334,7 @@ static bool purge_orig_node(struct bat_priv *bat_priv,
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 --git a/net/batman-adv/packet.h b/net/batman-adv/packet.h
index 6ddbfd83078..407dd2e84af 100644
--- a/net/batman-adv/packet.h
+++ b/net/batman-adv/packet.h
@@ -30,7 +30,8 @@ enum bat_packettype {
BAT_UNICAST = 0x03,
BAT_BCAST = 0x04,
BAT_VIS = 0x05,
- BAT_UNICAST_FRAG = 0x06
+ BAT_UNICAST_FRAG = 0x06,
+ BAT_TT_QUERY = 0x07
};
/* this file is included by batctl which needs these defines */
@@ -63,6 +64,25 @@ enum unicast_frag_flags {
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 */
@@ -73,8 +93,9 @@ struct batman_packet {
uint8_t prev_sender[6];
uint8_t gw_flags; /* flags related to gateway class */
uint8_t tq;
- uint8_t num_tt;
- uint8_t reserved;
+ 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)
@@ -112,7 +133,7 @@ struct unicast_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
uint8_t ttl;
- uint8_t reserved;
+ uint8_t ttvn; /* destination translation table version number */
uint8_t dest[6];
} __packed;
@@ -120,7 +141,7 @@ struct unicast_frag_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
uint8_t ttl;
- uint8_t reserved;
+ uint8_t ttvn; /* destination translation table version number */
uint8_t dest[6];
uint8_t flags;
uint8_t align;
@@ -150,4 +171,32 @@ struct vis_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 tt_change {
+ uint8_t flags;
+ uint8_t addr[ETH_ALEN];
+} __packed;
+
#endif /* _NET_BATMAN_ADV_PACKET_H_ */
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index eb6fb7d2d36..8b0f8330b06 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@ -64,27 +64,56 @@ void slide_own_bcast_window(struct hard_iface *hard_iface)
}
}
-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 */
+ spin_lock_bh(&bat_priv->tt_ghash_lock);
+ orig_node->tt_crc = tt_global_crc(bat_priv, orig_node);
+ spin_unlock_bh(&bat_priv->tt_ghash_lock);
+ } 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 +121,10 @@ static void update_route(struct bat_priv *bat_priv, struct orig_node *orig_node,
/* 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 +132,6 @@ static void update_route(struct bat_priv *bat_priv, struct orig_node *orig_node,
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 +158,7 @@ static void update_route(struct bat_priv *bat_priv, struct orig_node *orig_node,
}
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 +168,7 @@ void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node,
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)
@@ -360,14 +380,12 @@ static void update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
const struct ethhdr *ethhdr,
const struct batman_packet *batman_packet,
struct hard_iface *if_incoming,
- const unsigned char *tt_buff, int tt_buff_len,
- int 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 +450,6 @@ static void update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
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 +479,19 @@ static void update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
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);
@@ -594,7 +613,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);
@@ -633,12 +652,14 @@ void receive_bat_packet(const struct ethhdr *ethhdr,
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();
@@ -790,14 +811,14 @@ void receive_bat_packet(const struct ethhdr *ethhdr,
((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");
@@ -820,7 +841,7 @@ void receive_bat_packet(const struct ethhdr *ethhdr,
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))
@@ -1167,6 +1188,70 @@ static struct neigh_node *find_ifalter_router(struct orig_node *primary_orig,
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;
+}
+
/* find a suitable router for this originator, and use
* bonding if possible. increases the found neighbors
* refcount.*/
@@ -1353,14 +1438,82 @@ 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;
+
+ /* 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))
+ 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);
+ orig_node_free_ref(orig_node);
+ }
+
+ /* Check whether I have to reroute the packet */
+ if (seq_before(unicast_packet->ttvn, curr_ttvn)) {
+ /* 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 */
@@ -1383,6 +1536,9 @@ int recv_ucast_frag_packet(struct sk_buff *skb, struct hard_iface *recv_if)
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 --git a/net/batman-adv/routing.h b/net/batman-adv/routing.h
index 0ce03923ec0..e77d46440d2 100644
--- a/net/batman-adv/routing.h
+++ b/net/batman-adv/routing.h
@@ -25,11 +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,7 @@ int recv_ucast_frag_packet(struct sk_buff *skb, struct hard_iface *recv_if);
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);
struct neigh_node *find_router(struct bat_priv *bat_priv,
struct orig_node *orig_node,
const struct hard_iface *recv_if);
diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c
index be0d581a62a..6b1407570e4 100644
--- a/net/batman-adv/send.c
+++ b/net/batman-adv/send.c
@@ -120,7 +120,7 @@ static void send_packet_to_if(struct forw_packet *forw_packet,
/* 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 @@ static void send_packet_to_if(struct forw_packet *forw_packet,
"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);
@@ -213,25 +213,18 @@ static void send_packet(struct forw_packet *forw_packet)
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)
{
- 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 @@ static void rebuild_batman_packet(struct bat_priv *bat_priv,
}
}
+/* 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,22 @@ void schedule_own_packet(struct hard_iface *hard_iface)
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);
+ }
+
+ /* 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 +320,9 @@ void schedule_own_packet(struct hard_iface *hard_iface)
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