Commit 0e43182c authored by David S. Miller's avatar David S. Miller

Merge branch 'batman-adv/next' of git://git.open-mesh.org/linux-merge

parents 131ea667 a943cac1
......@@ -22,6 +22,14 @@ Description:
mesh will be fragmented or silently discarded if the
packet size exceeds the outgoing interface MTU.
What: /sys/class/net/<mesh_iface>/mesh/ap_isolation
Date: May 2011
Contact: Antonio Quartulli <ordex@autistici.org>
Description:
Indicates whether the data traffic going from a
wireless client to another wireless client will be
silently dropped.
What: /sys/class/net/<mesh_iface>/mesh/gw_bandwidth
Date: October 2010
Contact: Marek Lindner <lindner_marek@yahoo.de>
......
......@@ -28,8 +28,7 @@
static inline int aggregated_packet(int buff_pos, int packet_len,
int tt_num_changes)
{
int next_buff_pos = buff_pos + BAT_PACKET_LEN + (tt_num_changes *
sizeof(struct tt_change));
int next_buff_pos = buff_pos + BAT_PACKET_LEN + tt_len(tt_num_changes);
return (next_buff_pos <= packet_len) &&
(next_buff_pos <= MAX_AGGREGATION_BYTES);
......
......@@ -380,6 +380,7 @@ static ssize_t store_gw_bwidth(struct kobject *kobj, struct attribute *attr,
BAT_ATTR_BOOL(aggregated_ogms, S_IRUGO | S_IWUSR, NULL);
BAT_ATTR_BOOL(bonding, S_IRUGO | S_IWUSR, NULL);
BAT_ATTR_BOOL(fragmentation, S_IRUGO | S_IWUSR, update_min_mtu);
BAT_ATTR_BOOL(ap_isolation, S_IRUGO | S_IWUSR, NULL);
static BAT_ATTR(vis_mode, S_IRUGO | S_IWUSR, show_vis_mode, store_vis_mode);
static BAT_ATTR(gw_mode, S_IRUGO | S_IWUSR, show_gw_mode, store_gw_mode);
BAT_ATTR_UINT(orig_interval, S_IRUGO | S_IWUSR, 2 * JITTER, INT_MAX, NULL);
......@@ -396,6 +397,7 @@ static struct bat_attribute *mesh_attrs[] = {
&bat_attr_aggregated_ogms,
&bat_attr_bonding,
&bat_attr_fragmentation,
&bat_attr_ap_isolation,
&bat_attr_vis_mode,
&bat_attr_gw_mode,
&bat_attr_orig_interval,
......
......@@ -97,12 +97,12 @@ static void bit_shift(unsigned long *seq_bits, int32_t n)
(seq_bits[i - word_num - 1] >>
(WORD_BIT_SIZE-word_offset));
/* and the upper part of the right half and shift it left to
* it's position */
* its position */
/* for our example that would be: word[0] = 9800 + 0076 =
* 9876 */
}
/* now for our last word, i==word_num, we only have the it's "left"
* half. that's the 1000 word in our example.*/
/* now for our last word, i==word_num, we only have its "left" half.
* that's the 1000 word in our example.*/
seq_bits[i] = (seq_bits[i - word_num] << word_offset);
......
......@@ -532,14 +532,14 @@ static bool is_type_dhcprequest(struct sk_buff *skb, int header_len)
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 */
* - octet 1: option type
* - octet 2: option data len (only if type != 255 and 0)
* - octet 3: option data */
while (*p != 255 && !ret) {
/* p now points to the first octect: option type */
/* p now points to the first octet: option type */
if (*p == 53) {
/* type 53 is the message type option.
* Jump the len octect and go to the data octect */
* Jump the len octet and go to the data octet */
if (pkt_len < 2)
goto out;
p += 2;
......
......@@ -249,7 +249,7 @@ static void hardif_activate_interface(struct hard_iface *hard_iface)
/**
* the first active interface becomes our primary interface or
* the next active interface after the old primay interface was removed
* the next active interface after the old primary interface was removed
*/
primary_if = primary_if_get_selected(bat_priv);
if (!primary_if)
......@@ -573,7 +573,7 @@ static int hard_if_event(struct notifier_block *this,
return NOTIFY_DONE;
}
/* receive a packet with the batman ethertype coming on a hard
/* incoming packets with the batman ethertype received on any active hard
* interface */
static int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *ptype,
......@@ -681,6 +681,36 @@ static int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
return NET_RX_DROP;
}
/* This function returns true if the interface represented by ifindex is a
* 802.11 wireless device */
bool is_wifi_iface(int ifindex)
{
struct net_device *net_device = NULL;
bool ret = false;
if (ifindex == NULL_IFINDEX)
goto out;
net_device = dev_get_by_index(&init_net, ifindex);
if (!net_device)
goto out;
#ifdef CONFIG_WIRELESS_EXT
/* pre-cfg80211 drivers have to implement WEXT, so it is possible to
* check for wireless_handlers != NULL */
if (net_device->wireless_handlers)
ret = true;
else
#endif
/* cfg80211 drivers have to set ieee80211_ptr */
if (net_device->ieee80211_ptr)
ret = true;
out:
if (net_device)
dev_put(net_device);
return ret;
}
struct notifier_block hard_if_notifier = {
.notifier_call = hard_if_event,
};
......@@ -42,6 +42,7 @@ void hardif_remove_interfaces(void);
int hardif_min_mtu(struct net_device *soft_iface);
void update_min_mtu(struct net_device *soft_iface);
void hardif_free_rcu(struct rcu_head *rcu);
bool is_wifi_iface(int ifindex);
static inline void hardif_free_ref(struct hard_iface *hard_iface)
{
......
......@@ -76,19 +76,30 @@ static inline void hash_delete(struct hashtable_t *hash,
hash_destroy(hash);
}
/* adds data to the hashtable. returns 0 on success, -1 on error */
/**
* hash_add - adds data to the hashtable
* @hash: storage hash table
* @compare: callback to determine if 2 hash elements are identical
* @choose: callback calculating the hash index
* @data: data passed to the aforementioned callbacks as argument
* @data_node: to be added element
*
* Returns 0 on success, 1 if the element already is in the hash
* and -1 on error.
*/
static inline int hash_add(struct hashtable_t *hash,
hashdata_compare_cb compare,
hashdata_choose_cb choose,
const void *data, struct hlist_node *data_node)
{
int index;
int index, ret = -1;
struct hlist_head *head;
struct hlist_node *node;
spinlock_t *list_lock; /* spinlock to protect write access */
if (!hash)
goto err;
goto out;
index = choose(data, hash->size);
head = &hash->table[index];
......@@ -99,6 +110,7 @@ static inline int hash_add(struct hashtable_t *hash,
if (!compare(node, data))
continue;
ret = 1;
goto err_unlock;
}
rcu_read_unlock();
......@@ -108,12 +120,13 @@ static inline int hash_add(struct hashtable_t *hash,
hlist_add_head_rcu(data_node, head);
spin_unlock_bh(list_lock);
return 0;
ret = 0;
goto out;
err_unlock:
rcu_read_unlock();
err:
return -1;
out:
return ret;
}
/* removes data from hash, if found. returns pointer do data on success, so you
......
......@@ -107,7 +107,7 @@ int mesh_init(struct net_device *soft_iface)
if (tt_init(bat_priv) < 1)
goto err;
tt_local_add(soft_iface, soft_iface->dev_addr);
tt_local_add(soft_iface, soft_iface->dev_addr, NULL_IFINDEX);
if (vis_init(bat_priv) < 1)
goto err;
......
......@@ -44,7 +44,7 @@
#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
/* sliding packet range of received originator messages in sequence 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 */
......@@ -62,6 +62,8 @@
#define NO_FLAGS 0
#define NULL_IFINDEX 0 /* dummy ifindex used to avoid iface checks */
#define NUM_WORDS (TQ_LOCAL_WINDOW_SIZE / WORD_BIT_SIZE)
#define LOG_BUF_LEN 8192 /* has to be a power of 2 */
......@@ -133,7 +135,7 @@ enum dbg_level {
#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/etherdevice.h> /* ethernet address classification */
#include <linux/if_ether.h> /* ethernet header */
#include <linux/poll.h> /* poll_table */
#include <linux/kthread.h> /* kernel threads */
......
......@@ -252,7 +252,7 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, const uint8_t *addr)
hash_added = hash_add(bat_priv->orig_hash, compare_orig,
choose_orig, orig_node, &orig_node->hash_entry);
if (hash_added < 0)
if (hash_added != 0)
goto free_bcast_own_sum;
return orig_node;
......
......@@ -84,6 +84,7 @@ enum tt_query_flags {
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
......
......@@ -64,66 +64,6 @@ void slide_own_bcast_window(struct hard_iface *hard_iface)
}
}
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)
{
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);
/* The ttvn alone is not enough to guarantee consistency
* because a single value could repesent 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;
}
}
}
static void update_route(struct bat_priv *bat_priv,
struct orig_node *orig_node,
struct neigh_node *neigh_node)
......@@ -228,7 +168,7 @@ static int is_bidirectional_neigh(struct orig_node *orig_node,
if (!neigh_node)
goto out;
/* if orig_node is direct neighbour update neigh_node last_valid */
/* if orig_node is direct neighbor update neigh_node last_valid */
if (orig_node == orig_neigh_node)
neigh_node->last_valid = jiffies;
......@@ -473,7 +413,7 @@ static void update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
if (router && (router->tq_avg > neigh_node->tq_avg))
goto update_tt;
/* if the TQ is the same and the link not more symetric we
/* if the TQ is the same and the link not more symmetric we
* won't consider it either */
if (router && (neigh_node->tq_avg == router->tq_avg)) {
orig_node_tmp = router->orig_node;
......@@ -500,10 +440,9 @@ static void update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
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,
tt_update_orig(bat_priv, orig_node, tt_buff,
batman_packet->tt_num_changes,
batman_packet->ttvn,
batman_packet->tt_crc);
batman_packet->ttvn, batman_packet->tt_crc);
if (orig_node->gw_flags != batman_packet->gw_flags)
gw_node_update(bat_priv, orig_node, batman_packet->gw_flags);
......@@ -1243,7 +1182,7 @@ int recv_tt_query(struct sk_buff *skb, struct hard_iface *recv_if)
}
break;
case TT_RESPONSE:
/* packet needs to be linearised to access the TT changes */
/* packet needs to be linearized to access the TT changes */
if (skb_linearize(skb) < 0)
goto out;
......@@ -1300,7 +1239,7 @@ int recv_roam_adv(struct sk_buff *skb, struct hard_iface *recv_if)
roam_adv_packet->client);
tt_global_add(bat_priv, orig_node, roam_adv_packet->client,
atomic_read(&orig_node->last_ttvn) + 1, true);
atomic_read(&orig_node->last_ttvn) + 1, true, false);
/* Roaming phase starts: I have new information but the ttvn has not
* been incremented yet. This flag will make me check all the incoming
......@@ -1536,7 +1475,7 @@ static int check_unicast_ttvn(struct bat_priv *bat_priv,
ethhdr = (struct ethhdr *)(skb->data +
sizeof(struct unicast_packet));
orig_node = transtable_search(bat_priv, ethhdr->h_dest);
orig_node = transtable_search(bat_priv, NULL, ethhdr->h_dest);
if (!orig_node) {
if (!is_my_client(bat_priv, ethhdr->h_dest))
......
......@@ -135,7 +135,7 @@ 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, hvn %d) on interface %s [%pM]\n",
" IDF %s, ttvn %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,
......@@ -313,7 +313,7 @@ void schedule_own_packet(struct hard_iface *hard_iface)
prepare_packet_buffer(bat_priv, hard_iface);
}
/* if the changes have been sent enough times */
/* if the changes have been sent often enough */
if (!atomic_dec_not_zero(&bat_priv->tt_ogm_append_cnt))
reset_packet_buffer(bat_priv, hard_iface);
}
......@@ -454,7 +454,7 @@ static void _add_bcast_packet_to_list(struct bat_priv *bat_priv,
}
/* add a broadcast packet to the queue and setup timers. broadcast packets
* are sent multiple times to increase probability for beeing received.
* are sent multiple times to increase probability for being received.
*
* This function returns NETDEV_TX_OK on success and NETDEV_TX_BUSY on
* errors.
......@@ -612,7 +612,7 @@ void purge_outstanding_packets(struct bat_priv *bat_priv,
&bat_priv->forw_bcast_list, list) {
/**
* if purge_outstanding_packets() was called with an argmument
* if purge_outstanding_packets() was called with an argument
* we delete only packets belonging to the given interface
*/
if ((hard_iface) &&
......@@ -641,7 +641,7 @@ void purge_outstanding_packets(struct bat_priv *bat_priv,
&bat_priv->forw_bat_list, list) {
/**
* if purge_outstanding_packets() was called with an argmument
* if purge_outstanding_packets() was called with an argument
* we delete only packets belonging to the given interface
*/
if ((hard_iface) &&
......
......@@ -532,11 +532,11 @@ static int interface_set_mac_addr(struct net_device *dev, void *p)
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
/* only modify transtable if it has been initialised before */
/* only modify transtable if it has been initialized before */
if (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE) {
tt_local_remove(bat_priv, dev->dev_addr,
"mac address changed", false);
tt_local_add(dev, addr->sa_data);
tt_local_add(dev, addr->sa_data, NULL_IFINDEX);
}
memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
......@@ -595,9 +595,10 @@ static int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
goto dropped;
/* Register the client MAC in the transtable */
tt_local_add(soft_iface, ethhdr->h_source);
tt_local_add(soft_iface, ethhdr->h_source, skb->skb_iif);
orig_node = transtable_search(bat_priv, ethhdr->h_dest);
orig_node = transtable_search(bat_priv, ethhdr->h_source,
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);
......@@ -739,6 +740,9 @@ void interface_rx(struct net_device *soft_iface,
soft_iface->last_rx = jiffies;
if (is_ap_isolated(bat_priv, ethhdr->h_source, ethhdr->h_dest))
goto dropped;
netif_rx(skb);
goto out;
......@@ -812,6 +816,7 @@ struct net_device *softif_create(const char *name)
atomic_set(&bat_priv->aggregated_ogms, 1);
atomic_set(&bat_priv->bonding, 0);
atomic_set(&bat_priv->ap_isolation, 0);
atomic_set(&bat_priv->vis_mode, VIS_TYPE_CLIENT_UPDATE);
atomic_set(&bat_priv->gw_mode, GW_MODE_OFF);
atomic_set(&bat_priv->gw_sel_class, 20);
......
......@@ -183,7 +183,8 @@ static int tt_local_init(struct bat_priv *bat_priv)
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;
......@@ -207,6 +208,8 @@ 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;
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 */
......@@ -329,7 +332,7 @@ int tt_local_seq_print_text(struct seq_file *seq, void *offset)
rcu_read_lock();
__hlist_for_each_rcu(node, head)
buf_size += 21;
buf_size += 29;
rcu_read_unlock();
}
......@@ -348,8 +351,19 @@ int tt_local_seq_print_text(struct seq_file *seq, void *offset)
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();
}
......@@ -369,8 +383,8 @@ static void tt_local_set_pending(struct bat_priv *bat_priv,
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;
}
......@@ -495,7 +509,8 @@ static void tt_changes_list_free(struct bat_priv *bat_priv)
/* 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;
......@@ -537,6 +552,9 @@ int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
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);
......@@ -582,8 +600,8 @@ int tt_global_seq_print_text(struct seq_file *seq, void *offset)
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
......@@ -593,7 +611,7 @@ int tt_global_seq_print_text(struct seq_file *seq, void *offset)
rcu_read_lock();
__hlist_for_each_rcu(node, head)
buf_size += 59;
buf_size += 67;
rcu_read_unlock();
}
......@@ -612,14 +630,20 @@ int tt_global_seq_print_text(struct seq_file *seq, void *offset)
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();
}
......@@ -774,30 +798,56 @@ static void tt_global_table_free(struct bat_priv *bat_priv)
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;
}
......@@ -1029,7 +1079,8 @@ static struct sk_buff *tt_response_fill_table(uint16_t tt_len, uint8_t ttvn,
return skb;
}
int send_tt_request(struct bat_priv *bat_priv, struct orig_node *dst_orig_node,
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;
......@@ -1137,12 +1188,12 @@ static bool send_other_tt_response(struct bat_priv *bat_priv,
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;
......@@ -1363,7 +1414,9 @@ static void _tt_update_changes(struct bat_priv *bat_priv,
(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
......@@ -1403,7 +1456,8 @@ static void tt_fill_gtable(struct bat_priv *bat_priv,
orig_node_free_ref(orig_node);
}
void tt_update_changes(struct bat_priv *bat_priv, struct orig_node *orig_node,
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)
{
......@@ -1720,3 +1774,90 @@ void tt_commit_changes(struct bat_priv *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;
}
}
}
......@@ -26,15 +26,16 @@ 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_add(struct net_device *soft_iface, const uint8_t *addr,
int ifindex);
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,
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_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
const unsigned char *addr, uint8_t ttvn, bool roaming,
bool wifi);
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);
......@@ -42,25 +43,23 @@ 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);
const uint8_t *src, 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);
void tt_commit_changes(struct bat_priv *bat_priv);
bool is_ap_isolated(struct bat_priv *bat_priv, uint8_t *src, uint8_t *dst);
void tt_update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
const unsigned char *tt_buff, uint8_t tt_num_changes,
uint8_t ttvn, uint16_t tt_crc);
#endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */
......@@ -57,7 +57,7 @@ struct hard_iface {
* @batman_seqno_reset: time when the batman seqno window was reset
* @gw_flags: flags related to gateway class
* @flags: for now only VIS_SERVER flag
* @last_real_seqno: last and best known squence number
* @last_real_seqno: last and best known sequence number
* @last_ttl: ttl of last received packet
* @last_bcast_seqno: last broadcast sequence number received by this host
*
......@@ -146,6 +146,7 @@ struct bat_priv {
atomic_t aggregated_ogms; /* boolean */
atomic_t bonding; /* boolean */
atomic_t fragmentation; /* boolean */
atomic_t ap_isolation; /* boolean */
atomic_t vis_mode; /* VIS_TYPE_* */
atomic_t gw_mode; /* GW_MODE_* */
atomic_t gw_sel_class; /* uint */
......@@ -156,7 +157,7 @@ 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 ttvn; /* translation 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.
......
......@@ -299,8 +299,10 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv)
goto find_router;
}
/* check for tt host - increases orig_node refcount */
orig_node = transtable_search(bat_priv, ethhdr->h_dest);
/* check for tt host - increases orig_node refcount.
* returns NULL in case of AP isolation */
orig_node = transtable_search(bat_priv, ethhdr->h_source,
ethhdr->h_dest);
find_router:
/**
......
......@@ -24,7 +24,7 @@
#include "packet.h"
#define FRAG_TIMEOUT 10000 /* purge frag list entrys after time in ms */
#define FRAG_TIMEOUT 10000 /* purge frag list entries after time in ms */
#define FRAG_BUFFER_SIZE 6 /* number of list elements in buffer */
int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
......
......@@ -131,7 +131,7 @@ static void vis_data_insert_interface(const uint8_t *interface,
return;
}
/* its a new address, add it to the list */
/* it's a new address, add it to the list */
entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
if (!entry)
return;
......@@ -465,7 +465,7 @@ static struct vis_info *add_packet(struct bat_priv *bat_priv,
/* try to add it */
hash_added = hash_add(bat_priv->vis_hash, vis_info_cmp, vis_info_choose,
info, &info->hash_entry);
if (hash_added < 0) {
if (hash_added != 0) {
/* did not work (for some reason) */
kref_put(&info->refcount, free_info);
info = NULL;
......@@ -920,7 +920,7 @@ int vis_init(struct bat_priv *bat_priv)
hash_added = hash_add(bat_priv->vis_hash, vis_info_cmp, vis_info_choose,
bat_priv->my_vis_info,
&bat_priv->my_vis_info->hash_entry);
if (hash_added < 0) {
if (hash_added != 0) {
pr_err("Can't add own vis packet into hash\n");
/* not in hash, need to remove it manually. */
kref_put(&bat_priv->my_vis_info->refcount, free_info);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment