@@ -44,6 +44,8 @@
#define PURGE_TIMEOUT 200000 /* 200 seconds */
#define TT_LOCAL_TIMEOUT 3600000 /* in miliseconds */
#define TT_CLIENT_ROAM_TIMEOUT 600000 /* in miliseconds */
+#define TT_CLIENT_TEMP_TIMEOUT_FACT 10 /* multiply factor for the current orig
+ * interval */
/* sliding packet range of received originator messages in sequence numbers
* (should be a multiple of our word size) */
#define TQ_LOCAL_WINDOW_SIZE 64
@@ -91,12 +91,13 @@ enum tt_query_flags {
* Flags from 1 to 1 << 7 are sent on the wire, while flags from 1 << 8 to
* 1 << 15 are used for local computation only */
enum tt_client_flags {
- TT_CLIENT_DEL = 1 << 0,
- TT_CLIENT_ROAM = 1 << 1,
- TT_CLIENT_WIFI = 1 << 2,
- TT_CLIENT_NOPURGE = 1 << 8,
- TT_CLIENT_NEW = 1 << 9,
- TT_CLIENT_PENDING = 1 << 10
+ TT_CLIENT_DEL = 1 << 0,
+ TT_CLIENT_ROAM = 1 << 1,
+ TT_CLIENT_WIFI = 1 << 2,
+ TT_CLIENT_TEMP = 1 << 3,
+ TT_CLIENT_NOPURGE = 1 << 8,
+ TT_CLIENT_NEW = 1 << 9,
+ TT_CLIENT_PENDING = 1 << 10,
};
/* claim frame types for the bridge loop avoidance */
@@ -224,7 +225,7 @@ struct tt_query_packet {
struct roam_adv_packet {
struct batman_header header;
- uint8_t reserved;
+ uint8_t flags;
uint8_t dst[ETH_ALEN];
uint8_t src[ETH_ALEN];
uint8_t client[ETH_ALEN];
@@ -679,11 +679,13 @@ int recv_roam_adv(struct sk_buff *skb, struct hard_iface *recv_if)
goto out;
bat_dbg(DBG_TT, bat_priv,
- "Received ROAMING_ADV from %pM (client %pM)\n",
- roam_adv_packet->src, roam_adv_packet->client);
+ "Received ROAMING_ADV from %pM (client: %pM flags: 0x%.2x)\n",
+ roam_adv_packet->src, roam_adv_packet->client,
+ roam_adv_packet->flags);
tt_global_add(bat_priv, orig_node, roam_adv_packet->client,
- TT_CLIENT_ROAM, atomic_read(&orig_node->last_ttvn) + 1);
+ roam_adv_packet->flags | TT_CLIENT_ROAM,
+ atomic_read(&orig_node->last_ttvn) + 1);
/* Roaming phase starts: I have new information but the ttvn has not
* been incremented yet. This flag will make me check all the incoming
@@ -959,6 +961,7 @@ 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);
+ struct orig_node *orig_node = NULL;
unicast_packet = (struct unicast_packet *)skb->data;
@@ -974,7 +977,18 @@ int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
/* packet for me */
if (is_my_mac(unicast_packet->dest)) {
- interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size);
+ /* now we can look at the source field and retrieve the orig
+ * node */
+ if (unicast_packet->header.packet_type == BAT_UNICAST_4ADDR)
+ orig_node = orig_hash_find(bat_priv,
+ ((struct unicast_4addr_packet *)skb->data)->src);
+
+ interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size,
+ orig_node);
+
+ if (orig_node)
+ orig_node_free_ref(orig_node);
+
return NET_RX_SUCCESS;
}
@@ -1010,7 +1024,7 @@ int recv_ucast_frag_packet(struct sk_buff *skb, struct hard_iface *recv_if)
return NET_RX_SUCCESS;
interface_rx(recv_if->soft_iface, new_skb, recv_if,
- sizeof(struct unicast_packet));
+ sizeof(struct unicast_packet), NULL);
return NET_RX_SUCCESS;
}
@@ -1094,7 +1108,7 @@ int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
goto out;
/* broadcast for me */
- interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size);
+ interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size, orig_node);
ret = NET_RX_SUCCESS;
goto out;
@@ -256,7 +256,7 @@ end:
void interface_rx(struct net_device *soft_iface,
struct sk_buff *skb, struct hard_iface *recv_if,
- int hdr_size)
+ int hdr_size, struct orig_node *orig_node)
{
struct bat_priv *bat_priv = netdev_priv(soft_iface);
struct ethhdr *ethhdr;
@@ -307,6 +307,10 @@ void interface_rx(struct net_device *soft_iface,
soft_iface->last_rx = jiffies;
+ if (orig_node)
+ tt_add_temporary_global_entry(bat_priv, orig_node,
+ ethhdr->h_source);
+
if (is_ap_isolated(bat_priv, ethhdr->h_source, ethhdr->h_dest))
goto dropped;
@@ -25,7 +25,7 @@
int my_skb_head_push(struct sk_buff *skb, unsigned int len);
void interface_rx(struct net_device *soft_iface,
struct sk_buff *skb, struct hard_iface *recv_if,
- int hdr_size);
+ int hdr_size, struct orig_node *orig_node);
struct net_device *softif_create(const char *name);
void softif_destroy(struct net_device *soft_iface);
int softif_is_valid(const struct net_device *net_dev);
@@ -31,10 +31,21 @@
#include <linux/crc16.h>
-static void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
+/* the temporary client timeout is defined as a multiple of the originator
+ * interval */
+#define TT_CLIENT_TEMP_TIMEOUT (TT_CLIENT_TEMP_TIMEOUT_FACT * \
+ atomic_read(&bat_priv->orig_interval))
+
+
+static void send_roam_adv(struct bat_priv *bat_priv,
+ struct tt_global_entry *tt_global_entry,
struct orig_node *orig_node);
static void tt_purge(struct work_struct *work);
static void tt_global_del_orig_list(struct tt_global_entry *tt_global_entry);
+static void tt_global_del(struct bat_priv *bat_priv,
+ struct orig_node *orig_node,
+ const unsigned char *addr,
+ const char *message, bool roaming);
/* returns 1 if they are the same mac addr */
static int compare_tt(const struct hlist_node *node, const void *data2)
@@ -250,6 +261,7 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
tt_local_entry->common.flags |= TT_CLIENT_WIFI;
atomic_set(&tt_local_entry->common.refcount, 2);
tt_local_entry->last_seen = jiffies;
+ tt_local_entry->common.added_at = tt_local_entry->last_seen;
/* the batman interface mac address should never be purged */
if (compare_eth(addr, soft_iface->dev_addr))
@@ -283,15 +295,25 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
hlist_for_each_entry_rcu(orig_entry, node, head, list) {
orig_entry->orig_node->tt_poss_change = true;
- send_roam_adv(bat_priv, tt_global_entry->common.addr,
+ send_roam_adv(bat_priv, tt_global_entry,
orig_entry->orig_node);
}
rcu_read_unlock();
- /* The global entry has to be marked as ROAMING and
- * has to be kept for consistency purpose */
- tt_global_entry->common.flags |= TT_CLIENT_ROAM;
- tt_global_entry->roam_at = jiffies;
+ /* if the global client is marked as TEMP or ROAM we can
+ * directly delete it because it has never been announced yet
+ * and we don't need to keep it for consistency purposes */
+ if ((tt_global_entry->common.flags & TT_CLIENT_TEMP) ||
+ (tt_global_entry->common.flags & TT_CLIENT_ROAM))
+ tt_global_del(bat_priv, NULL, addr,
+ "Not yet announced global client roamed to us",
+ true);
+ else {
+ /* The global entry has to be marked as ROAMING and
+ * has to be kept for consistency purpose */
+ tt_global_entry->common.flags |= TT_CLIENT_ROAM;
+ tt_global_entry->roam_at = jiffies;
+ }
}
out:
if (tt_local_entry)
@@ -607,6 +629,8 @@ int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
tt_global_entry->common.flags = flags;
tt_global_entry->roam_at = 0;
atomic_set(&tt_global_entry->common.refcount, 2);
+ tt_global_entry->common.added_at = jiffies;
+
INIT_HLIST_HEAD(&tt_global_entry->orig_list);
spin_lock_init(&tt_global_entry->list_lock);
@@ -624,6 +648,14 @@ int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
tt_global_add_orig_entry(tt_global_entry, orig_node, ttvn);
} else {
/* there is already a global entry, use this one. */
+ /* if we are trying to add a temporary node, but we found an
+ * already existent entry, we can exit directly */
+ if (flags & TT_CLIENT_TEMP)
+ goto out;
+
+ /* if the client was temporary added before receiving the first
+ * OGM announcing it, we have to clear the TEMP flag */
+ tt_global_entry->common.flags &= ~TT_CLIENT_TEMP;
/* If there is the TT_CLIENT_ROAM flag set, there is only one
* originator left in the list and we previously received a
@@ -686,11 +718,12 @@ static void tt_global_print_entry(struct tt_global_entry *tt_global_entry,
hlist_for_each_entry_rcu(orig_entry, node, head, list) {
flags = tt_common_entry->flags;
last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn);
- seq_printf(seq, " * %pM (%3u) via %pM (%3u) [%c%c]\n",
+ seq_printf(seq, " * %pM (%3u) via %pM (%3u) [%c%c%c]\n",
tt_global_entry->common.addr, orig_entry->ttvn,
orig_entry->orig_node->orig, last_ttvn,
(flags & TT_CLIENT_ROAM ? 'R' : '.'),
- (flags & TT_CLIENT_WIFI ? 'W' : '.'));
+ (flags & TT_CLIENT_WIFI ? 'W' : '.'),
+ (flags & TT_CLIENT_TEMP ? 'T' : '.'));
}
}
@@ -941,7 +974,7 @@ void tt_global_del_orig(struct bat_priv *bat_priv,
orig_node->tt_initialised = false;
}
-static void tt_global_roam_purge(struct bat_priv *bat_priv)
+static void tt_global_purge(struct bat_priv *bat_priv)
{
struct hashtable_t *hash = bat_priv->tt_global_hash;
struct tt_common_entry *tt_common_entry;
@@ -950,6 +983,8 @@ static void tt_global_roam_purge(struct bat_priv *bat_priv)
struct hlist_head *head;
spinlock_t *list_lock; /* protects write access to the hash lists */
uint32_t i;
+ bool purge;
+ char *msg = NULL;
for (i = 0; i < hash->size; i++) {
head = &hash->table[i];
@@ -958,18 +993,29 @@ static void tt_global_roam_purge(struct bat_priv *bat_priv)
spin_lock_bh(list_lock);
hlist_for_each_entry_safe(tt_common_entry, node, node_tmp,
head, hash_entry) {
+ purge = false;
tt_global_entry = container_of(tt_common_entry,
struct tt_global_entry,
common);
- if (!(tt_global_entry->common.flags & TT_CLIENT_ROAM))
- continue;
- if (!has_timed_out(tt_global_entry->roam_at,
- TT_CLIENT_ROAM_TIMEOUT))
+ if ((tt_global_entry->common.flags & TT_CLIENT_ROAM) &&
+ has_timed_out(tt_global_entry->roam_at,
+ TT_CLIENT_ROAM_TIMEOUT)) {
+ purge = true;
+ msg = "Roaming timeout\n";
+ }
+
+ if ((tt_global_entry->common.flags & TT_CLIENT_TEMP) &&
+ has_timed_out(tt_global_entry->common.added_at,
+ TT_CLIENT_TEMP_TIMEOUT)) {
+ purge = true;
+ msg = "Temporary client timeout\n";
+ }
+
+ if (!purge)
continue;
- bat_dbg(DBG_TT, bat_priv,
- "Deleting global tt entry (%pM): Roaming timeout\n",
- tt_global_entry->common.addr);
+ bat_dbg(DBG_TT, bat_priv, "Deleting global tt entry (%pM): %s\n",
+ tt_global_entry->common.addr, msg);
hlist_del_rcu(node);
tt_global_entry_free_ref(tt_global_entry);
@@ -1878,7 +1924,8 @@ unlock:
return ret;
}
-static void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
+static void send_roam_adv(struct bat_priv *bat_priv,
+ struct tt_global_entry *tt_global_entry,
struct orig_node *orig_node)
{
struct neigh_node *neigh_node = NULL;
@@ -1889,7 +1936,7 @@ static void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
/* 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))
+ if (!tt_check_roam_count(bat_priv, tt_global_entry->common.addr))
goto out;
skb = dev_alloc_skb(sizeof(struct roam_adv_packet) + ETH_HLEN);
@@ -1910,7 +1957,10 @@ static void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
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);
+ memcpy(roam_adv_packet->client, tt_global_entry->common.addr, ETH_ALEN);
+ roam_adv_packet->flags = NO_FLAGS;
+ if (tt_global_entry->common.flags & TT_CLIENT_TEMP)
+ roam_adv_packet->flags |= TT_CLIENT_TEMP;
neigh_node = orig_node_get_router(orig_node);
if (!neigh_node)
@@ -1918,7 +1968,8 @@ static void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
bat_dbg(DBG_TT, bat_priv,
"Sending ROAMING_ADV to %pM (client %pM) via %pM\n",
- orig_node->orig, client, neigh_node->addr);
+ orig_node->orig, tt_global_entry->common.addr,
+ neigh_node->addr);
send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
ret = 0;
@@ -1939,7 +1990,7 @@ static void tt_purge(struct work_struct *work)
container_of(delayed_work, struct bat_priv, tt_work);
tt_local_purge(bat_priv);
- tt_global_roam_purge(bat_priv);
+ tt_global_purge(bat_priv);
tt_req_purge(bat_priv);
tt_roam_purge(bat_priv);
@@ -2162,3 +2213,21 @@ bool tt_global_client_is_roaming(struct bat_priv *bat_priv, uint8_t *addr)
out:
return ret;
}
+
+bool tt_add_temporary_global_entry(struct bat_priv *bat_priv,
+ struct orig_node *orig_node,
+ const unsigned char *addr)
+{
+ bool ret = false;
+
+ if (!tt_global_add(bat_priv, orig_node, addr, TT_CLIENT_TEMP,
+ atomic_read(&orig_node->last_ttvn)))
+ goto out;
+
+ bat_dbg(DBG_TT, bat_priv,
+ "Added temporary global client (addr: %pM orig: %pM)\n",
+ addr, orig_node->orig);
+ ret = true;
+out:
+ return ret;
+}
@@ -53,6 +53,8 @@ void tt_update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
const unsigned char *tt_buff, uint8_t tt_num_changes,
uint8_t ttvn, uint16_t tt_crc);
bool tt_global_client_is_roaming(struct bat_priv *bat_priv, uint8_t *addr);
-
+bool tt_add_temporary_global_entry(struct bat_priv *bat_priv,
+ struct orig_node *orig_node,
+ const unsigned char *addr);
#endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */
@@ -261,6 +261,7 @@ struct tt_common_entry {
uint8_t addr[ETH_ALEN];
struct hlist_node hash_entry;
uint16_t flags;
+ unsigned long added_at;
atomic_t refcount;
struct rcu_head rcu;
};