Merge branch 'batman-adv/next' of git://git.open-mesh.org/linux-merge
This commit is contained in:
commit
0e43182c0c
@ -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 @@ out:
|
||||
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 @@ err_out:
|
||||
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 @@ update_tt:
|
||||
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);
|
||||
tt_update_orig(bat_priv, orig_node, tt_buff,
|
||||
batman_packet->tt_num_changes,
|
||||
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;
|
||||
}
|
||||
|
||||
struct orig_node *transtable_search(struct bat_priv *bat_priv,
|
||||
const uint8_t *addr)
|
||||
static bool _is_ap_isolated(struct tt_local_entry *tt_local_entry,
|
||||
struct tt_global_entry *tt_global_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 *src, const uint8_t *addr)
|
||||
{
|
||||
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,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;
|
||||
@ -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,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);
|
||||
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user