The following commit has been merged in the next branch: commit 81f834b4f278b8f1a79ea412f142ef45d63ab7ca Merge: 2d05b4a9732e16e425b34743cd254117ce554606 d1b1d7c61046afc9288d1e6c89f27839a588bd7b Author: Marek Lindner lindner_marek@yahoo.de Date: Mon Oct 17 14:01:20 2011 +0200
Merge branch 'maint' into next
diff --combined translation-table.c index cc53f78,f599db9..04ad2a4 --- a/translation-table.c +++ b/translation-table.c @@@ -183,8 -183,7 +183,8 @@@ static int tt_local_init(struct bat_pri return 1; }
-void tt_local_add(struct net_device *soft_iface, const uint8_t *addr) +void tt_local_add(struct net_device *soft_iface, const uint8_t *addr, + int ifindex) { struct bat_priv *bat_priv = netdev_priv(soft_iface); struct tt_local_entry *tt_local_entry = NULL; @@@ -208,8 -207,6 +208,8 @@@ memcpy(tt_local_entry->addr, addr, ETH_ALEN); tt_local_entry->last_seen = jiffies; tt_local_entry->flags = NO_FLAGS; + if (is_wifi_iface(ifindex)) + tt_local_entry->flags |= TT_CLIENT_WIFI; atomic_set(&tt_local_entry->refcount, 2);
/* the batman interface mac address should never be purged */ @@@ -332,7 -329,7 +332,7 @@@ int tt_local_seq_print_text(struct seq_
rcu_read_lock(); __hlist_for_each_rcu(node, head) - buf_size += 21; + buf_size += 29; rcu_read_unlock(); }
@@@ -351,19 -348,8 +351,19 @@@ rcu_read_lock(); hlist_for_each_entry_rcu(tt_local_entry, node, head, hash_entry) { - pos += snprintf(buff + pos, 22, " * %pM\n", - tt_local_entry->addr); + pos += snprintf(buff + pos, 30, " * %pM " + "[%c%c%c%c%c]\n", + tt_local_entry->addr, + (tt_local_entry->flags & + TT_CLIENT_ROAM ? 'R' : '.'), + (tt_local_entry->flags & + TT_CLIENT_NOPURGE ? 'P' : '.'), + (tt_local_entry->flags & + TT_CLIENT_NEW ? 'N' : '.'), + (tt_local_entry->flags & + TT_CLIENT_PENDING ? 'X' : '.'), + (tt_local_entry->flags & + TT_CLIENT_WIFI ? 'W' : '.')); } rcu_read_unlock(); } @@@ -383,8 -369,8 +383,8 @@@ static void tt_local_set_pending(struc tt_local_event(bat_priv, tt_local_entry->addr, tt_local_entry->flags | flags);
- /* The local client has to be merked as "pending to be removed" but has - * to be kept in the table in order to send it in an full tables + /* The local client has to be marked as "pending to be removed" but has + * to be kept in the table in order to send it in a full table * response issued before the net ttvn increment (consistency check) */ tt_local_entry->flags |= TT_CLIENT_PENDING; } @@@ -509,8 -495,7 +509,8 @@@ static void tt_changes_list_free(struc
/* 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) + const unsigned char *tt_addr, uint8_t ttvn, bool roaming, + bool wifi) { struct tt_global_entry *tt_global_entry; struct orig_node *orig_node_tmp; @@@ -552,9 -537,6 +552,9 @@@ tt_global_entry->roam_at = 0; }
+ if (wifi) + tt_global_entry->flags |= TT_CLIENT_WIFI; + bat_dbg(DBG_TT, bat_priv, "Creating new global tt entry: %pM (via %pM)\n", tt_global_entry->addr, orig_node->orig); @@@ -600,8 -582,8 +600,8 @@@ int tt_global_seq_print_text(struct seq seq_printf(seq, "Globally announced TT entries received via the mesh %s\n", net_dev->name); - seq_printf(seq, " %-13s %s %-15s %s\n", - "Client", "(TTVN)", "Originator", "(Curr TTVN)"); + seq_printf(seq, " %-13s %s %-15s %s %s\n", + "Client", "(TTVN)", "Originator", "(Curr TTVN)", "Flags");
buf_size = 1; /* Estimate length for: " * xx:xx:xx:xx:xx:xx (ttvn) via @@@ -611,7 -593,7 +611,7 @@@
rcu_read_lock(); __hlist_for_each_rcu(node, head) - buf_size += 59; + buf_size += 67; rcu_read_unlock(); }
@@@ -630,20 -612,14 +630,20 @@@ rcu_read_lock(); hlist_for_each_entry_rcu(tt_global_entry, node, head, hash_entry) { - pos += snprintf(buff + pos, 61, - " * %pM (%3u) via %pM (%3u)\n", - tt_global_entry->addr, + pos += snprintf(buff + pos, 69, + " * %pM (%3u) via %pM (%3u) " + "[%c%c%c]\n", tt_global_entry->addr, tt_global_entry->ttvn, tt_global_entry->orig_node->orig, (uint8_t) atomic_read( &tt_global_entry->orig_node-> - last_ttvn)); + last_ttvn), + (tt_global_entry->flags & + TT_CLIENT_ROAM ? 'R' : '.'), + (tt_global_entry->flags & + TT_CLIENT_PENDING ? 'X' : '.'), + (tt_global_entry->flags & + TT_CLIENT_WIFI ? 'W' : '.')); } rcu_read_unlock(); } @@@ -798,56 -774,30 +798,56 @@@ static void tt_global_table_free(struc bat_priv->tt_global_hash = NULL; }
+static bool _is_ap_isolated(struct tt_local_entry *tt_local_entry, + struct tt_global_entry *tt_global_entry) +{ + bool ret = false; + + if (tt_local_entry->flags & TT_CLIENT_WIFI && + tt_global_entry->flags & TT_CLIENT_WIFI) + ret = true; + + return ret; +} + struct orig_node *transtable_search(struct bat_priv *bat_priv, - const uint8_t *addr) + const uint8_t *src, const uint8_t *addr) { - struct tt_global_entry *tt_global_entry; + struct tt_local_entry *tt_local_entry = NULL; + struct tt_global_entry *tt_global_entry = NULL; struct orig_node *orig_node = NULL;
- tt_global_entry = tt_global_hash_find(bat_priv, addr); + if (src && atomic_read(&bat_priv->ap_isolation)) { + tt_local_entry = tt_local_hash_find(bat_priv, src); + if (!tt_local_entry) + goto out; + }
+ tt_global_entry = tt_global_hash_find(bat_priv, addr); if (!tt_global_entry) goto out;
+ /* check whether the clients should not communicate due to AP + * isolation */ + if (tt_local_entry && _is_ap_isolated(tt_local_entry, tt_global_entry)) + goto out; + if (!atomic_inc_not_zero(&tt_global_entry->orig_node->refcount)) - goto free_tt; + goto out;
/* A global client marked as PENDING has already moved from that * originator */ if (tt_global_entry->flags & TT_CLIENT_PENDING) - goto free_tt; + goto out;
orig_node = tt_global_entry->orig_node;
-free_tt: - tt_global_entry_free_ref(tt_global_entry); out: + if (tt_global_entry) + tt_global_entry_free_ref(tt_global_entry); + if (tt_local_entry) + tt_local_entry_free_ref(tt_local_entry); + return orig_node; }
@@@ -1079,9 -1029,8 +1079,9 @@@ 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) +static 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; @@@ -1188,12 -1137,12 +1188,12 @@@ static bool send_other_tt_response(stru orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn); req_ttvn = tt_request->ttvn;
- /* I have not the requested data */ + /* I don't have 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 the full table has been explicitly requested */ if (tt_request->flags & TT_FULL_TABLE || !req_dst_orig_node->tt_buff) full_table = true; @@@ -1414,9 -1363,7 +1414,9 @@@ static void _tt_update_changes(struct b (tt_change + i)->flags & TT_CLIENT_ROAM); else if (!tt_global_add(bat_priv, orig_node, - (tt_change + i)->addr, ttvn, false)) + (tt_change + i)->addr, ttvn, false, + (tt_change + i)->flags & + TT_CLIENT_WIFI)) /* In case of problem while storing a * global_entry, we stop the updating * procedure without committing the @@@ -1456,10 -1403,9 +1456,10 @@@ out 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) +static 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); @@@ -1722,6 -1668,8 +1722,8 @@@ static void tt_local_reset_flags(struc rcu_read_lock(); hlist_for_each_entry_rcu(tt_local_entry, node, head, hash_entry) { + if (!(tt_local_entry->flags & flags)) + continue; tt_local_entry->flags &= ~flags; atomic_inc(&bat_priv->num_local_tt); } @@@ -1774,90 -1722,3 +1776,90 @@@ void tt_commit_changes(struct bat_priv atomic_inc(&bat_priv->ttvn); bat_priv->tt_poss_change = false; } + +bool is_ap_isolated(struct bat_priv *bat_priv, uint8_t *src, uint8_t *dst) +{ + struct tt_local_entry *tt_local_entry = NULL; + struct tt_global_entry *tt_global_entry = NULL; + bool ret = true; + + if (!atomic_read(&bat_priv->ap_isolation)) + return false; + + tt_local_entry = tt_local_hash_find(bat_priv, dst); + if (!tt_local_entry) + goto out; + + tt_global_entry = tt_global_hash_find(bat_priv, src); + if (!tt_global_entry) + goto out; + + if (_is_ap_isolated(tt_local_entry, tt_global_entry)) + goto out; + + ret = false; + +out: + if (tt_global_entry) + tt_global_entry_free_ref(tt_global_entry); + if (tt_local_entry) + tt_local_entry_free_ref(tt_local_entry); + return ret; +} + +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) +{ + 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 due to their size 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 precomputed crc with 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); + + /* The ttvn alone is not enough to guarantee consistency + * because a single value could represent different states + * (due to the wrap around). Thus a node has to check whether + * the resulting table (after applying the changes) is still + * consistent or not. E.g. a node could disconnect while its + * ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case + * checking the CRC value is mandatory to detect the + * inconsistency */ + if (orig_node->tt_crc != tt_crc) + goto request_table; + + /* 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; + } + } +}