Commit 8b72ca67 authored by David S. Miller's avatar David S. Miller

Merge tag 'batman-adv-for-davem' of git://git.open-mesh.org/linux-merge

Antonio Quartulli says:

====================
Included changes:
- code beautification
- remove obsolete 'deleted' attribute for bat-gw node
- increase internal version number
- prevent potential access to netdev object after deregistration
- set needed_head/tail_room for batman virtual interface
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 9723e6ab ed292663
...@@ -296,39 +296,13 @@ batadv_iv_ogm_neigh_new(struct batadv_hard_iface *hard_iface, ...@@ -296,39 +296,13 @@ batadv_iv_ogm_neigh_new(struct batadv_hard_iface *hard_iface,
struct batadv_orig_node *orig_node, struct batadv_orig_node *orig_node,
struct batadv_orig_node *orig_neigh) struct batadv_orig_node *orig_neigh)
{ {
struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); struct batadv_neigh_node *neigh_node;
struct batadv_neigh_node *neigh_node, *tmp_neigh_node;
neigh_node = batadv_neigh_node_new(hard_iface, neigh_addr, orig_node); neigh_node = batadv_neigh_node_new(orig_node, hard_iface, neigh_addr);
if (!neigh_node) if (!neigh_node)
goto out; goto out;
if (!atomic_inc_not_zero(&hard_iface->refcount)) {
kfree(neigh_node);
neigh_node = NULL;
goto out;
}
neigh_node->orig_node = orig_neigh; neigh_node->orig_node = orig_neigh;
neigh_node->if_incoming = hard_iface;
spin_lock_bh(&orig_node->neigh_list_lock);
tmp_neigh_node = batadv_neigh_node_get(orig_node, hard_iface,
neigh_addr);
if (!tmp_neigh_node) {
hlist_add_head_rcu(&neigh_node->list, &orig_node->neigh_list);
} else {
kfree(neigh_node);
batadv_hardif_free_ref(hard_iface);
neigh_node = tmp_neigh_node;
}
spin_unlock_bh(&orig_node->neigh_list_lock);
if (!tmp_neigh_node)
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Creating new neighbor %pM for orig_node %pM on interface %s\n",
neigh_addr, orig_node->orig,
hard_iface->net_dev->name);
out: out:
return neigh_node; return neigh_node;
......
...@@ -27,7 +27,6 @@ ...@@ -27,7 +27,6 @@
#include <linux/in.h> #include <linux/in.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/ipv6.h> #include <linux/ipv6.h>
#include <linux/jiffies.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
...@@ -161,9 +160,6 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv) ...@@ -161,9 +160,6 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv)
rcu_read_lock(); rcu_read_lock();
hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.list, list) { hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.list, list) {
if (gw_node->deleted)
continue;
orig_node = gw_node->orig_node; orig_node = gw_node->orig_node;
router = batadv_orig_router_get(orig_node, BATADV_IF_DEFAULT); router = batadv_orig_router_get(orig_node, BATADV_IF_DEFAULT);
if (!router) if (!router)
...@@ -473,9 +469,6 @@ batadv_gw_node_get(struct batadv_priv *bat_priv, ...@@ -473,9 +469,6 @@ batadv_gw_node_get(struct batadv_priv *bat_priv,
if (gw_node_tmp->orig_node != orig_node) if (gw_node_tmp->orig_node != orig_node)
continue; continue;
if (gw_node_tmp->deleted)
continue;
if (!atomic_inc_not_zero(&gw_node_tmp->refcount)) if (!atomic_inc_not_zero(&gw_node_tmp->refcount))
continue; continue;
...@@ -525,9 +518,7 @@ void batadv_gw_node_update(struct batadv_priv *bat_priv, ...@@ -525,9 +518,7 @@ void batadv_gw_node_update(struct batadv_priv *bat_priv,
gw_node->bandwidth_down = ntohl(gateway->bandwidth_down); gw_node->bandwidth_down = ntohl(gateway->bandwidth_down);
gw_node->bandwidth_up = ntohl(gateway->bandwidth_up); gw_node->bandwidth_up = ntohl(gateway->bandwidth_up);
gw_node->deleted = 0;
if (ntohl(gateway->bandwidth_down) == 0) { if (ntohl(gateway->bandwidth_down) == 0) {
gw_node->deleted = jiffies;
batadv_dbg(BATADV_DBG_BATMAN, bat_priv, batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Gateway %pM removed from gateway list\n", "Gateway %pM removed from gateway list\n",
orig_node->orig); orig_node->orig);
...@@ -535,14 +526,21 @@ void batadv_gw_node_update(struct batadv_priv *bat_priv, ...@@ -535,14 +526,21 @@ void batadv_gw_node_update(struct batadv_priv *bat_priv,
/* Note: We don't need a NULL check here, since curr_gw never /* Note: We don't need a NULL check here, since curr_gw never
* gets dereferenced. * gets dereferenced.
*/ */
spin_lock_bh(&bat_priv->gw.list_lock);
hlist_del_init_rcu(&gw_node->list);
spin_unlock_bh(&bat_priv->gw.list_lock);
batadv_gw_node_free_ref(gw_node);
curr_gw = batadv_gw_get_selected_gw_node(bat_priv); curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
if (gw_node == curr_gw) if (gw_node == curr_gw)
batadv_gw_reselect(bat_priv); batadv_gw_reselect(bat_priv);
if (curr_gw)
batadv_gw_node_free_ref(curr_gw);
} }
out: out:
if (curr_gw)
batadv_gw_node_free_ref(curr_gw);
if (gw_node) if (gw_node)
batadv_gw_node_free_ref(gw_node); batadv_gw_node_free_ref(gw_node);
} }
...@@ -558,39 +556,18 @@ void batadv_gw_node_delete(struct batadv_priv *bat_priv, ...@@ -558,39 +556,18 @@ void batadv_gw_node_delete(struct batadv_priv *bat_priv,
batadv_gw_node_update(bat_priv, orig_node, &gateway); batadv_gw_node_update(bat_priv, orig_node, &gateway);
} }
void batadv_gw_node_purge(struct batadv_priv *bat_priv) void batadv_gw_node_free(struct batadv_priv *bat_priv)
{ {
struct batadv_gw_node *gw_node, *curr_gw; struct batadv_gw_node *gw_node;
struct hlist_node *node_tmp; struct hlist_node *node_tmp;
unsigned long timeout = msecs_to_jiffies(2 * BATADV_PURGE_TIMEOUT);
int do_reselect = 0;
curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
spin_lock_bh(&bat_priv->gw.list_lock); spin_lock_bh(&bat_priv->gw.list_lock);
hlist_for_each_entry_safe(gw_node, node_tmp, hlist_for_each_entry_safe(gw_node, node_tmp,
&bat_priv->gw.list, list) { &bat_priv->gw.list, list) {
if (((!gw_node->deleted) || hlist_del_init_rcu(&gw_node->list);
(time_before(jiffies, gw_node->deleted + timeout))) &&
atomic_read(&bat_priv->mesh_state) == BATADV_MESH_ACTIVE)
continue;
if (curr_gw == gw_node)
do_reselect = 1;
hlist_del_rcu(&gw_node->list);
batadv_gw_node_free_ref(gw_node); batadv_gw_node_free_ref(gw_node);
} }
spin_unlock_bh(&bat_priv->gw.list_lock); spin_unlock_bh(&bat_priv->gw.list_lock);
/* gw_reselect() needs to acquire the gw_list_lock */
if (do_reselect)
batadv_gw_reselect(bat_priv);
if (curr_gw)
batadv_gw_node_free_ref(curr_gw);
} }
/* fails if orig_node has no router */ /* fails if orig_node has no router */
...@@ -654,9 +631,6 @@ int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset) ...@@ -654,9 +631,6 @@ int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset)
rcu_read_lock(); rcu_read_lock();
hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.list, list) { hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.list, list) {
if (gw_node->deleted)
continue;
/* fails if orig_node has no router */ /* fails if orig_node has no router */
if (batadv_write_buffer_text(bat_priv, seq, gw_node) < 0) if (batadv_write_buffer_text(bat_priv, seq, gw_node) < 0)
continue; continue;
......
...@@ -38,7 +38,7 @@ void batadv_gw_node_update(struct batadv_priv *bat_priv, ...@@ -38,7 +38,7 @@ void batadv_gw_node_update(struct batadv_priv *bat_priv,
struct batadv_tvlv_gateway_data *gateway); struct batadv_tvlv_gateway_data *gateway);
void batadv_gw_node_delete(struct batadv_priv *bat_priv, void batadv_gw_node_delete(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node); struct batadv_orig_node *orig_node);
void batadv_gw_node_purge(struct batadv_priv *bat_priv); void batadv_gw_node_free(struct batadv_priv *bat_priv);
int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset); int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset);
bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, struct sk_buff *skb); bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, struct sk_buff *skb);
enum batadv_dhcp_recipient enum batadv_dhcp_recipient
......
...@@ -252,6 +252,44 @@ static void batadv_check_known_mac_addr(const struct net_device *net_dev) ...@@ -252,6 +252,44 @@ static void batadv_check_known_mac_addr(const struct net_device *net_dev)
rcu_read_unlock(); rcu_read_unlock();
} }
/**
* batadv_hardif_recalc_extra_skbroom() - Recalculate skbuff extra head/tailroom
* @soft_iface: netdev struct of the mesh interface
*/
static void batadv_hardif_recalc_extra_skbroom(struct net_device *soft_iface)
{
const struct batadv_hard_iface *hard_iface;
unsigned short lower_header_len = ETH_HLEN;
unsigned short lower_headroom = 0;
unsigned short lower_tailroom = 0;
unsigned short needed_headroom;
rcu_read_lock();
list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
if (hard_iface->if_status == BATADV_IF_NOT_IN_USE)
continue;
if (hard_iface->soft_iface != soft_iface)
continue;
lower_header_len = max_t(unsigned short, lower_header_len,
hard_iface->net_dev->hard_header_len);
lower_headroom = max_t(unsigned short, lower_headroom,
hard_iface->net_dev->needed_headroom);
lower_tailroom = max_t(unsigned short, lower_tailroom,
hard_iface->net_dev->needed_tailroom);
}
rcu_read_unlock();
needed_headroom = lower_headroom + (lower_header_len - ETH_HLEN);
needed_headroom += batadv_max_header_len();
soft_iface->needed_headroom = needed_headroom;
soft_iface->needed_tailroom = lower_tailroom;
}
int batadv_hardif_min_mtu(struct net_device *soft_iface) int batadv_hardif_min_mtu(struct net_device *soft_iface)
{ {
struct batadv_priv *bat_priv = netdev_priv(soft_iface); struct batadv_priv *bat_priv = netdev_priv(soft_iface);
...@@ -474,6 +512,8 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, ...@@ -474,6 +512,8 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
"Not using interface %s (retrying later): interface not active\n", "Not using interface %s (retrying later): interface not active\n",
hard_iface->net_dev->name); hard_iface->net_dev->name);
batadv_hardif_recalc_extra_skbroom(soft_iface);
/* begin scheduling originator messages on that interface */ /* begin scheduling originator messages on that interface */
batadv_schedule_bat_ogm(hard_iface); batadv_schedule_bat_ogm(hard_iface);
...@@ -528,6 +568,9 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface, ...@@ -528,6 +568,9 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface,
batadv_purge_outstanding_packets(bat_priv, hard_iface); batadv_purge_outstanding_packets(bat_priv, hard_iface);
dev_put(hard_iface->soft_iface); dev_put(hard_iface->soft_iface);
netdev_upper_dev_unlink(hard_iface->net_dev, hard_iface->soft_iface);
batadv_hardif_recalc_extra_skbroom(hard_iface->soft_iface);
/* nobody uses this interface anymore */ /* nobody uses this interface anymore */
if (!bat_priv->num_ifaces) { if (!bat_priv->num_ifaces) {
batadv_gw_check_client_stop(bat_priv); batadv_gw_check_client_stop(bat_priv);
...@@ -536,7 +579,6 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface, ...@@ -536,7 +579,6 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface,
batadv_softif_destroy_sysfs(hard_iface->soft_iface); batadv_softif_destroy_sysfs(hard_iface->soft_iface);
} }
netdev_upper_dev_unlink(hard_iface->net_dev, hard_iface->soft_iface);
hard_iface->soft_iface = NULL; hard_iface->soft_iface = NULL;
batadv_hardif_free_ref(hard_iface); batadv_hardif_free_ref(hard_iface);
......
...@@ -199,7 +199,7 @@ void batadv_mesh_free(struct net_device *soft_iface) ...@@ -199,7 +199,7 @@ void batadv_mesh_free(struct net_device *soft_iface)
batadv_purge_outstanding_packets(bat_priv, NULL); batadv_purge_outstanding_packets(bat_priv, NULL);
batadv_gw_node_purge(bat_priv); batadv_gw_node_free(bat_priv);
batadv_nc_mesh_free(bat_priv); batadv_nc_mesh_free(bat_priv);
batadv_dat_free(bat_priv); batadv_dat_free(bat_priv);
batadv_bla_free(bat_priv); batadv_bla_free(bat_priv);
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
#define BATADV_DRIVER_DEVICE "batman-adv" #define BATADV_DRIVER_DEVICE "batman-adv"
#ifndef BATADV_SOURCE_VERSION #ifndef BATADV_SOURCE_VERSION
#define BATADV_SOURCE_VERSION "2015.1" #define BATADV_SOURCE_VERSION "2015.2"
#endif #endif
/* B.A.T.M.A.N. parameters */ /* B.A.T.M.A.N. parameters */
......
...@@ -442,40 +442,6 @@ batadv_neigh_ifinfo_new(struct batadv_neigh_node *neigh, ...@@ -442,40 +442,6 @@ batadv_neigh_ifinfo_new(struct batadv_neigh_node *neigh,
return neigh_ifinfo; return neigh_ifinfo;
} }
/**
* batadv_neigh_node_new - create and init a new neigh_node object
* @hard_iface: the interface where the neighbour is connected to
* @neigh_addr: the mac address of the neighbour interface
* @orig_node: originator object representing the neighbour
*
* Allocates a new neigh_node object and initialises all the generic fields.
* Returns the new object or NULL on failure.
*/
struct batadv_neigh_node *
batadv_neigh_node_new(struct batadv_hard_iface *hard_iface,
const u8 *neigh_addr, struct batadv_orig_node *orig_node)
{
struct batadv_neigh_node *neigh_node;
neigh_node = kzalloc(sizeof(*neigh_node), GFP_ATOMIC);
if (!neigh_node)
goto out;
INIT_HLIST_NODE(&neigh_node->list);
INIT_HLIST_HEAD(&neigh_node->ifinfo_list);
spin_lock_init(&neigh_node->ifinfo_lock);
ether_addr_copy(neigh_node->addr, neigh_addr);
neigh_node->if_incoming = hard_iface;
neigh_node->orig_node = orig_node;
/* extra reference for return */
atomic_set(&neigh_node->refcount, 2);
out:
return neigh_node;
}
/** /**
* batadv_neigh_node_get - retrieve a neighbour from the list * batadv_neigh_node_get - retrieve a neighbour from the list
* @orig_node: originator which the neighbour belongs to * @orig_node: originator which the neighbour belongs to
...@@ -486,7 +452,7 @@ batadv_neigh_node_new(struct batadv_hard_iface *hard_iface, ...@@ -486,7 +452,7 @@ batadv_neigh_node_new(struct batadv_hard_iface *hard_iface,
* which is connected through the provided hard interface. * which is connected through the provided hard interface.
* Returns NULL if the neighbour is not found. * Returns NULL if the neighbour is not found.
*/ */
struct batadv_neigh_node * static struct batadv_neigh_node *
batadv_neigh_node_get(const struct batadv_orig_node *orig_node, batadv_neigh_node_get(const struct batadv_orig_node *orig_node,
const struct batadv_hard_iface *hard_iface, const struct batadv_hard_iface *hard_iface,
const u8 *addr) const u8 *addr)
...@@ -512,6 +478,59 @@ batadv_neigh_node_get(const struct batadv_orig_node *orig_node, ...@@ -512,6 +478,59 @@ batadv_neigh_node_get(const struct batadv_orig_node *orig_node,
return res; return res;
} }
/**
* batadv_neigh_node_new - create and init a new neigh_node object
* @orig_node: originator object representing the neighbour
* @hard_iface: the interface where the neighbour is connected to
* @neigh_addr: the mac address of the neighbour interface
*
* Allocates a new neigh_node object and initialises all the generic fields.
* Returns the new object or NULL on failure.
*/
struct batadv_neigh_node *
batadv_neigh_node_new(struct batadv_orig_node *orig_node,
struct batadv_hard_iface *hard_iface,
const u8 *neigh_addr)
{
struct batadv_neigh_node *neigh_node;
neigh_node = batadv_neigh_node_get(orig_node, hard_iface, neigh_addr);
if (neigh_node)
goto out;
neigh_node = kzalloc(sizeof(*neigh_node), GFP_ATOMIC);
if (!neigh_node)
goto out;
if (!atomic_inc_not_zero(&hard_iface->refcount)) {
kfree(neigh_node);
neigh_node = NULL;
goto out;
}
INIT_HLIST_NODE(&neigh_node->list);
INIT_HLIST_HEAD(&neigh_node->ifinfo_list);
spin_lock_init(&neigh_node->ifinfo_lock);
ether_addr_copy(neigh_node->addr, neigh_addr);
neigh_node->if_incoming = hard_iface;
neigh_node->orig_node = orig_node;
/* extra reference for return */
atomic_set(&neigh_node->refcount, 2);
spin_lock_bh(&orig_node->neigh_list_lock);
hlist_add_head_rcu(&neigh_node->list, &orig_node->neigh_list);
spin_unlock_bh(&orig_node->neigh_list_lock);
batadv_dbg(BATADV_DBG_BATMAN, orig_node->bat_priv,
"Creating new neighbor %pM for orig_node %pM on interface %s\n",
neigh_addr, orig_node->orig, hard_iface->net_dev->name);
out:
return neigh_node;
}
/** /**
* batadv_orig_ifinfo_free_rcu - free the orig_ifinfo object * batadv_orig_ifinfo_free_rcu - free the orig_ifinfo object
* @rcu: rcu pointer of the orig_ifinfo object * @rcu: rcu pointer of the orig_ifinfo object
...@@ -1010,7 +1029,6 @@ static void _batadv_purge_orig(struct batadv_priv *bat_priv) ...@@ -1010,7 +1029,6 @@ static void _batadv_purge_orig(struct batadv_priv *bat_priv)
spin_unlock_bh(list_lock); spin_unlock_bh(list_lock);
} }
batadv_gw_node_purge(bat_priv);
batadv_gw_election(bat_priv); batadv_gw_election(bat_priv);
} }
......
...@@ -42,12 +42,9 @@ void batadv_orig_node_free_ref_now(struct batadv_orig_node *orig_node); ...@@ -42,12 +42,9 @@ void batadv_orig_node_free_ref_now(struct batadv_orig_node *orig_node);
struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv, struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv,
const u8 *addr); const u8 *addr);
struct batadv_neigh_node * struct batadv_neigh_node *
batadv_neigh_node_get(const struct batadv_orig_node *orig_node, batadv_neigh_node_new(struct batadv_orig_node *orig_node,
const struct batadv_hard_iface *hard_iface, struct batadv_hard_iface *hard_iface,
const u8 *addr); const u8 *neigh_addr);
struct batadv_neigh_node *
batadv_neigh_node_new(struct batadv_hard_iface *hard_iface,
const u8 *neigh_addr, struct batadv_orig_node *orig_node);
void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node); void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node);
struct batadv_neigh_node * struct batadv_neigh_node *
batadv_orig_router_get(struct batadv_orig_node *orig_node, batadv_orig_router_get(struct batadv_orig_node *orig_node,
......
...@@ -947,8 +947,6 @@ static void batadv_softif_init_early(struct net_device *dev) ...@@ -947,8 +947,6 @@ static void batadv_softif_init_early(struct net_device *dev)
* have not been initialized yet * have not been initialized yet
*/ */
dev->mtu = ETH_DATA_LEN; dev->mtu = ETH_DATA_LEN;
/* reserve more space in the skbuff for our header */
dev->hard_header_len = batadv_max_header_len();
/* generate random address */ /* generate random address */
eth_hw_addr_random(dev); eth_hw_addr_random(dev);
......
...@@ -328,7 +328,6 @@ enum batadv_orig_capabilities { ...@@ -328,7 +328,6 @@ enum batadv_orig_capabilities {
* @orig_node: pointer to corresponding orig node * @orig_node: pointer to corresponding orig node
* @bandwidth_down: advertised uplink download bandwidth * @bandwidth_down: advertised uplink download bandwidth
* @bandwidth_up: advertised uplink upload bandwidth * @bandwidth_up: advertised uplink upload bandwidth
* @deleted: this struct is scheduled for deletion
* @refcount: number of contexts the object is used * @refcount: number of contexts the object is used
* @rcu: struct used for freeing in an RCU-safe manner * @rcu: struct used for freeing in an RCU-safe manner
*/ */
...@@ -337,7 +336,6 @@ struct batadv_gw_node { ...@@ -337,7 +336,6 @@ struct batadv_gw_node {
struct batadv_orig_node *orig_node; struct batadv_orig_node *orig_node;
u32 bandwidth_down; u32 bandwidth_down;
u32 bandwidth_up; u32 bandwidth_up;
unsigned long deleted;
atomic_t refcount; atomic_t refcount;
struct rcu_head rcu; struct rcu_head rcu;
}; };
......
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